Skip to content

Commit

Permalink
Bangle.js: Extend intents functionality for Bangle.js
Browse files Browse the repository at this point in the history
...to allow intents to start activities on the android device.

Add pop-up asking for permission to "Display over other apps"

Add info for intents on Bangle.js

Add message to display on "Display over other apps" permission pop-up

Move permission to display over other apps to main build variant/flavor.

fix getting permission for display over other apps.

Clarify that permission to display over other apps is mainly for Bangle.js.
  • Loading branch information
Ganblejs authored and Ganblejs committed Aug 16, 2022
1 parent 70e60fb commit 60c7f79
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 10 deletions.
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Expand Up @@ -47,6 +47,9 @@
<uses-permission android:name="lineageos.permission.READ_WEATHER" />
<uses-permission android:name="org.omnirom.omnijaws.READ_WEATHER" />

<!-- Used for starting activities from the background with intents -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />


<uses-feature
android:name="android.hardware.bluetooth"
Expand Down
Expand Up @@ -283,6 +283,17 @@ public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
dialog.show(getSupportFragmentManager(), "NotifyPolicyPermissionsDialogFragment");
}
}

if (!android.provider.Settings.canDrawOverlays(getApplicationContext())) {
// If diplay over other apps access hasn't been granted
// Put up a dialog explaining why we need permissions (Polite, but also Play Store policy)
// When accepted, we open the Activity for permission to display over other apps.
if (pesterWithPermissions) {
DialogFragment dialog = new DisplayOverOthersPermissionsDialogFragment();
dialog.show(getSupportFragmentManager(), "DisplayOverOthersPermissionsDialogFragment");
}
}

// Check all the other permissions that we need to for Android M + later
checkAndRequestPermissions(true);
}
Expand Down Expand Up @@ -607,6 +618,26 @@ public void onClick(DialogInterface dialog, int id) {
}
}

/// Called from onCreate - this puts up a dialog explaining we need permissions, and goes to the correct Activity
public static class DisplayOverOthersPermissionsDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
Context context = getContext();
builder.setMessage(context.getString(R.string.permission_display_over_other_apps,
getContext().getString(R.string.app_name),
getContext().getString(R.string.ok)))
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Intent enableIntent = new Intent(android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(enableIntent);
}
});
return builder.create();
}
}

/// Called from checkAndRequestPermissions - this puts up a dialog explaining we need permissions, and then calls checkAndRequestPermissions (via an intent) when 'ok' pressed
public static class LocationPermissionsDialogFragment extends DialogFragment {
ControlCenterv2 controlCenter;
Expand Down
Expand Up @@ -649,23 +649,50 @@ public Map<String, String> getHeaders() throws AuthFailureError {
case "intent": {
Prefs devicePrefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
if (devicePrefs.getBoolean(PREF_DEVICE_INTENTS, false)) {
String action = json.getString("action");
JSONObject extra = json.getJSONObject("extra");
Intent in = new Intent();
in.setAction(action);
if (json.has("action")) in.setAction((String)json.get("action"));
if (json.has("category")) in.addCategory((String)json.get("category"));
if (json.has("mimetype")) in.setType((String)json.get("mimetype"));
if (json.has("data")) in.setData(Uri.parse((String)json.get("data")));
if (json.has("package") && !json.has("class")) in.setPackage((String)json.getString("package"));
if (json.has("package") && json.has("class")) in.setClassName((String)json.getString("package"), (String)json.getString("class"));
String target = "";
if (json.has("target")) target = (String)json.get("target");
JSONObject extra = new JSONObject();
if (json.has("extra")) extra = json.getJSONObject("extra");
if (extra != null) {
Iterator<String> iter = extra.keys();
while (iter.hasNext()) {
String key = iter.next();
in.putExtra(key, extra.getString(key));
}
}
LOG.info("Sending intent " + action);
this.getContext().getApplicationContext().sendBroadcast(in);
LOG.info("Sending intent: " + String.valueOf(in));
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);
break;
case "activity":
in.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.getContext().getApplicationContext().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()?
break;
default:
LOG.info("Targeting '"+target+"' isn't implemented or doesn't exist.");
GB.toast(getContext(), "Targeting '"+target+"' isn't implemented or it doesn't exist.", Toast.LENGTH_LONG, GB.INFO);
}
} else {
uartTxJSONError("intent", "Android Intents not enabled, check Gadgetbridge Device Settings");
}
} break;
} break;
}
case "force_calendar_sync": {
//if(!GBApplication.getPrefs().getBoolean("enable_calendar_sync", false)) return;
//pretty much like the updateEvents in CalendarReceiver, but would need a lot of libraries here
Expand Down
7 changes: 4 additions & 3 deletions app/src/main/res/values/strings.xml
Expand Up @@ -292,7 +292,7 @@
<string name="pref_title_device_internet_access">Allow Internet Access</string>
<string name="pref_summary_device_internet_access">Allow apps on this device to access the internet</string>
<string name="pref_title_device_intents">Allow Intents</string>
<string name="pref_summary_device_intents">Allow Bangle.js watch apps to send Android Intents, and allow other apps on Android (like Tasker) to send data to Bangle.js with the com.banglejs.uart.tx Intent.</string>
<string name="pref_summary_device_intents">Allow Bangle.js watch apps to send Android Intents, and allow other apps on Android (like Tasker) to send data to Bangle.js with the com.banglejs.uart.tx Intent. Needs permission to display over other apps to work in the background.</string>
<string name="pref_summary_sync_calendar">Enables calendar alerts, even when disconnected</string>
<string name="pref_title_sync_caldendar">Sync calendar events</string>
<string name="pref_summary_relax_firmware_checks">Relax firmware checks</string>
Expand Down Expand Up @@ -1241,9 +1241,10 @@
<string name="about_additional_contributions">Many thanks to all unlisted contributors for contributing code, translations, support, ideas, motivation, bug reports, money… ✊</string>
<string name="about_links">Links</string>
<string name="permission_granting_mandatory">All these permissions are required and instability might occur if not granted</string>
<string name="permission_notification_listener">%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</string>
<string name="permission_notification_policy_access">%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</string>
<string name="permission_notification_listener">%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.</string>
<string name="permission_notification_policy_access">%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.</string>
<string name="permission_location">%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.</string>
<string name="permission_display_over_other_apps">%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.</string>
<string name="error_version_check_extreme_caution">CAUTION: Error when checking version information! You should not continue! Saw version name \"%s\"</string>
<string name="require_location_provider">Location must be enabled</string>
<string name="companiondevice_pairing">CompanionDevice Pairing</string>
Expand Down

0 comments on commit 60c7f79

Please sign in to comment.