diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.java b/app/src/main/java/info/nightscout/androidaps/MainActivity.java index cdd5c59523..84f297c0ae 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.java @@ -2,19 +2,15 @@ package info.nightscout.androidaps; import android.Manifest; import android.app.Activity; -import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Rect; -import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.PowerManager; -import android.provider.Settings; import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewPager; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; @@ -52,24 +48,17 @@ import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.setupwizard.SetupWizardActivity; import info.nightscout.androidaps.tabs.SlidingTabLayout; import info.nightscout.androidaps.tabs.TabPageAdapter; +import info.nightscout.utils.AndroidPermission; import info.nightscout.utils.ImportExportPrefs; import info.nightscout.utils.LocaleHelper; import info.nightscout.utils.LogDialog; import info.nightscout.utils.OKDialog; import info.nightscout.utils.PasswordProtection; import info.nightscout.utils.SP; -import info.nightscout.utils.ToastUtils; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static Logger log = LoggerFactory.getLogger(MainActivity.class); - static final int CASE_STORAGE = 0x1; - static final int CASE_SMS = 0x2; - static final int CASE_LOCATION = 0x3; - - private boolean askForSMS = false; - private boolean askForLocation = true; - ImageButton menuButton; protected PowerManager.WakeLock mWakeLock; @@ -85,10 +74,10 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe checkEula(); if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { - askForPermission(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.WRITE_EXTERNAL_STORAGE}, CASE_STORAGE); + AndroidPermission.askForPermission(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE}, AndroidPermission.CASE_STORAGE); } - askForBatteryOptimizationPermission(); + AndroidPermission.askForBatteryOptimizationPermission(this); doMigrations(); if (!SP.getBoolean(R.string.key_setupwizard_processed, false)) { @@ -219,22 +208,18 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { synchronized (this) { if (SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)) { - setAskForSMS(); + AndroidPermission.setAskForSMS(); } } } } } - private synchronized void setAskForSMS() { - askForSMS = true; - } - @Override protected void onResume() { super.onResume(); - askForSMSPermissions(); - askForLocationPermissions(); + AndroidPermission.askForSMSPermissions(this); + AndroidPermission.askForLocationPermissions(this); MainApp.bus().post(new EventFeatureRunning(EventFeatureRunning.Feature.MAIN)); } @@ -246,86 +231,22 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe super.onDestroy(); } - private void askForBatteryOptimizationPermission() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - final String packageName = getPackageName(); - - final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - if (!pm.isIgnoringBatteryOptimizations(packageName)) { - log.debug("Requesting ignore battery optimization"); - - OKDialog.show(this, MainApp.gs(R.string.pleaseallowpermission), String.format(MainApp.gs(R.string.needwhitelisting), MainApp.gs(R.string.app_name)), new Runnable() { - - @Override - public void run() { - try { - final Intent intent = new Intent(); - - // ignoring battery optimizations required for constant connection - intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); - intent.setData(Uri.parse("package:" + packageName)); - startActivity(intent); - - } catch (ActivityNotFoundException e) { - final String msg = MainApp.gs(R.string.batteryoptimalizationerror); - ToastUtils.showToastInUiThread(getApplicationContext(), msg); - log.error(msg); - } - } - }); - } - } - } - - private synchronized void askForSMSPermissions() { - if (askForSMS) { //only when settings were changed an MainActivity resumes. - askForSMS = false; - if (SP.getBoolean(R.string.smscommunicator_remotecommandsallowed, false)) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { - askForPermission(new String[]{Manifest.permission.RECEIVE_SMS, - Manifest.permission.SEND_SMS, - Manifest.permission.RECEIVE_MMS}, CASE_SMS); - } - } - } - } - - private synchronized void askForLocationPermissions() { - if (askForLocation) { //only when settings were changed an MainActivity resumes. - askForLocation = false; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - askForPermission(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_FINE_LOCATION}, CASE_LOCATION); - } - } - } - - private void askForPermission(String[] permission, Integer requestCode) { - boolean test = false; - for (int i = 0; i < permission.length; i++) { - test = test || (ContextCompat.checkSelfPermission(this, permission[i]) != PackageManager.PERMISSION_GRANTED); - } - if (test) { - ActivityCompat.requestPermissions(this, permission, requestCode); - } - } - @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (permissions.length != 0) { if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED) { switch (requestCode) { - case CASE_STORAGE: + case AndroidPermission.CASE_STORAGE: //show dialog after permission is granted AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setMessage(R.string.alert_dialog_storage_permission_text); alert.setPositiveButton(R.string.ok, null); alert.show(); break; - case CASE_LOCATION: - case CASE_SMS: + case AndroidPermission.CASE_LOCATION: + case AndroidPermission.CASE_SMS: + case AndroidPermission.CASE_BATTERY: break; } } @@ -420,13 +341,13 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe if (MainApp.engineeringMode) message += "\n" + MainApp.gs(R.string.engineering_mode_enabled); message += MainApp.gs(R.string.about_link_urls); - final SpannableString messageSpanned = new SpannableString(message); + final SpannableString messageSpanned = new SpannableString(message); Linkify.addLinks(messageSpanned, Linkify.WEB_URLS); builder.setMessage(messageSpanned); builder.setPositiveButton(MainApp.gs(R.string.ok), null); AlertDialog alertDialog = builder.create(); alertDialog.show(); - ((TextView)alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); + ((TextView) alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); break; case R.id.nav_exit: log.debug("Exiting"); diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.java b/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.java index 66f1d07d33..fbff517c32 100644 --- a/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.java +++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.java @@ -1,6 +1,13 @@ package info.nightscout.androidaps.setupwizard; +import android.Manifest; +import android.content.ActivityNotFoundException; +import android.content.Context; import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.os.PowerManager; +import android.provider.Settings; import android.support.v7.app.AppCompatActivity; import com.squareup.otto.Subscribe; @@ -45,19 +52,24 @@ import info.nightscout.androidaps.setupwizard.elements.SWEditString; import info.nightscout.androidaps.setupwizard.elements.SWEditUrl; import info.nightscout.androidaps.setupwizard.events.EventSWLabel; import info.nightscout.androidaps.setupwizard.events.EventSWUpdate; +import info.nightscout.utils.AndroidPermission; import info.nightscout.utils.ImportExportPrefs; import info.nightscout.utils.LocaleHelper; import info.nightscout.utils.PasswordProtection; import info.nightscout.utils.SP; +import info.nightscout.utils.ToastUtils; public class SWDefinition { private static Logger log = LoggerFactory.getLogger(SWDefinition.class); + private String packageName; + private AppCompatActivity activity; private List screens = new ArrayList<>(); public void setActivity(AppCompatActivity activity) { this.activity = activity; + packageName = activity.getPackageName(); } public AppCompatActivity getActivity() { @@ -99,6 +111,36 @@ public class SWDefinition { return SP.contains(R.string.key_language); }) ) + .add(new SWScreen(R.string.permission) + .skippable(true) + .add(new SWInfotext() + .label(String.format(MainApp.gs(R.string.needwhitelisting), MainApp.gs(R.string.app_name)))) + .add(new SWBreak()) + .add(new SWButton() + .text(R.string.askforpermission) + .action(() -> AndroidPermission.askForPermission(getActivity(), Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, AndroidPermission.CASE_BATTERY))) + .visibility(() -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)) + ) + .add(new SWScreen(R.string.permission) + .skippable(true) + .add(new SWInfotext() + .label(MainApp.gs(R.string.needlocationpermission))) + .add(new SWBreak()) + .add(new SWButton() + .text(R.string.askforpermission) + .action(() -> AndroidPermission.askForPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION, AndroidPermission.CASE_LOCATION))) + .visibility(() -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)) + ) + .add(new SWScreen(R.string.permission) + .skippable(true) + .add(new SWInfotext() + .label(MainApp.gs(R.string.needstoragepermission))) + .add(new SWBreak()) + .add(new SWButton() + .text(R.string.askforpermission) + .action(() -> AndroidPermission.askForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE, AndroidPermission.CASE_STORAGE))) + .visibility(() -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) + ) .add(new SWScreen(R.string.nsclientinternal_title) .skippable(true) .add(new SWInfotext() diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/SetupWizardActivity.java b/app/src/main/java/info/nightscout/androidaps/setupwizard/SetupWizardActivity.java index 68ebcafdad..fde19eafaa 100644 --- a/app/src/main/java/info/nightscout/androidaps/setupwizard/SetupWizardActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/SetupWizardActivity.java @@ -1,7 +1,10 @@ package info.nightscout.androidaps.setupwizard; import android.content.Intent; +import android.content.pm.PackageManager; import android.os.Bundle; +import android.support.v4.app.ActivityCompat; +import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.LinearLayout; @@ -24,6 +27,7 @@ import info.nightscout.androidaps.plugins.ConstraintsObjectives.events.EventObje import info.nightscout.androidaps.plugins.NSClientInternal.events.EventNSClientStatus; import info.nightscout.androidaps.setupwizard.elements.SWItem; import info.nightscout.androidaps.setupwizard.events.EventSWUpdate; +import info.nightscout.utils.AndroidPermission; import info.nightscout.utils.LocaleHelper; import info.nightscout.utils.OKDialog; import info.nightscout.utils.SP; @@ -187,4 +191,27 @@ public class SetupWizardActivity extends AppCompatActivity { } return currentWizardPage; } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (permissions.length != 0) { + if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED) { + switch (requestCode) { + case AndroidPermission.CASE_STORAGE: + //show dialog after permission is granted + AlertDialog.Builder alert = new AlertDialog.Builder(this); + alert.setMessage(R.string.alert_dialog_storage_permission_text); + alert.setPositiveButton(R.string.ok, null); + alert.show(); + break; + case AndroidPermission.CASE_LOCATION: + case AndroidPermission.CASE_SMS: + case AndroidPermission.CASE_BATTERY: + break; + } + } + } + } + } diff --git a/app/src/main/java/info/nightscout/utils/AndroidPermission.java b/app/src/main/java/info/nightscout/utils/AndroidPermission.java new file mode 100644 index 0000000000..c0ce505e9b --- /dev/null +++ b/app/src/main/java/info/nightscout/utils/AndroidPermission.java @@ -0,0 +1,78 @@ +package info.nightscout.utils; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Build; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; + +import info.nightscout.androidaps.R; + +public class AndroidPermission { + + private static boolean askForSMS = false; + private static boolean askForLocation = true; + + public static final int CASE_STORAGE = 0x1; + public static final int CASE_SMS = 0x2; + public static final int CASE_LOCATION = 0x3; + public static final int CASE_BATTERY = 0x4; + + public static void askForPermission(Activity activity, String[] permission, Integer requestCode) { + boolean test = false; + for (int i = 0; i < permission.length; i++) { + test = test || (ContextCompat.checkSelfPermission(activity, permission[i]) != PackageManager.PERMISSION_GRANTED); + } + if (test) { + ActivityCompat.requestPermissions(activity, permission, requestCode); + } + } + + public static void askForPermission(Activity activity, String permission, Integer requestCode) { + String[] permissions = {permission}; + + if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) + ActivityCompat.requestPermissions(activity, permissions, requestCode); + } + + public static boolean checkForPermission(Context context, String permission) { + return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED; + } + + public static synchronized void askForSMSPermissions(Activity activity) { + if (askForSMS) { //only when settings were changed an MainActivity resumes. + askForSMS = false; + if (SP.getBoolean(R.string.smscommunicator_remotecommandsallowed, false)) { + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { + AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.RECEIVE_SMS, + Manifest.permission.SEND_SMS, + Manifest.permission.RECEIVE_MMS}, AndroidPermission.CASE_SMS); + } + } + } + } + + public static synchronized void askForBatteryOptimizationPermission(Activity activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}, AndroidPermission.CASE_BATTERY); + } + } + + public static synchronized void askForLocationPermissions(Activity activity) { + if (askForLocation) { //only when settings were changed an MainActivity resumes. + askForLocation = false; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION}, AndroidPermission.CASE_LOCATION); + } + } + } + + public static synchronized void setAskForSMS() { + askForSMS = true; + } + +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index beb1efd994..27695b1d6a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1080,4 +1080,8 @@ Please select source of profile. If patient is a child you should use NS profile. If there is nobody following you on Nightscout you will probably prefer Local profile. Please remember that you are only selecting the profile source. To use it you must activate it by executing \"Profile switch\" Select one from availables algorithms. They are sorted from oldest to newest. Newer algorithm is usualy more powerfull and more aggresive. Thus if you are new looper you may probably start with AMA and not with latest one. Do not forget to read the OpenAPS documentation and configure it before use. Start your first objective + Permission + Ask for permission + Application needs location permission for BT scan + Application needs storage permission to be able store log files