mvp/injection: Applies MVP and DI patterns to SettingsFragment
- Introduce the SettingsService interface. Its implementation is
the native Android SharePreferences mecanism. Dependency inversion allows
to respect the best practices in terms of separation of concerns.
- LocalService has been adapted to fit the new architecture patterns
but it will be refactored more deeply in a next patch.
Change-Id: Iff9cdc640f2dd6ae2467236564e9d35c3a4d2ca9
Tuleap: #1304
diff --git a/ring-android/app/src/main/java/cx/ring/application/RingApplication.java b/ring-android/app/src/main/java/cx/ring/application/RingApplication.java
index 1e02a83..7430c1b 100644
--- a/ring-android/app/src/main/java/cx/ring/application/RingApplication.java
+++ b/ring-android/app/src/main/java/cx/ring/application/RingApplication.java
@@ -21,6 +21,9 @@
import android.app.Application;
+import java.util.HashMap;
+import java.util.Map;
+
import cx.ring.dependencyinjection.DaggerRingInjectionComponent;
import cx.ring.dependencyinjection.PresenterInjectionModule;
import cx.ring.dependencyinjection.RingInjectionComponent;
@@ -31,10 +34,14 @@
private RingInjectionComponent mRingInjectionComponent;
+ private Map<String, Boolean> mPermissionsBeingAsked;
+
@Override
public void onCreate() {
super.onCreate();
+ mPermissionsBeingAsked = new HashMap<>();
+
// building injection dependency tree
mRingInjectionComponent = DaggerRingInjectionComponent.builder()
.ringInjectionModule(new RingInjectionModule(this))
@@ -49,4 +56,21 @@
public RingInjectionComponent getRingInjectionComponent() {
return mRingInjectionComponent;
}
+
+ public boolean canAskForPermission (String permission) {
+
+ Boolean isBeingAsked = mPermissionsBeingAsked.get(permission);
+
+ if (isBeingAsked!=null && isBeingAsked) {
+ return false;
+ }
+
+ mPermissionsBeingAsked.put(permission, true);
+
+ return true;
+ }
+
+ public void permissionHasBeenAsked (String permission) {
+ mPermissionsBeingAsked.remove(permission);
+ }
}
diff --git a/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java b/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
index f54bfe4..fb48900 100644
--- a/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
@@ -57,21 +57,23 @@
import android.widget.TextView;
import java.io.File;
+import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import cx.ring.R;
import cx.ring.about.AboutFragment;
+import cx.ring.application.RingApplication;
import cx.ring.fragments.AccountsManagementFragment;
import cx.ring.fragments.ContactListFragment;
-import cx.ring.fragments.SettingsFragment;
import cx.ring.fragments.SmartListFragment;
import cx.ring.model.Account;
import cx.ring.model.CallContact;
import cx.ring.model.ConfigKey;
import cx.ring.service.IDRingService;
import cx.ring.service.LocalService;
+import cx.ring.settings.SettingsFragment;
import cx.ring.share.ShareFragment;
import cx.ring.utils.FileUtils;
import cx.ring.views.MenuHeaderView;
@@ -194,8 +196,16 @@
// Bind to LocalService
String[] toRequest = LocalService.checkRequiredPermissions(this);
- if (toRequest.length > 0) {
- ActivityCompat.requestPermissions(this, toRequest, LocalService.PERMISSIONS_REQUEST);
+ ArrayList<String> permissionsWeCanAsk = new ArrayList<>();
+
+ for (String permission: toRequest) {
+ if (((RingApplication)getApplication()).canAskForPermission(permission)) {
+ permissionsWeCanAsk.add(permission);
+ }
+ }
+
+ if (!permissionsWeCanAsk.isEmpty()) {
+ ActivityCompat.requestPermissions(this, permissionsWeCanAsk.toArray(new String[permissionsWeCanAsk.size()]), LocalService.PERMISSIONS_REQUEST);
} else if (!mBound) {
Log.d(TAG, "onCreate: Binding service...");
Intent intent = new Intent(this, LocalService.class);
@@ -307,7 +317,9 @@
}
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
for (int i = 0, n = permissions.length; i < n; i++) {
- switch (permissions[i]) {
+ String permission = permissions[i];
+ ((RingApplication)getApplication()).permissionHasBeenAsked(permission);
+ switch (permission) {
case Manifest.permission.RECORD_AUDIO:
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
Log.e(TAG, "Missing required permission RECORD_AUDIO");
diff --git a/ring-android/app/src/main/java/cx/ring/dependencyinjection/PresenterInjectionModule.java b/ring-android/app/src/main/java/cx/ring/dependencyinjection/PresenterInjectionModule.java
index f5975a1..e9509ac 100755
--- a/ring-android/app/src/main/java/cx/ring/dependencyinjection/PresenterInjectionModule.java
+++ b/ring-android/app/src/main/java/cx/ring/dependencyinjection/PresenterInjectionModule.java
@@ -23,6 +23,7 @@
import cx.ring.about.AboutPresenter;
import cx.ring.application.RingApplication;
+import cx.ring.settings.SettingsPresenter;
import cx.ring.share.SharePresenter;
import dagger.Module;
import dagger.Provides;
@@ -53,4 +54,13 @@
presenter.afterInjection();
return presenter;
}
+
+ @Provides
+ @Singleton
+ SettingsPresenter provideSettingsPresenter() {
+ SettingsPresenter presenter = new SettingsPresenter();
+ mRingApplication.getRingInjectionComponent().inject(presenter);
+ presenter.afterInjection();
+ return presenter;
+ }
}
diff --git a/ring-android/app/src/main/java/cx/ring/dependencyinjection/RingInjectionComponent.java b/ring-android/app/src/main/java/cx/ring/dependencyinjection/RingInjectionComponent.java
index c7fa5cc..4a2c33c 100755
--- a/ring-android/app/src/main/java/cx/ring/dependencyinjection/RingInjectionComponent.java
+++ b/ring-android/app/src/main/java/cx/ring/dependencyinjection/RingInjectionComponent.java
@@ -24,6 +24,12 @@
import cx.ring.about.AboutFragment;
import cx.ring.about.AboutPresenter;
import cx.ring.application.RingApplication;
+import cx.ring.service.BootReceiver;
+import cx.ring.service.LocalService;
+import cx.ring.services.HistoryServiceImpl;
+import cx.ring.services.SettingsServiceImpl;
+import cx.ring.settings.SettingsFragment;
+import cx.ring.settings.SettingsPresenter;
import cx.ring.share.ShareFragment;
import cx.ring.share.SharePresenter;
import cx.ring.views.MenuHeaderView;
@@ -40,7 +46,19 @@
void inject(ShareFragment fragment);
+ void inject(SettingsFragment fragment);
+
+ void inject(LocalService service);
+
+ void inject(SettingsServiceImpl service);
+
+ void inject(HistoryServiceImpl service);
+
+ void inject(BootReceiver receiver);
+
void inject(AboutPresenter presenter);
void inject(SharePresenter presenter);
+
+ void inject(SettingsPresenter presenter);
}
diff --git a/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.java b/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.java
index ec7fd17..e11382f 100755
--- a/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.java
+++ b/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.java
@@ -22,6 +22,10 @@
import javax.inject.Singleton;
import cx.ring.application.RingApplication;
+import cx.ring.services.HistoryService;
+import cx.ring.services.HistoryServiceImpl;
+import cx.ring.services.SettingsService;
+import cx.ring.services.SettingsServiceImpl;
import cx.ring.services.StateService;
import dagger.Module;
import dagger.Provides;
@@ -40,4 +44,21 @@
StateService provideStateService() {
return new StateService();
}
+
+ @Provides
+ @Singleton
+ SettingsService provideSettingsService() {
+ SettingsServiceImpl settingsService = new SettingsServiceImpl();
+ mRingApplication.getRingInjectionComponent().inject(settingsService);
+ return settingsService;
+ }
+
+ @Provides
+ @Singleton
+ HistoryService provideHistoryService() {
+ HistoryServiceImpl historyService = new HistoryServiceImpl();
+ mRingApplication.getRingInjectionComponent().inject(historyService);
+ historyService.initHelper();
+ return historyService;
+ }
}
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/SettingsFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/SettingsFragment.java
deleted file mode 100644
index 2335454..0000000
--- a/ring-android/app/src/main/java/cx/ring/fragments/SettingsFragment.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Copyright (C) 2004-2016 Savoir-faire Linux Inc.
- *
- * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
- * Romain Bertozzi <romain.bertozzi@savoirfairelinux.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package cx.ring.fragments;
-
-import android.Manifest;
-import android.app.Activity;
-import android.content.DialogInterface;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.design.widget.Snackbar;
-import android.support.v14.preference.PreferenceFragment;
-import android.support.v14.preference.SwitchPreference;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.preference.Preference;
-import android.text.TextUtils;
-import android.util.Log;
-import android.widget.Toast;
-
-import cx.ring.R;
-import cx.ring.client.HomeActivity;
-import cx.ring.service.LocalService;
-
-/**
- * TODO: improvements : handle multiples permissions for feature.
- */
-public class SettingsFragment extends PreferenceFragment implements
- SharedPreferences.OnSharedPreferenceChangeListener {
- private static final String TAG = SettingsFragment.class.getSimpleName();
-
- private LocalService.Callbacks mCallbacks = LocalService.DUMMY_CALLBACKS;
-
- private String FEATURE_KEY_PREF_CONTACTS = null;
- private String FEATURE_KEY_PREF_DIALER = null;
-
- @Override
- public void onAttach(Activity activity) {
- Log.d(TAG, "onAttach");
- super.onAttach(activity);
-
- if (!(activity instanceof LocalService.Callbacks)) {
- throw new IllegalStateException("Activity must implement fragment's callbacks.");
- }
-
- mCallbacks = (LocalService.Callbacks) activity;
- }
-
- @Override
- public void onDetach() {
- Log.d(TAG, "onDetach");
- super.onDetach();
- mCallbacks = LocalService.DUMMY_CALLBACKS;
- }
-
- @Override
- public void onCreatePreferences(Bundle bundle, String s) {
- addPreferencesFromResource(R.xml.preferences);
- FEATURE_KEY_PREF_CONTACTS = getString(R.string.pref_systemContacts_key);
- FEATURE_KEY_PREF_DIALER = getString(R.string.pref_systemDialer_key);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
- Activity activity = getActivity();
- if (activity instanceof HomeActivity) {
- ((HomeActivity) activity).setToolbarState(false, R.string.menu_item_settings);
- }
- this.checkAndResolveCorrectSync();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
- }
-
- @Override
- public boolean onPreferenceTreeClick(Preference preference) {
- if (null != preference) {
- if (getString(R.string.pref_clearHistory_key).equals(preference.getKey())) {
- this.clearHistory();
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- String neededPermission = this.neededPermissionForFeature(key);
- this.handlePermissionsForFeaturePreference(sharedPreferences,
- key,
- neededPermission);
- }
-
- /**
- * Check if all the features are in a good state of activation.
- *
- * @see SettingsFragment#checkAndResolveCorrectSyncFeatureAndPermission(String)
- */
- private void checkAndResolveCorrectSync() {
- this.checkAndResolveCorrectSyncFeatureAndPermission(FEATURE_KEY_PREF_CONTACTS);
- this.checkAndResolveCorrectSyncFeatureAndPermission(FEATURE_KEY_PREF_DIALER);
- }
-
- /**
- * Checks if a feature has the correct permission if any. If not, the feature is disable and the
- * layout reestablished to a proper state.
- *
- * @param feature FEATURE_KEY_PREF_CONTACTS or FEATURE_KEY_PREF_DIALER
- */
- private void checkAndResolveCorrectSyncFeatureAndPermission(String feature) {
- if (TextUtils.isEmpty(feature)) {
- return;
- }
- SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
- boolean useFeature = sharedPreferences.getBoolean(feature, false);
- String neededPermission = this.neededPermissionForFeature(feature);
- if (!TextUtils.isEmpty(neededPermission) && useFeature) {
- boolean hasPermission = LocalService.checkPermission(getActivity(), neededPermission);
- if (!hasPermission) {
- this.enableFeature(false, feature);
- }
- }
- }
-
- /**
- * Provides the permission associated to a feature
- *
- * @param feature FEATURE_KEY_PREF_CONTACTS or FEATURE_KEY_PREF_DIALER
- * @return the permission as a String
- */
- private String neededPermissionForFeature(String feature) {
- String neededPermission = null;
- if (FEATURE_KEY_PREF_CONTACTS.equals(feature)) {
- neededPermission = Manifest.permission.READ_CONTACTS;
- } else if (FEATURE_KEY_PREF_DIALER.equals(feature)) {
- neededPermission = Manifest.permission.WRITE_CALL_LOG;
- }
- return neededPermission;
- }
-
- /**
- * Handles the permission managements for the key feature of the fragment
- *
- * @param sharedPreferences Shared Preferences, such as those from onSharedPreferenceChanged
- * @param feature FEATURE_KEY_PREF_CONTACTS or FEATURE_KEY_PREF_DIALER
- * @param neededPermission if any, the permission to manage
- */
- private void handlePermissionsForFeaturePreference(SharedPreferences sharedPreferences,
- String feature,
- String neededPermission) {
- if (null == sharedPreferences ||
- TextUtils.isEmpty(feature) ||
- TextUtils.isEmpty(neededPermission)) {
- Log.d(TAG, "No permission to handle for feature");
- return;
- }
- //~ Checking if the user wants to use the feature
- boolean useFeature = sharedPreferences.getBoolean(feature, true);
- //~ Checking if a permission is required to use the enabled feature
- if (useFeature && !TextUtils.isEmpty(neededPermission)) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- //~ Must ask permission to use the feature
- if (!LocalService.checkPermission(getActivity(),
- neededPermission)) {
- //~ Ask permission to use the contacts of the device
- requestPermissions(new String[]{neededPermission},
- LocalService.PERMISSIONS_REQUEST);
- }
- }
- }
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode,
- @NonNull String permissions[],
- @NonNull int[] grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- for (int i = 0, n = permissions.length; i < n; ++i) {
- boolean granted = (grantResults[i] == PackageManager.PERMISSION_GRANTED);
- switch (permissions[i]) {
- case Manifest.permission.READ_CONTACTS: {
- this.enableFeature(granted, FEATURE_KEY_PREF_CONTACTS);
- Activity activity = getActivity();
- if (activity instanceof HomeActivity) {
- HomeActivity homeActivity = (HomeActivity) getActivity();
- homeActivity.getService().refreshContacts();
- }
- }
- break;
- case Manifest.permission.WRITE_CALL_LOG: {
- this.enableFeature(granted, FEATURE_KEY_PREF_DIALER);
- }
- break;
- }
- }
- }
-
- /**
- * Enables or disables a feature
- *
- * @param enable boolean true if enabled, false otherwise
- * @param feature FEATURE_KEY_PREF_CONTACTS or FEATURE_KEY_PREF_DIALER
- */
- private void enableFeature(boolean enable, String feature) {
- if (TextUtils.isEmpty(feature)) {
- return;
- }
- SharedPreferences prefs = getPreferenceScreen().getSharedPreferences();
- prefs.edit().putBoolean(feature, enable).apply();
- SwitchPreference pref = (SwitchPreference) findPreference(feature);
- pref.setChecked(enable);
- if (!enable) {
- this.presentPermissionExplanationToastForFeature(feature);
- }
- }
-
- /**
- * Presents the right explanation toast for the denied permission of the corresponding feature
- *
- * @param feature FEATURE_KEY_PREF_CONTACTS or FEATURE_KEY_PREF_DIALER
- */
- private void presentPermissionExplanationToastForFeature(String feature) {
- if (!TextUtils.isEmpty(feature)) {
- if (feature.equals(FEATURE_KEY_PREF_CONTACTS)) {
- this.presentReadContactPermissionExplanationToast();
- } else if (feature.equals(FEATURE_KEY_PREF_DIALER)) {
- this.presentWriteCallLogPermissionExplanationToast();
- }
- }
- }
-
- /**
- * Presents a Toast explaining why the Read Contacts permission is required to display the devi-
- * ces contacts in Ring.
- */
- private void presentReadContactPermissionExplanationToast() {
- Activity activity = getActivity();
- if (null != activity) {
- String toastMessage = getString(R.string.permission_dialog_read_contacts_message);
- Toast.makeText(activity, toastMessage, Toast.LENGTH_LONG).show();
- }
- }
-
- /**
- * Presents a Toast explaining why the Write Call Log permission is required to enable the cor-
- * responding feature.
- */
- private void presentWriteCallLogPermissionExplanationToast() {
- Activity activity = getActivity();
- if (null != activity) {
- String toastMessage = getString(R.string.permission_dialog_write_call_log_message);
- Toast.makeText(activity, toastMessage, Toast.LENGTH_LONG).show();
- }
- }
-
- //region History
-
- /**
- * Clears all the conversations history. Ask the user to confirm first as it is a critical
- * action.
- */
- private void clearHistory() {
- final Activity activity = getActivity();
- if (activity == null || getView() == null)
- return;
-
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle(getString(R.string.clear_history_dialog_title))
- .setMessage(getString(R.string.clear_history_dialog_message))
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- mCallbacks.getService().clearHistory();
- Snackbar.make(getView(),
- getString(R.string.clear_history_completed),
- Snackbar.LENGTH_SHORT).show();
- }
- })
- .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- //~ Empty
- }
- });
- AlertDialog dialog = builder.create();
- dialog.show();
- }
-
- //endregion
-}
diff --git a/ring-android/app/src/main/java/cx/ring/history/HistoryTimeModel.java b/ring-android/app/src/main/java/cx/ring/history/HistoryTimeModel.java
index 14a9035..f513432 100644
--- a/ring-android/app/src/main/java/cx/ring/history/HistoryTimeModel.java
+++ b/ring-android/app/src/main/java/cx/ring/history/HistoryTimeModel.java
@@ -37,7 +37,7 @@
String NEVER = "Never"; // 24
}
- private static final String TAG = HistoryManager.class.getSimpleName();
+ private static final String TAG = HistoryTimeModel.class.getSimpleName();
static Calendar removeDays(int ago) {
Calendar cal = Calendar.getInstance(Locale.getDefault());
diff --git a/ring-android/app/src/main/java/cx/ring/loaders/ContactsLoader.java b/ring-android/app/src/main/java/cx/ring/loaders/ContactsLoader.java
index 43c38ee..07a13b6 100644
--- a/ring-android/app/src/main/java/cx/ring/loaders/ContactsLoader.java
+++ b/ring-android/app/src/main/java/cx/ring/loaders/ContactsLoader.java
@@ -25,11 +25,9 @@
import android.content.AsyncTaskLoader;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.OperationCanceledException;
-import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.provider.ContactsContract.CommonDataKinds.Phone;
@@ -40,7 +38,6 @@
import java.util.ArrayList;
-import cx.ring.R;
import cx.ring.model.CallContact;
import cx.ring.model.SipUri;
import cx.ring.service.LocalService;
@@ -79,6 +76,7 @@
private final Uri baseUri;
private final LongSparseArray<CallContact> filterFrom;
private volatile boolean abandon = false;
+ private boolean mCanUseSystemContact = true;
public boolean loadSipContacts = true;
public boolean loadRingContacts = true;
@@ -93,6 +91,10 @@
filterFrom = filter;
}
+ public void setSystemContactPermission (boolean canUseSystemContact) {
+ mCanUseSystemContact = canUseSystemContact;
+ }
+
private boolean checkCancel() {
return checkCancel(null);
}
@@ -116,9 +118,7 @@
public Result loadInBackground()
{
final Result res = new Result();
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
- boolean canUseContacts = sharedPreferences.getBoolean(getContext().getString(R.string.pref_systemContacts_key), true);
- if (!canUseContacts || !LocalService.checkPermission(getContext(), Manifest.permission.READ_CONTACTS))
+ if (!mCanUseSystemContact || !LocalService.checkPermission(getContext(), Manifest.permission.READ_CONTACTS))
return res;
long startTime = System.nanoTime();
diff --git a/ring-android/app/src/main/java/cx/ring/service/BootReceiver.java b/ring-android/app/src/main/java/cx/ring/service/BootReceiver.java
index 0772b8e..ee90e81 100644
--- a/ring-android/app/src/main/java/cx/ring/service/BootReceiver.java
+++ b/ring-android/app/src/main/java/cx/ring/service/BootReceiver.java
@@ -3,28 +3,34 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
import android.util.Log;
-import cx.ring.R;
-import cx.ring.fragments.SettingsFragment;
+import javax.inject.Inject;
+
+import cx.ring.application.RingApplication;
+import cx.ring.services.SettingsService;
public class BootReceiver extends BroadcastReceiver {
private static final String TAG = BootReceiver.class.getSimpleName();
+ @Inject
+ SettingsService mSettingsService;
+
public BootReceiver() {
}
@Override
- public void onReceive(Context c, Intent intent) {
+ public void onReceive(Context context, Intent intent) {
+
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(c);
- boolean startOnBoot = sharedPreferences.getBoolean(c.getString(R.string.pref_startOnBoot_key), true);
- if (startOnBoot) {
+
+ ((RingApplication) context.getApplicationContext()).getRingInjectionComponent().inject(this);
+ boolean isAllowRingOnStartup = mSettingsService.loadSettings().isAllowRingOnStartup();
+
+ if (isAllowRingOnStartup) {
Log.w(TAG, "Starting Ring on boot");
- Intent serviceIntent = new Intent(c, LocalService.class);
- c.startService(serviceIntent);
+ Intent serviceIntent = new Intent(context, LocalService.class);
+ context.startService(serviceIntent);
}
}
}
diff --git a/ring-android/app/src/main/java/cx/ring/service/LocalService.java b/ring-android/app/src/main/java/cx/ring/service/LocalService.java
index 88d211c..cf76d1a 100644
--- a/ring-android/app/src/main/java/cx/ring/service/LocalService.java
+++ b/ring-android/app/src/main/java/cx/ring/service/LocalService.java
@@ -69,17 +69,21 @@
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
+import java.util.Observable;
+import java.util.Observer;
import java.util.Random;
import java.util.TreeMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import javax.inject.Inject;
+
import cx.ring.BuildConfig;
import cx.ring.R;
+import cx.ring.application.RingApplication;
import cx.ring.client.ConversationActivity;
import cx.ring.history.HistoryCall;
import cx.ring.history.HistoryEntry;
-import cx.ring.history.HistoryManager;
import cx.ring.history.HistoryText;
import cx.ring.loaders.AccountsLoader;
import cx.ring.loaders.ContactsLoader;
@@ -90,12 +94,16 @@
import cx.ring.model.ConfigKey;
import cx.ring.model.Conversation;
import cx.ring.model.SecureSipCall;
+import cx.ring.model.Settings;
import cx.ring.model.SipCall;
import cx.ring.model.SipUri;
import cx.ring.model.TextMessage;
+import cx.ring.services.HistoryService;
+import cx.ring.services.HistoryServiceImpl;
+import cx.ring.services.SettingsService;
import cx.ring.utils.MediaManager;
-public class LocalService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener {
+public class LocalService extends Service implements Observer {
static final String TAG = LocalService.class.getSimpleName();
// Emitting events
@@ -117,6 +125,12 @@
public final static String[] REQUIRED_RUNTIME_PERMISSIONS = {Manifest.permission.RECORD_AUDIO};
+ @Inject
+ HistoryService mHistoryService;
+
+ @Inject
+ SettingsService mSettingsService;
+
private IDRingService mService = null;
private boolean dringStarted = false;
@@ -130,8 +144,6 @@
private List<Account> accounts = new ArrayList<>();
- private HistoryManager historyManager;
-
private final LongSparseArray<CallContact> systemContactCache = new LongSparseArray<>();
private ContactsLoader.Result lastContactLoaderResult = new ContactsLoader.Result();
@@ -260,7 +272,9 @@
TextMessage message = new TextMessage(false, txt, to, null, account);
message.setID(id);
message.read();
- historyManager.insertNewTextMessage(message);
+ // todo as soon as the HistoryService interface will propose this method we
+ // wont have to cast it anymore
+ ((HistoryServiceImpl) mHistoryService).insertNewTextMessage(message);
messages.put(id, message);
textMessageSent(message);
} catch (RemoteException e) {
@@ -322,7 +336,9 @@
SipCall call = conf.getParticipants().get(0);
TextMessage message = new TextMessage(false, txt, call.getNumberUri(), conf.getId(), call.getAccount());
message.read();
- historyManager.insertNewTextMessage(message);
+ // todo as soon as the HistoryService interface will propose this method we
+ // wont have to cast it anymore
+ ((HistoryServiceImpl) mHistoryService).insertNewTextMessage(message);
textMessageSent(message);
} catch (RemoteException e) {
Log.e(TAG, "sendTextMessage", e);
@@ -332,7 +348,9 @@
private void readTextMessage(TextMessage message) {
message.read();
HistoryText ht = new HistoryText(message);
- historyManager.updateTextMessage(ht);
+ // todo as soon as the HistoryService interface will propose this method we
+ // wont have to cast it anymore
+ ((HistoryServiceImpl) mHistoryService).updateTextMessage(ht);
}
public void readConversation(Conversation conv) {
@@ -432,7 +450,18 @@
}
};
- historyManager = new HistoryManager(this);
+ // dependency injection
+ ((RingApplication) getApplication()).getRingInjectionComponent().inject(this);
+
+ // todo
+ // temporary listen for history modifications
+ // When MVP/DI injection will be done, only the concerned presenters should listen
+ // for model modifications
+ mHistoryService.addObserver(this);
+ mSettingsService.addObserver(this);
+ Settings settings = mSettingsService.loadSettings();
+ canUseContacts = settings.isAllowSystemContacts();
+ canUseMobile = settings.isAllowMobileData();
startDRingService();
@@ -441,11 +470,6 @@
isWifiConn = ni != null && ni.isConnected();
ni = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
isMobileConn = ni != null && ni.isConnected();
-
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
- canUseContacts = sharedPreferences.getBoolean(getString(R.string.pref_systemContacts_key), true);
- canUseMobile = sharedPreferences.getBoolean(getString(R.string.pref_mobileData_key), false);
- sharedPreferences.registerOnSharedPreferenceChangeListener(this);
}
private void startDRingService() {
@@ -466,7 +490,6 @@
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy");
- PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);
stopListener();
mMemoryCache.evictAll();
mPool.shutdown();
@@ -536,18 +559,6 @@
}
};
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- if (key.equals(getString(R.string.pref_systemContacts_key))) {
- canUseContacts = sharedPreferences.getBoolean(key, true);
- mSystemContactLoader.onContentChanged();
- mSystemContactLoader.startLoading();
- } else if (key.equals(getString(R.string.pref_mobileData_key))) {
- canUseMobile = sharedPreferences.getBoolean(key, true);
- updateConnectivityState();
- }
- }
-
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
@@ -557,6 +568,7 @@
initAccountLoader();
mSystemContactLoader = new ContactsLoader(LocalService.this);
+ mSystemContactLoader.setSystemContactPermission(canUseContacts);
mSystemContactLoader.registerListener(1, onSystemContactsLoaded);
}
@@ -830,7 +842,7 @@
}
public void clearHistory() {
- historyManager.clearDB();
+ mHistoryService.clearHistory();
refreshConversations();
}
@@ -1084,8 +1096,10 @@
protected Map<String, Conversation> doInBackground(Void... params) {
final Map<String, Conversation> ret = new HashMap<>();
try {
- final List<HistoryCall> history = historyManager.getAll();
- final List<HistoryText> historyTexts = historyManager.getAllTextMessages();
+ // todo as soon as the HistoryService interface will propose this method we
+ // wont have to cast it anymore
+ final List<HistoryCall> history = ((HistoryServiceImpl) mHistoryService).getAll();
+ final List<HistoryText> historyTexts = ((HistoryServiceImpl) mHistoryService).getAllTextMessages();
final Map<String, ArrayList<String>> confs = mService.getConferenceList();
for (HistoryCall call : history) {
@@ -1461,7 +1475,10 @@
if (conversation.mVisible) {
txt.read();
}
- historyManager.insertNewTextMessage(txt);
+
+ // todo as soon as the HistoryService interface will propose this method we
+ // wont have to cast it anymore
+ ((HistoryServiceImpl) mHistoryService).insertNewTextMessage(txt);
conversation.addTextMessage(txt);
if (!conversation.mVisible) {
@@ -1654,7 +1671,10 @@
if (newState == SipCall.State.HUNGUP) {
call.setTimestampEnd(System.currentTimeMillis());
}
- historyManager.insertNewEntry(found);
+
+ // todo as soon as the HistoryService interface will propose this method
+ // we wont have to cast it anymore
+ ((HistoryServiceImpl) mHistoryService).insertNewEntry(found);
conversation.addHistoryCall(new HistoryCall(call));
notificationManager.cancel(found.notificationId);
found.removeParticipant(call);
@@ -1737,12 +1757,28 @@
public void refreshContacts() {
Log.d(TAG, "refreshContacts");
+ mSystemContactLoader.setSystemContactPermission(canUseContacts);
mSystemContactLoader.onContentChanged();
mSystemContactLoader.startLoading();
}
public void deleteConversation(Conversation conversation) {
- historyManager.clearHistoryForConversation(conversation);
+ // todo as soon as the HistoryService interface will propose this method we wont have to cast it anymore
+ ((HistoryServiceImpl) mHistoryService).clearHistoryForConversation(conversation);
refreshConversations();
}
+
+ @Override
+ public void update(Observable observable, Object arg) {
+ if (observable instanceof HistoryService) {
+ refreshConversations();
+ }
+
+ if (observable instanceof SettingsService) {
+ canUseContacts = mSettingsService.loadSettings().isAllowSystemContacts();
+ canUseMobile = mSettingsService.loadSettings().isAllowMobileData();
+ refreshContacts();
+ updateConnectivityState();
+ }
+ }
}
diff --git a/ring-android/app/src/main/java/cx/ring/service/OutgoingCallHandler.java b/ring-android/app/src/main/java/cx/ring/service/OutgoingCallHandler.java
index 2692f5c..b10f951 100644
--- a/ring-android/app/src/main/java/cx/ring/service/OutgoingCallHandler.java
+++ b/ring-android/app/src/main/java/cx/ring/service/OutgoingCallHandler.java
@@ -26,11 +26,9 @@
import android.content.SharedPreferences;
import android.net.Uri;
import android.preference.PreferenceManager;
-import android.util.Log;
import cx.ring.R;
import cx.ring.client.CallActivity;
-import cx.ring.fragments.SettingsFragment;
import cx.ring.model.SipUri;
public class OutgoingCallHandler extends BroadcastReceiver
diff --git a/ring-android/app/src/main/java/cx/ring/history/HistoryManager.java b/ring-android/app/src/main/java/cx/ring/services/HistoryServiceImpl.java
similarity index 83%
rename from ring-android/app/src/main/java/cx/ring/history/HistoryManager.java
rename to ring-android/app/src/main/java/cx/ring/services/HistoryServiceImpl.java
index c0d6ffe..d6c8ea0 100644
--- a/ring-android/app/src/main/java/cx/ring/history/HistoryManager.java
+++ b/ring-android/app/src/main/java/cx/ring/services/HistoryServiceImpl.java
@@ -19,7 +19,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-package cx.ring.history;
+package cx.ring.services;
import android.content.ContentValues;
import android.content.Context;
@@ -38,21 +38,27 @@
import java.util.List;
import java.util.Map;
+import javax.inject.Inject;
+
import cx.ring.R;
+import cx.ring.history.DatabaseHelper;
+import cx.ring.history.HistoryCall;
+import cx.ring.history.HistoryEntry;
+import cx.ring.history.HistoryText;
import cx.ring.model.Conference;
import cx.ring.model.Conversation;
import cx.ring.model.SipCall;
import cx.ring.model.TextMessage;
-public class HistoryManager {
- private static final String TAG = HistoryManager.class.getSimpleName();
+public class HistoryServiceImpl extends HistoryService {
+ private static final String TAG = HistoryServiceImpl.class.getSimpleName();
- private Context mContext;
+ @Inject
+ Context mContext;
+
private DatabaseHelper historyDBHelper = null;
- public HistoryManager(Context context) {
- mContext = context;
- getHelper();
+ public HistoryServiceImpl() {
}
public boolean insertNewEntry(Conference toInsert) {
@@ -80,7 +86,7 @@
HistoryCall persistent = new HistoryCall(call);
try {
- Log.w("HistoryManager", "HistoryDao().create() " + persistent.getNumber() + " " + persistent.getStartDate().toString() + " " + persistent.getEndDate());
+ Log.w("HistoryServiceImpl", "HistoryDao().create() " + persistent.getNumber() + " " + persistent.getStartDate().toString() + " " + persistent.getEndDate());
getHelper().getHistoryDao().create(persistent);
} catch (SQLException e) {
e.printStackTrace();
@@ -92,7 +98,7 @@
public boolean insertNewTextMessage(HistoryText txt) {
try {
- Log.d("HistoryManager", "HistoryDao().create() id:" + txt.id + " acc:" + txt.getAccountID() + " num:" + txt.getNumber() + " date:" + txt.getDate().toString() + " msg:" + txt.getMessage());
+ Log.d("HistoryServiceImpl", "HistoryDao().create() id:" + txt.id + " acc:" + txt.getAccountID() + " num:" + txt.getNumber() + " date:" + txt.getDate().toString() + " msg:" + txt.getMessage());
getHelper().getTextHistoryDao().create(txt);
} catch (SQLException e) {
e.printStackTrace();
@@ -111,7 +117,7 @@
public boolean updateTextMessage(HistoryText txt) {
try {
- Log.w("HistoryManager", "HistoryDao().update() id:" + txt.id + " acc:" + txt.getAccountID() + " num:" + txt.getNumber() + " date:" + txt.getDate().toString() + " msg:" + txt.getMessage());
+ Log.w("HistoryServiceImpl", "HistoryDao().update() id:" + txt.id + " acc:" + txt.getAccountID() + " num:" + txt.getNumber() + " date:" + txt.getDate().toString() + " msg:" + txt.getMessage());
getHelper().getTextHistoryDao().update(txt);
} catch (SQLException e) {
e.printStackTrace();
@@ -129,6 +135,15 @@
}
/**
+ * Init Helper for our DB
+ */
+ public void initHelper() {
+ if (historyDBHelper == null) {
+ historyDBHelper = OpenHelperManager.getHelper(mContext, DatabaseHelper.class);
+ }
+ }
+
+ /**
* Retrieve helper for our DB
*/
private DatabaseHelper getHelper() {
@@ -189,14 +204,17 @@
}
}
- public boolean clearDB() {
+ @Override
+ public void clearHistory() {
try {
TableUtils.clearTable(getHelper().getConnectionSource(), HistoryCall.class);
TableUtils.clearTable(getHelper().getConnectionSource(), HistoryText.class);
+
+ // notify the observers
+ setChanged();
+ notifyObservers();
} catch (SQLException e) {
- e.printStackTrace();
- return false;
+ Log.e(TAG, "Error while clearing history tables", e);
}
- return true;
}
}
diff --git a/ring-android/app/src/main/java/cx/ring/services/SettingsServiceImpl.java b/ring-android/app/src/main/java/cx/ring/services/SettingsServiceImpl.java
new file mode 100644
index 0000000..a441374
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/services/SettingsServiceImpl.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ * Author: Thibault Wittemberg <thibault.wittemberg@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package cx.ring.services;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import javax.inject.Inject;
+
+import cx.ring.model.Settings;
+
+public class SettingsServiceImpl extends SettingsService {
+
+ public static final String RING_SETTINGS = "ring_settings";
+
+ public static final String RING_MOBILE_DATA = "mobile_data";
+ public static final String RING_SYSTEM_CONTACTS = "system_contacts";
+ public static final String RING_PLACE_CALLS = "place_calls";
+ public static final String RING_ON_STARTUP = "on_startup";
+
+ @Inject
+ Context mContext;
+
+ @Override
+ public void saveSettings(Settings settings) {
+ SharedPreferences appPrefs = mContext.getSharedPreferences(RING_SETTINGS, Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = appPrefs.edit();
+ edit.clear();
+ edit.putBoolean(RING_MOBILE_DATA, settings.isAllowMobileData());
+ edit.putBoolean(RING_SYSTEM_CONTACTS, settings.isAllowSystemContacts());
+ edit.putBoolean(RING_PLACE_CALLS, settings.isAllowPlaceSystemCalls());
+ edit.putBoolean(RING_ON_STARTUP, settings.isAllowRingOnStartup());
+
+ edit.apply();
+
+ // notify the observers
+ setChanged();
+ notifyObservers();
+ }
+
+ @Override
+ public Settings loadSettings() {
+ Settings settings = new Settings();
+ SharedPreferences appPrefs = mContext.getSharedPreferences(RING_SETTINGS, Context.MODE_PRIVATE);
+
+ settings.setAllowMobileData(appPrefs.getBoolean(RING_MOBILE_DATA, false));
+ settings.setAllowSystemContacts(appPrefs.getBoolean(RING_SYSTEM_CONTACTS, true));
+ settings.setAllowPlaceSystemCalls(appPrefs.getBoolean(RING_PLACE_CALLS, false));
+ settings.setAllowRingOnStartup(appPrefs.getBoolean(RING_ON_STARTUP, true));
+
+ return settings;
+ }
+}
diff --git a/ring-android/app/src/main/java/cx/ring/settings/SettingsFragment.java b/ring-android/app/src/main/java/cx/ring/settings/SettingsFragment.java
new file mode 100644
index 0000000..9d1e659
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/settings/SettingsFragment.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2004-2016 Savoir-faire Linux Inc.
+ *
+ * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ * Romain Bertozzi <romain.bertozzi@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package cx.ring.settings;
+
+import android.Manifest;
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.design.widget.Snackbar;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.AlertDialog;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CompoundButton;
+import android.widget.Switch;
+import android.widget.Toast;
+
+import javax.inject.Inject;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnCheckedChanged;
+import butterknife.OnClick;
+import butterknife.Unbinder;
+import cx.ring.R;
+import cx.ring.application.RingApplication;
+import cx.ring.client.HomeActivity;
+import cx.ring.model.Settings;
+import cx.ring.mvp.GenericView;
+import cx.ring.service.LocalService;
+
+/**
+ * TODO: improvements : handle multiples permissions for feature.
+ */
+public class SettingsFragment extends Fragment implements GenericView<SettingsViewModel> {
+
+ Unbinder mUnbinder;
+
+ private boolean mIsRefreshingViewFromPresenter;
+
+ @Inject
+ SettingsPresenter mSettingsPresenter;
+
+ @Inject
+ Context mContext;
+
+ @BindView(R.id.settings_mobile_data)
+ Switch mViewMobileData;
+
+ @BindView(R.id.settings_contacts)
+ Switch mViewContacts;
+
+ @BindView(R.id.settings_place_call)
+ Switch mViewPlaceCall;
+
+ @BindView(R.id.settings_startup)
+ Switch mViewStartup;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
+ final View inflatedView = inflater.inflate(R.layout.frag_settings, parent, false);
+
+ // views injection
+ mUnbinder = ButterKnife.bind(this, inflatedView);
+
+ // dependency injection
+ ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+
+ return inflatedView;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ ((HomeActivity) getActivity()).setToolbarState(false, R.string.menu_item_settings);
+
+ // view binding
+ mSettingsPresenter.bindView(this);
+
+ // loading preferences
+ mSettingsPresenter.loadSettings();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+
+ // Butterknife unbinding
+ mUnbinder.unbind();
+
+ // view unbinding
+ mSettingsPresenter.unbindView();
+ }
+
+ @OnCheckedChanged({R.id.settings_mobile_data, R.id.settings_contacts, R.id.settings_place_call, R.id.settings_startup})
+ public void onSettingsCheckedChanged(CompoundButton button, boolean isChecked) {
+
+ String neededPermission = null;
+
+ if (isChecked) {
+ switch (button.getId()) {
+ case R.id.settings_contacts:
+ neededPermission = Manifest.permission.READ_CONTACTS;
+ break;
+ case R.id.settings_place_call:
+ neededPermission = Manifest.permission.WRITE_CALL_LOG;
+ break;
+ default:
+ neededPermission = null;
+ break;
+ }
+ }
+
+ // No specific permission needed but we known that user as triggered un settings change
+ if (TextUtils.isEmpty(neededPermission) && !mIsRefreshingViewFromPresenter) {
+ saveSettings();
+ return;
+ }
+
+ // Some specific permissions are required, we must check for them
+ if (!TextUtils.isEmpty(neededPermission)) {
+ if (ContextCompat.checkSelfPermission(mContext, neededPermission) != PackageManager.PERMISSION_GRANTED) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ //~ Ask permission to use the contacts of the device
+ if (((RingApplication) getActivity().getApplication()).canAskForPermission(neededPermission)) {
+ requestPermissions(new String[]{neededPermission}, LocalService.PERMISSIONS_REQUEST);
+ }
+ }
+ } else if (!mIsRefreshingViewFromPresenter){
+ // permission is already granted
+ saveSettings();
+ }
+ }
+ }
+
+ private void saveSettings() {
+ Settings newSettings = new Settings();
+
+ newSettings.setAllowMobileData(mViewMobileData.isChecked());
+ newSettings.setAllowSystemContacts(mViewContacts.isChecked());
+ newSettings.setAllowPlaceSystemCalls(mViewPlaceCall.isChecked());
+ newSettings.setAllowRingOnStartup(mViewStartup.isChecked());
+
+ // save settings according to UI inputs
+ mSettingsPresenter.saveSettings(newSettings);
+ }
+
+ @OnClick(R.id.settings_clear_history)
+ public void onClearHistoryClick() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(getString(R.string.clear_history_dialog_title))
+ .setMessage(getString(R.string.clear_history_dialog_message))
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+
+ // ask the presenter to clear history
+ mSettingsPresenter.clearHistory();
+
+ Snackbar.make(getView(),
+ getString(R.string.clear_history_completed),
+ Snackbar.LENGTH_SHORT).show();
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ //~ Empty
+ }
+ });
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode,
+ @NonNull String permissions[],
+ @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ for (int i = 0, n = permissions.length; i < n; ++i) {
+ if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
+ String permission = permissions[i];
+ ((RingApplication) getActivity().getApplication()).permissionHasBeenAsked(permission);
+ switch (permission) {
+ case Manifest.permission.READ_CONTACTS:
+ mViewContacts.setChecked(false);
+ presentReadContactPermissionExplanationToast();
+ break;
+ case Manifest.permission.WRITE_CALL_LOG:
+ mViewPlaceCall.setChecked(false);
+ presentWriteCallLogPermissionExplanationToast();
+ break;
+ }
+ }
+ }
+
+ saveSettings();
+ }
+
+ /**
+ * Presents a Toast explaining why the Read Contacts permission is required to display the devi-
+ * ces contacts in Ring.
+ */
+ private void presentReadContactPermissionExplanationToast() {
+ Activity activity = getActivity();
+ if (null != activity) {
+ String toastMessage = getString(R.string.permission_dialog_read_contacts_message);
+ Toast.makeText(activity, toastMessage, Toast.LENGTH_LONG).show();
+ }
+ }
+
+ /**
+ * Presents a Toast explaining why the Write Call Log permission is required to enable the cor-
+ * responding feature.
+ */
+ private void presentWriteCallLogPermissionExplanationToast() {
+ Activity activity = getActivity();
+ if (null != activity) {
+ String toastMessage = getString(R.string.permission_dialog_write_call_log_message);
+ Toast.makeText(activity, toastMessage, Toast.LENGTH_LONG).show();
+ }
+ }
+
+ //region View Methods Implementation
+ @Override
+ public void showViewModel(SettingsViewModel viewModel) {
+ mIsRefreshingViewFromPresenter = true;
+ mViewMobileData.setChecked(viewModel.isAllowMobileData());
+ mViewContacts.setChecked(viewModel.isAllowSystemContacts());
+ mViewPlaceCall.setChecked(viewModel.isAllowPlaceSystemCalls());
+ mViewStartup.setChecked(viewModel.isAllowRingOnStartup());
+ mIsRefreshingViewFromPresenter = false;
+ }
+ //endregion
+}
diff --git a/ring-android/app/src/main/res/layout/frag_settings.xml b/ring-android/app/src/main/res/layout/frag_settings.xml
new file mode 100644
index 0000000..16ccef4
--- /dev/null
+++ b/ring-android/app/src/main/res/layout/frag_settings.xml
@@ -0,0 +1,303 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (c) 2016 Savoir-faire Linux Inc.
+
+Author: Thibault Wittemberg <thibault.wittemberg@savoirfairelinux.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="@dimen/padding_medium">
+
+ <!-- Network settings -->
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:text="@string/pref_category_network"
+ android:textColor="@color/color_primary_dark"
+ android:textSize="18sp" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="8dp"
+ android:weightSum="1">
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="0.2">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:src="@drawable/ic_perm_data_setting_black_24dp"
+ android:contentDescription="@string/pref_mobileData_summary" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.6"
+ android:orientation="vertical">
+
+ <TextView
+ style="@style/ListPrimary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:lines="1"
+ android:text="@string/pref_mobileData_title" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/pref_mobileData_summary" />
+
+ </LinearLayout>
+
+ <Switch
+ android:id="@+id/settings_mobile_data"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="0.2"
+ android:checked="false" />
+
+ </LinearLayout>
+
+ <!-- Contacts settings -->
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:text="@string/pref_category_contacts"
+ android:textColor="@color/color_primary_dark"
+ android:textSize="18sp" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="8dp"
+ android:weightSum="1">
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="0.2">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:src="@drawable/ic_group_black"
+ android:contentDescription="@string/pref_systemContacts_summary" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.6"
+ android:orientation="vertical">
+
+ <TextView
+ style="@style/ListPrimary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:lines="1"
+ android:text="@string/pref_systemContacts_title" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/pref_systemContacts_summary" />
+
+ </LinearLayout>
+
+ <Switch
+ android:id="@+id/settings_contacts"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="0.2"
+ android:checked="false" />
+
+ </LinearLayout>
+
+ <!-- System settings -->
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:text="@string/pref_category_system"
+ android:textColor="@color/color_primary_dark"
+ android:textSize="18sp" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="8dp"
+ android:weightSum="1">
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="0.2">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:src="@drawable/ic_dialpad_black"
+ android:contentDescription="@string/pref_systemDialer_summary" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.6"
+ android:orientation="vertical">
+
+ <TextView
+ style="@style/ListPrimary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:lines="1"
+ android:ellipsize="end"
+ android:text="@string/pref_systemDialer_title" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/pref_systemDialer_summary" />
+
+ </LinearLayout>
+
+ <Switch
+ android:id="@+id/settings_place_call"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="0.2"
+ android:checked="false" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="8dp"
+ android:weightSum="1">
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="0.2">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:src="@drawable/ic_android_black"
+ android:contentDescription="@string/pref_startOnBoot_summary" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.6"
+ android:orientation="vertical">
+
+ <TextView
+ style="@style/ListPrimary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:lines="1"
+ android:ellipsize="end"
+ android:text="@string/pref_startOnBoot_title" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/pref_startOnBoot_summary" />
+
+ </LinearLayout>
+
+ <Switch
+ android:id="@+id/settings_startup"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="0.2"
+ android:checked="false" />
+
+ </LinearLayout>
+
+ <!-- Privacy -->
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:text="@string/pref_category_privacy"
+ android:textColor="@color/color_primary_dark"
+ android:textSize="18sp" />
+
+ <LinearLayout
+ android:id="@+id/settings_clear_history"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackground"
+ android:padding="8dp"
+ android:orientation="vertical">
+
+ <TextView
+ style="@style/ListPrimary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:lines="1"
+ android:ellipsize="end"
+ android:text="@string/pref_clearHistory_title" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/pref_clearHistory_summary" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+</ScrollView>
diff --git a/ring-android/app/src/main/res/xml/preferences.xml b/ring-android/app/src/main/res/xml/preferences.xml
deleted file mode 100644
index 17896ed..0000000
--- a/ring-android/app/src/main/res/xml/preferences.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-Copyright (c) 2016 Savoir-faire Linux Inc.
-
-Author: Adrien Beraud <adrien.beraud@savoirfairelinux.com>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
--->
-<android.support.v7.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
-
- <android.support.v7.preference.PreferenceCategory android:title="@string/pref_category_network">
- <android.support.v14.preference.SwitchPreference
- android:defaultValue="false"
- android:icon="@drawable/ic_perm_data_setting_black_24dp"
- android:key="@string/pref_mobileData_key"
- android:summary="@string/pref_mobileData_summary"
- android:title="@string/pref_mobileData_title" />
- </android.support.v7.preference.PreferenceCategory>
-
- <android.support.v7.preference.PreferenceCategory android:title="@string/pref_category_contacts">
- <android.support.v14.preference.SwitchPreference
- android:defaultValue="true"
- android:icon="@drawable/ic_group_black"
- android:key="@string/pref_systemContacts_key"
- android:summary="@string/pref_systemContacts_summary"
- android:title="@string/pref_systemContacts_title" />
-
- </android.support.v7.preference.PreferenceCategory>
- <android.support.v7.preference.PreferenceCategory android:title="@string/pref_category_system">
-
- <android.support.v14.preference.SwitchPreference
- android:defaultValue="false"
- android:icon="@drawable/ic_dialpad_black"
- android:key="@string/pref_systemDialer_key"
- android:summary="@string/pref_systemDialer_summary"
- android:title="@string/pref_systemDialer_title" />
-
-
- <android.support.v14.preference.SwitchPreference
- android:defaultValue="true"
- android:icon="@drawable/ic_android_black"
- android:key="@string/pref_startOnBoot_key"
- android:summary="@string/pref_startOnBoot_summary"
- android:title="@string/pref_startOnBoot_title" />
-
- </android.support.v7.preference.PreferenceCategory>
-
- <android.support.v7.preference.PreferenceCategory android:title="@string/pref_category_privacy">
- <Preference
- android:key="@string/pref_clearHistory_key"
- android:summary="@string/pref_clearHistory_summary"
- android:title="@string/pref_clearHistory_title" />
- </android.support.v7.preference.PreferenceCategory>
-
-</android.support.v7.preference.PreferenceScreen>
\ No newline at end of file
diff --git a/ring-android/libringclient/src/main/java/cx/ring/model/Settings.java b/ring-android/libringclient/src/main/java/cx/ring/model/Settings.java
new file mode 100644
index 0000000..ccdebe6
--- /dev/null
+++ b/ring-android/libringclient/src/main/java/cx/ring/model/Settings.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ * Author: Thibault Wittemberg <thibault.wittemberg@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package cx.ring.model;
+
+public class Settings {
+
+ private boolean mAllowMobileData;
+ private boolean mAllowSystemContacts;
+ private boolean mAllowPlaceSystemCalls;
+ private boolean mAllowRingOnStartup;
+
+ public boolean isAllowMobileData() {
+ return mAllowMobileData;
+ }
+
+ public void setAllowMobileData(boolean allowMobileData) {
+ this.mAllowMobileData = allowMobileData;
+ }
+
+ public boolean isAllowSystemContacts() {
+ return mAllowSystemContacts;
+ }
+
+ public void setAllowSystemContacts(boolean allowSystemContacts) {
+ this.mAllowSystemContacts = allowSystemContacts;
+ }
+
+ public boolean isAllowPlaceSystemCalls() {
+ return mAllowPlaceSystemCalls;
+ }
+
+ public void setAllowPlaceSystemCalls(boolean allowPlaceSystemCalls) {
+ this.mAllowPlaceSystemCalls = allowPlaceSystemCalls;
+ }
+
+ public boolean isAllowRingOnStartup() {
+ return mAllowRingOnStartup;
+ }
+
+ public void setAllowRingOnStartup(boolean allowRingOnStartup) {
+ this.mAllowRingOnStartup = allowRingOnStartup;
+ }
+}
diff --git a/ring-android/libringclient/src/main/java/cx/ring/services/HistoryService.java b/ring-android/libringclient/src/main/java/cx/ring/services/HistoryService.java
new file mode 100644
index 0000000..327d3cc
--- /dev/null
+++ b/ring-android/libringclient/src/main/java/cx/ring/services/HistoryService.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ * Author: Thibault Wittemberg <thibault.wittemberg@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package cx.ring.services;
+
+import java.util.Observable;
+
+public abstract class HistoryService extends Observable {
+
+ public abstract void clearHistory();
+
+}
diff --git a/ring-android/libringclient/src/main/java/cx/ring/services/SettingsService.java b/ring-android/libringclient/src/main/java/cx/ring/services/SettingsService.java
new file mode 100644
index 0000000..37f5b90
--- /dev/null
+++ b/ring-android/libringclient/src/main/java/cx/ring/services/SettingsService.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ * Author: Thibault Wittemberg <thibault.wittemberg@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package cx.ring.services;
+
+import java.util.Observable;
+
+import cx.ring.model.Settings;
+
+public abstract class SettingsService extends Observable {
+
+ public abstract void saveSettings(Settings settings);
+
+ public abstract Settings loadSettings();
+
+}
diff --git a/ring-android/libringclient/src/main/java/cx/ring/settings/SettingsPresenter.java b/ring-android/libringclient/src/main/java/cx/ring/settings/SettingsPresenter.java
new file mode 100644
index 0000000..a64e795
--- /dev/null
+++ b/ring-android/libringclient/src/main/java/cx/ring/settings/SettingsPresenter.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ * Author: Thibault Wittemberg <thibault.wittemberg@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package cx.ring.settings;
+
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.inject.Inject;
+
+import cx.ring.model.Settings;
+import cx.ring.mvp.GenericView;
+import cx.ring.mvp.RootPresenter;
+import cx.ring.services.HistoryService;
+import cx.ring.services.SettingsService;
+
+public class SettingsPresenter extends RootPresenter<GenericView<SettingsViewModel>> implements Observer {
+
+ @Inject
+ SettingsService mSettingsService;
+
+ @Inject
+ HistoryService mHistoryService;
+
+ @Override
+ public void afterInjection() {
+ // We observe the application settings changes
+ mSettingsService.addObserver(this);
+ // no need to observe the history changes
+ // only the smartlist should do so
+ }
+
+ public void loadSettings() {
+ if (getView() == null) {
+ return;
+ }
+
+ // load the app settings
+ Settings settings = mSettingsService.loadSettings();
+
+ // let the view display the associated ViewModel
+ getView().showViewModel(new SettingsViewModel(settings));
+ }
+
+ public void saveSettings (Settings settings) {
+ mSettingsService.saveSettings(settings);
+ }
+
+ public void clearHistory() {
+ mHistoryService.clearHistory();
+ }
+
+ @Override
+ public void update(Observable observable, Object o) {
+ loadSettings();
+ }
+}
diff --git a/ring-android/libringclient/src/main/java/cx/ring/settings/SettingsViewModel.java b/ring-android/libringclient/src/main/java/cx/ring/settings/SettingsViewModel.java
new file mode 100644
index 0000000..2ce2827
--- /dev/null
+++ b/ring-android/libringclient/src/main/java/cx/ring/settings/SettingsViewModel.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ * Author: Thibault Wittemberg <thibault.wittemberg@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package cx.ring.settings;
+
+import cx.ring.model.Settings;
+
+public class SettingsViewModel {
+
+ Settings mSettings;
+
+ public SettingsViewModel(Settings settings) {
+ mSettings = settings;
+ }
+
+ public boolean isAllowMobileData() {
+ return mSettings.isAllowMobileData();
+ }
+
+ public boolean isAllowSystemContacts() {
+ return mSettings.isAllowSystemContacts();
+ }
+
+ public boolean isAllowPlaceSystemCalls() {
+ return mSettings.isAllowPlaceSystemCalls();
+ }
+
+ public boolean isAllowRingOnStartup() {
+ return mSettings.isAllowRingOnStartup();
+ }
+}