From 82315b32818ab534a0d5dda821fa9cadce6e81bc Mon Sep 17 00:00:00 2001 From: Ganblejs Date: Sun, 21 Aug 2022 12:26:09 +0200 Subject: [PATCH] Bangle.js: extending intents functionality (continuation) Add support for (explicit) service intents. Add support for setting flags for intents. Add support for setting multiple categories for intents. Add ability for Gadgetbridge to wake the Android device and leave the lock screen to start activities when it is sleeping. A new activity 'WakeActivity' is used for this. (Must use 'trusted device' in Android) Add dismiss-button to 'display over other apps' permission pop up. Bangle.js can send "gadgetbridge" as package info to accomodate the different GB build variants/flavours. Use only getContext() and not getApplicationContext() when executing the intents. --- app/src/banglejs/AndroidManifest.xml | 13 +++- app/src/main/AndroidManifest.xml | 7 +- .../activities/ControlCenterv2.java | 2 + .../gadgetbridge/activities/WakeActivity.java | 41 ++++++++++ .../devices/banglejs/BangleJSCoordinator.java | 1 - .../banglejs/BangleJSDeviceSupport.java | 78 +++++++++++++------ app/src/main/res/values/strings.xml | 3 +- 7 files changed, 114 insertions(+), 31 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/WakeActivity.java diff --git a/app/src/banglejs/AndroidManifest.xml b/app/src/banglejs/AndroidManifest.xml index 4a43bcf19..f285bad1f 100644 --- a/app/src/banglejs/AndroidManifest.xml +++ b/app/src/banglejs/AndroidManifest.xml @@ -2,7 +2,14 @@ - - - + + + + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ef58e16d3..578f7e773 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -50,7 +50,6 @@ - @@ -707,9 +706,15 @@ + + + + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java index 601feb69c..26cdeb3ad 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java @@ -633,6 +633,8 @@ public class ControlCenterv2 extends AppCompatActivity Intent enableIntent = new Intent(android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION); startActivity(enableIntent); } + }).setNegativeButton(R.string.dismiss, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) {} }); return builder.create(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/WakeActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/WakeActivity.java new file mode 100644 index 000000000..1495c9b8a --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/WakeActivity.java @@ -0,0 +1,41 @@ +package nodomain.freeyourgadget.gadgetbridge.activities; + +import android.app.Activity; +import android.app.KeyguardManager; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; +import android.view.WindowManager; + +import androidx.annotation.Nullable; + +public class WakeActivity extends Activity { + /* + By starting this activity via an intent sent e.g. by a Bangle.js the keyguard can be + dismissed automatically if the android device is in a trusted state (e.g. using a GB Device (Bangle.js) as a + trusted device via smart lock settings) + + First try to start the activity you want to start with an intent and then start this activity with a second intent, both initiated on the Bangle.js, or other device. + */ + + private void dismissKeyguard() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { + setTurnScreenOn(true); + KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); + keyguardManager.requestDismissKeyguard(this, null); + } else { + this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON|WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); + } + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(null); + // Unlock the android device if it's in a trusted state, otherwise request user action to unlock + dismissKeyguard(); + // Go back to last activity, which can have been waiting to start under + // the lock screen, e.g. it was previously initiated via intent message from Bangle.js + this.onBackPressed(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/banglejs/BangleJSCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/banglejs/BangleJSCoordinator.java index 5a68cf384..47ed683b8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/banglejs/BangleJSCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/banglejs/BangleJSCoordinator.java @@ -190,5 +190,4 @@ public class BangleJSCoordinator extends AbstractBLEDeviceCoordinator { for (int i=0; i iter = extra.keys(); while (iter.hasNext()) { String key = iter.next(); - in.putExtra(key, extra.getString(key)); + in.putExtra(key, extra.getString(key)); // Should this be implemented for other types, e.g. extra.getInt(key)? Or will this always work even if receiving ints/doubles/etc.? } } - LOG.info("Sending intent: " + String.valueOf(in)); + LOG.info("Executing intent:\n\t" + String.valueOf(in) + "\n\tTargeting: " + target); + //GB.toast(getContext(), String.valueOf(in), Toast.LENGTH_LONG, GB.INFO); switch (target) { - case "": - // This case should make sure intents matched to the original Bangle.js Gadgetbridge intents implementation still work. - this.getContext().getApplicationContext().sendBroadcast(in); - break; case "broadcastreceiver": - this.getContext().getApplicationContext().sendBroadcast(in); + getContext().sendBroadcast(in); break; - case "activity": - in.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - this.getContext().getApplicationContext().startActivity(in); + case "activity": // See wakeActivity.java if you want to start activities from under the keyguard/lock sceen. + getContext().startActivity(in); break; - case "service": // Targeting 'Service' is not yet implemented. - LOG.info("Targeting 'Service' not yet implemented."); - GB.toast(getContext(), "Targeting '"+target+"' is not yet implemented.", Toast.LENGTH_LONG, GB.INFO); - // Use jobInfo() and jobScheduler to program this part? Context.startService()? Context.bindService()? + case "service": // Should this be implemented differently, e.g. workManager? + getContext().startService(in); + break; + case "foregroundservice": // Should this be implemented differently, e.g. workManager? + getContext().startForegroundService(in); break; default: LOG.info("Targeting '"+target+"' isn't implemented or doesn't exist."); @@ -761,6 +776,19 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport { } } + private Intent addIntentFlag(Intent intent, String flag) { + try { + final Class intentClass = Intent.class; + final Field flagField = intentClass.getDeclaredField(flag); + intent.addFlags(flagField.getInt(null)); + } catch (final Exception e) { + // The user sent an invalid flag + LOG.info("Flag '"+flag+"' isn't implemented or doesn't exist and was therefore not set."); + GB.toast(getContext(), "Flag '"+flag+"' isn't implemented or it doesn't exist and was therefore not set.", Toast.LENGTH_LONG, GB.INFO); + } + return intent; + } + @Override public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c9c14dc71..1252b9b65 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -944,6 +944,7 @@ Cancel Delete OK + Dismiss Start Set Export/Import directory content @@ -1301,7 +1302,7 @@ %1$s needs access to Notifications in order to display them on your watch when your phone\'s screen is off.\n\nPlease tap \'%2$s\' then \'%1$s\' and enable \'Allow Notification Access\', then tap \'Back\' to return to %1$s. %1$s needs access to Do Not Disturb settings in order to honour them on your watch when your phone\'s screen is off.\n\nPlease tap \'%2$s\' then \'%1$s\' and enable \'Allow Do Not Disturb\', then tap \'Back\' to return to %1$s. %1$s needs access to your location in the background to allow it to stay connected to your watch even when your screen is off.\n\nPlease tap \'%2$s\' to agree. - %1$s needs permission to display over other apps in order to let Bangle.js watches start activities via intents when %1$s is in the background.\n\nThis can be used to start a music app and play a song, and many other things.\n\nPlease tap \'%2$s\' then \'%1$s\' and enable \'Allow display over other apps\', then tap \'Back\' to return to %1$s. + %1$s needs permission to display over other apps in order to let Bangle.js watches start activities via intents when %1$s is in the background.\n\nThis can be used to start a music app and play a song, and many other things.\n\nPlease tap \'%2$s\' then \'%1$s\' and enable \'Allow display over other apps\', then tap \'Back\' to return to %1$s.\n\nTo stop %1$s asking for permissions go to \'Settings\' and uncheck \'Check permission status\'.\n\nMake sure to grant %1$s the permissions needed to function as you expect. CAUTION: Error when checking version information! You should not continue! Saw version name \"%s\" Location must be enabled CompanionDevice Pairing