From 8dd1738354dbae311cf77342dae5c4f9c7f14adb Mon Sep 17 00:00:00 2001 From: Mike C Date: Mon, 2 Dec 2013 01:48:20 -0500 Subject: [PATCH 1/7] Initial Sony Smart Watch 2 (SW2) support --- .settings/org.eclipse.core.resources.prefs | 2 + AndroidManifest.xml | 50 ++++- project.properties | 5 +- ...18x18_black_white_message_notification.png | Bin 0 -> 2872 bytes .../icn_18x18_message_notification.png | Bin 0 -> 3260 bytes .../icn_30x30_message_notification.png | Bin 0 -> 3580 bytes res/drawable/icon_extension.png | Bin 0 -> 4024 bytes res/drawable/icon_extension_48.png | Bin 0 -> 4435 bytes res/values/strings.xml | 10 + res/xml/preferences.xml | 10 + .../dattasmoon/pebble/plugin/Constants.java | 5 + .../pebble/plugin/FireReceiver.java | 40 +++- .../pebble/plugin/NotificationService.java | 198 ++++++++++------- .../sony/plugin/SonyExtensionReceiver.java | 31 +++ .../sony/plugin/SonyExtensionService.java | 201 ++++++++++++++++++ .../sony/plugin/SonyPreferenceActivity.java | 130 +++++++++++ .../plugin/SonyRegistrationInformation.java | 132 ++++++++++++ 17 files changed, 731 insertions(+), 83 deletions(-) create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 res/drawable/icn_18x18_black_white_message_notification.png create mode 100644 res/drawable/icn_18x18_message_notification.png create mode 100644 res/drawable/icn_30x30_message_notification.png create mode 100644 res/drawable/icon_extension.png create mode 100644 res/drawable/icon_extension_48.png create mode 100644 src/com/dattasmoon/sony/plugin/SonyExtensionReceiver.java create mode 100644 src/com/dattasmoon/sony/plugin/SonyExtensionService.java create mode 100644 src/com/dattasmoon/sony/plugin/SonyPreferenceActivity.java create mode 100644 src/com/dattasmoon/sony/plugin/SonyRegistrationInformation.java diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..74897e1 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding//src/com/dattasmoon/pebble/plugin/NotificationService.java=UTF-8 diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 44c6765..f70635c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2,18 +2,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 literal 0 HcmV?d00001 diff --git a/res/drawable/icon_extension.png b/res/drawable/icon_extension.png new file mode 100644 index 0000000000000000000000000000000000000000..b6bc4ad4bbbab7d15544547cf6eb78dcf2671811 GIT binary patch literal 4024 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 ZHvo`|)Oxn|_k{oe002ovPDHLkV1m(BRqX%( literal 0 HcmV?d00001 diff --git a/res/values/strings.xml b/res/values/strings.xml index 4e2783c..e9b0be7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -85,4 +85,14 @@ This can\'t be blank Case\nInsensitive + Clear All Events + "All events on device will be cleared, continue?" + preference_key_clear + Settings + All events have been cleared + Failed to clear events + New notification from + Smart Watch Notifier + Settings + Notifier Source \ No newline at end of file diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 7a762d7..64dc70e 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -57,6 +57,16 @@ android:title="@string/pref_dnd_time_after" android:defaultValue="21:00" /> + + + + + + diff --git a/src/com/dattasmoon/pebble/plugin/Constants.java b/src/com/dattasmoon/pebble/plugin/Constants.java index f30b264..8002cb2 100644 --- a/src/com/dattasmoon/pebble/plugin/Constants.java +++ b/src/com/dattasmoon/pebble/plugin/Constants.java @@ -60,6 +60,11 @@ public final class Constants { // Accessibility specific items public static final String ACCESSIBILITY_SERVICE = "com.dattasmoon.pebble.plugin/com.dattasmoon.pebble.plugin.NotificationService"; + // Sony Specific Items + public static final String EXTENSION_SPECIFIC_ID = "COM_DATTASMOON_SONY_PLUGIN_SONY_EXTENSION_ID"; + public static final String EXTENSION_KEY = "com.dattasmoon.sony.plugin.key"; + public static final String INTENT_ACTION_ADD = "com.dattasmoon.sony.plugin.notification"; + public static enum Type { NOTIFICATION, SETTINGS }; diff --git a/src/com/dattasmoon/pebble/plugin/FireReceiver.java b/src/com/dattasmoon/pebble/plugin/FireReceiver.java index 5eab0c0..b0029b0 100644 --- a/src/com/dattasmoon/pebble/plugin/FireReceiver.java +++ b/src/com/dattasmoon/pebble/plugin/FireReceiver.java @@ -31,6 +31,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import com.dattasmoon.pebble.plugin.Constants.Mode; import com.dattasmoon.pebble.plugin.Constants.Type; +import com.dattasmoon.sony.plugin.SonyExtensionService; public class FireReceiver extends BroadcastReceiver { @@ -59,21 +60,23 @@ public void onReceive(final Context context, final Intent intent) { break; } - //handle quiet hours DND + // handle quiet hours DND boolean quiet_hours = sharedPref.getBoolean(Constants.PREFERENCE_QUIET_HOURS, false); - //we only need to pull this if quiet hours are enabled. Save the cycles for the cpu! (haha) - if(quiet_hours){ + // we only need to pull this if quiet hours are enabled. Save + // the cycles for the cpu! (haha) + if (quiet_hours) { String[] pieces = sharedPref.getString(Constants.PREFERENCE_QUIET_HOURS_BEFORE, "00:00").split(":"); - Date quiet_hours_before= new Date(0, 0, 0, Integer.parseInt(pieces[0]), Integer.parseInt(pieces[1])); + Date quiet_hours_before = new Date(0, 0, 0, Integer.parseInt(pieces[0]), + Integer.parseInt(pieces[1])); pieces = sharedPref.getString(Constants.PREFERENCE_QUIET_HOURS_AFTER, "23:59").split(":"); Date quiet_hours_after = new Date(0, 0, 0, Integer.parseInt(pieces[0]), Integer.parseInt(pieces[1])); Calendar c = Calendar.getInstance(); Date now = new Date(0, 0, 0, c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE)); if (Constants.IS_LOGGABLE) { - Log.i(Constants.LOG_TAG, "Checking quiet hours. Now: " + now.toString() + " vs " + - quiet_hours_before.toString() + " and " +quiet_hours_after.toString()); + Log.i(Constants.LOG_TAG, "Checking quiet hours. Now: " + now.toString() + " vs " + + quiet_hours_before.toString() + " and " + quiet_hours_after.toString()); } - if(now.before(quiet_hours_before) || now.after(quiet_hours_after)){ + if (now.before(quiet_hours_before) || now.after(quiet_hours_after)) { if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, "Time is before or after the quiet hours time. Returning."); } @@ -85,6 +88,7 @@ public void onReceive(final Context context, final Intent intent) { String body = intent.getStringExtra(Constants.BUNDLE_EXTRA_STRING_BODY); sendAlertToPebble(context, bundleVersionCode, title, body); + sendAlertToSmartWatch(context, bundleVersionCode, title, body); break; case SETTINGS: Mode mode = Mode.values()[intent.getIntExtra(Constants.BUNDLE_EXTRA_INT_MODE, Mode.OFF.ordinal())]; @@ -96,7 +100,7 @@ public void onReceive(final Context context, final Intent intent) { } } - public void setNotificationSettings(final Context context, int bundleVersionCode, Mode mode,String packageList) { + public void setNotificationSettings(final Context context, int bundleVersionCode, Mode mode, String packageList) { if (Constants.IS_LOGGABLE) { switch (mode) { @@ -115,7 +119,8 @@ public void setNotificationSettings(final Context context, int bundleVersionCode Log.i(Constants.LOG_TAG, "Package list is: " + packageList); } - Editor editor = context.getSharedPreferences(Constants.LOG_TAG+"_preferences", context.MODE_MULTI_PROCESS | context.MODE_PRIVATE).edit(); + Editor editor = context.getSharedPreferences(Constants.LOG_TAG + "_preferences", + context.MODE_MULTI_PROCESS | context.MODE_PRIVATE).edit(); editor.putInt(Constants.PREFERENCE_MODE, mode.ordinal()); editor.putBoolean(Constants.PREFERENCE_TASKER_SET, true); editor.putString(Constants.PREFERENCE_PACKAGE_LIST, packageList); @@ -160,4 +165,21 @@ public void sendAlertToPebble(final Context context, int bundleVersionCode, Stri } context.sendBroadcast(i); } + + public void sendAlertToSmartWatch(final Context context, int bundleVersionCode, String title, String body) { + // Create the intent to house the Pebble notification + final Intent i = new Intent(context, SonyExtensionService.class); + i.setAction(Constants.INTENT_ACTION_ADD); + i.putExtra("sender", context.getString(R.string.app_name)); + i.putExtra("title", title); + i.putExtra("body", body); + + // Send the alert to Pebble + if (Constants.IS_LOGGABLE) { + Log.d(Constants.LOG_TAG, "About to send a modal alert to Smart Watch: " + title + ":" + body); + } + context.startService(i); // // Use startService instead of sendBroadcast + // so the notification gets passed to SW2 + // properly + } } diff --git a/src/com/dattasmoon/pebble/plugin/NotificationService.java b/src/com/dattasmoon/pebble/plugin/NotificationService.java index 4889a74..724a192 100644 --- a/src/com/dattasmoon/pebble/plugin/NotificationService.java +++ b/src/com/dattasmoon/pebble/plugin/NotificationService.java @@ -12,7 +12,12 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -43,6 +48,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import android.widget.TextView; import com.dattasmoon.pebble.plugin.Constants.Mode; +import com.dattasmoon.sony.plugin.SonyExtensionService; public class NotificationService extends AccessibilityService { private class queueItem { @@ -55,24 +61,24 @@ public queueItem(String title, String body) { } } - private Mode mode = Mode.EXCLUDE; - private boolean notifications_only = false; - private boolean no_ongoing_notifs = false; - private boolean notification_extras = false; - private boolean quiet_hours = false; - private boolean notifScreenOn = true; - private JSONArray converts = new JSONArray(); - private JSONArray ignores = new JSONArray(); - private JSONArray pkg_renames = new JSONArray(); - private long min_notification_wait = 0 * 1000; - private long notification_last_sent = 0; - private Date quiet_hours_before = null; - private Date quiet_hours_after = null; - private String[] packages = null; - private Handler mHandler; - private File watchFile; - private Long lastChange; - Queue queue; + private Mode mode = Mode.EXCLUDE; + private boolean notifications_only = false; + private boolean no_ongoing_notifs = false; + private boolean notification_extras = false; + private boolean quiet_hours = false; + private boolean notifScreenOn = true; + private JSONArray converts = new JSONArray(); + private JSONArray ignores = new JSONArray(); + private JSONArray pkg_renames = new JSONArray(); + private long min_notification_wait = 0 * 1000; + private long notification_last_sent = 0; + private Date quiet_hours_before = null; + private Date quiet_hours_after = null; + private String[] packages = null; + private Handler mHandler; + private File watchFile; + private Long lastChange; + Queue queue; @Override public void onAccessibilityEvent(AccessibilityEvent event) { @@ -92,25 +98,26 @@ public void onAccessibilityEvent(AccessibilityEvent event) { return; } - //handle quiet hours - if(quiet_hours){ + // handle quiet hours + if (quiet_hours) { Calendar c = Calendar.getInstance(); Date now = new Date(0, 0, 0, c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE)); if (Constants.IS_LOGGABLE) { - Log.i(Constants.LOG_TAG, "Checking quiet hours. Now: " + now.toString() + " vs " + - quiet_hours_before.toString() + " and " +quiet_hours_after.toString()); + Log.i(Constants.LOG_TAG, + "Checking quiet hours. Now: " + now.toString() + " vs " + quiet_hours_before.toString() + + " and " + quiet_hours_after.toString()); } - if(quiet_hours_before.after(quiet_hours_after)){ - if(now.after(quiet_hours_after) && now.before(quiet_hours_before)){ + if (quiet_hours_before.after(quiet_hours_after)) { + if (now.after(quiet_hours_after) && now.before(quiet_hours_before)) { if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, "Time is during quiet time. Returning."); } return; } - } else if(now.before(quiet_hours_before) || now.after(quiet_hours_after)){ + } else if (now.before(quiet_hours_before) || now.after(quiet_hours_after)) { if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, "Time is before or after the quiet hours time. Returning."); } @@ -133,11 +140,11 @@ public void onAccessibilityEvent(AccessibilityEvent event) { } } } - if (no_ongoing_notifs){ + if (no_ongoing_notifs) { Parcelable parcelable = event.getParcelableData(); if (parcelable instanceof Notification) { Notification notif = (Notification) parcelable; - if ((notif.flags & Notification.FLAG_ONGOING_EVENT) == Notification.FLAG_ONGOING_EVENT){ + if ((notif.flags & Notification.FLAG_ONGOING_EVENT) == Notification.FLAG_ONGOING_EVENT) { if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, "Event is a notification, notification flag contains ongoing, and no ongoing notification is true. Returning."); @@ -146,13 +153,11 @@ public void onAccessibilityEvent(AccessibilityEvent event) { } } else { if (Constants.IS_LOGGABLE) { - Log.i(Constants.LOG_TAG, - "Event is not a notification."); + Log.i(Constants.LOG_TAG, "Event is not a notification."); } } } - // Handle the do not disturb screen on settings PowerManager powMan = (PowerManager) this.getSystemService(Context.POWER_SERVICE); if (Constants.IS_LOGGABLE) { @@ -177,7 +182,7 @@ public void onAccessibilityEvent(AccessibilityEvent event) { PackageManager pm = getPackageManager(); String eventPackageName; - if (event.getPackageName() != null){ + if (event.getPackageName() != null) { eventPackageName = event.getPackageName().toString(); } else { eventPackageName = ""; @@ -230,13 +235,13 @@ public void onAccessibilityEvent(AccessibilityEvent event) { String title = ""; try { boolean renamed = false; - for(int i = 0; i < pkg_renames.length(); i++){ - if(pkg_renames.getJSONObject(i).getString("pkg").equalsIgnoreCase(eventPackageName)){ + for (int i = 0; i < pkg_renames.length(); i++) { + if (pkg_renames.getJSONObject(i).getString("pkg").equalsIgnoreCase(eventPackageName)) { renamed = true; title = pkg_renames.getJSONObject(i).getString("to"); } } - if(!renamed){ + if (!renamed) { title = pm.getApplicationLabel(pm.getApplicationInfo(eventPackageName, 0)).toString(); } } catch (NameNotFoundException e) { @@ -266,52 +271,55 @@ public void onAccessibilityEvent(AccessibilityEvent event) { } // Check ignore lists - for(int i = 0; i < ignores.length(); i++){ - try{ + for (int i = 0; i < ignores.length(); i++) { + try { JSONObject ignore = ignores.getJSONObject(i); String app = ignore.getString("app"); boolean exclude = ignore.optBoolean("exclude", true); boolean case_insensitive = ignore.optBoolean("insensitive", true); - if((!app.equals("-1")) && (!eventPackageName.equalsIgnoreCase(app))){ - //this rule doesn't apply to all apps and this isn't the app we're looking for. + if ((!app.equals("-1")) && (!eventPackageName.equalsIgnoreCase(app))) { + // this rule doesn't apply to all apps and this isn't the + // app we're looking for. continue; } String regex = ""; - if(case_insensitive){ + if (case_insensitive) { regex += "(?i)"; } - if(!ignore.getBoolean("raw")){ + if (!ignore.getBoolean("raw")) { regex += Pattern.quote(ignore.getString("match")); } else { regex += ignore.getString("match"); } Pattern p = Pattern.compile(regex); Matcher m = p.matcher(notificationText); - if(m.find()){ - if(exclude){ + if (m.find()) { + if (exclude) { if (Constants.IS_LOGGABLE) { - Log.i(Constants.LOG_TAG, "Notification text of '" + notificationText + "' matches: '" + regex +"' and exclude is on. Returning"); + Log.i(Constants.LOG_TAG, "Notification text of '" + notificationText + "' matches: '" + + regex + "' and exclude is on. Returning"); } return; } } else { - if(!exclude){ - if(Constants.IS_LOGGABLE){ - Log.i(Constants.LOG_TAG, "Notification text of '" + notificationText + "' does not match: '" + regex +"' and include is on. Returning"); + if (!exclude) { + if (Constants.IS_LOGGABLE) { + Log.i(Constants.LOG_TAG, "Notification text of '" + notificationText + + "' does not match: '" + regex + "' and include is on. Returning"); } return; } } - } catch (JSONException e){ + } catch (JSONException e) { continue; } } - // Send the alert to Pebble sendToPebble(title, notificationText); + sendToSmartWatch(title, notificationText); if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, event.toString()); @@ -328,18 +336,19 @@ private void sendToPebble(String title, String notificationText) { } return; } - for(int i = 0; i < converts.length(); i++){ + for (int i = 0; i < converts.length(); i++) { String from; String to; - try{ + try { JSONObject convert = converts.getJSONObject(i); from = "(?i)" + Pattern.quote(convert.getString("from")); to = convert.getString("to"); - } catch (JSONException e){ + } catch (JSONException e) { continue; } - //not sure if the title should be replaced as well or not. I'm guessing not - //title = title.replaceAll(from, to); + // not sure if the title should be replaced as well or not. I'm + // guessing not + // title = title.replaceAll(from, to); notificationText = notificationText.replaceAll(from, to); } @@ -367,6 +376,48 @@ private void sendToPebble(String title, String notificationText) { } + private void sendToSmartWatch(String title, String notificationText) { + title = title.trim(); + notificationText = notificationText.trim(); + if (title.trim().isEmpty() || notificationText.isEmpty()) { + if (Constants.IS_LOGGABLE) { + Log.i(Constants.LOG_TAG, "Detected empty title or notification text, skipping"); + } + return; + } + for (int i = 0; i < converts.length(); i++) { + String from; + String to; + try { + JSONObject convert = converts.getJSONObject(i); + from = "(?i)" + Pattern.quote(convert.getString("from")); + to = convert.getString("to"); + } catch (JSONException e) { + continue; + } + // not sure if the title should be replaced as well or not. I'm + // guessing not + // title = title.replaceAll(from, to); + notificationText = notificationText.replaceAll(from, to); + } + + // Create the intent to house the Pebble notification + final Intent i = new Intent(this, SonyExtensionService.class); + i.setAction(Constants.INTENT_ACTION_ADD); + i.putExtra("sender", getString(R.string.app_name)); + i.putExtra("title", title); + i.putExtra("body", notificationText); + + // Send the alert to Pebble + if (Constants.IS_LOGGABLE) { + Log.d(Constants.LOG_TAG, "About to send a modal alert to Smart Watch: " + title + ":" + notificationText); + } + startService(i); // Use startService instead of sendBroadcast so the + // notification gets passed to SW2 properly + notification_last_sent = System.currentTimeMillis(); + + } + @Override public void onInterrupt() { @@ -405,16 +456,20 @@ private void loadPrefs() { SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences sharedPreferences = getSharedPreferences(Constants.LOG_TAG, MODE_MULTI_PROCESS | MODE_PRIVATE); - //if old preferences exist, convert them. - if(sharedPreferences.contains(Constants.LOG_TAG + ".mode")){ + // if old preferences exist, convert them. + if (sharedPreferences.contains(Constants.LOG_TAG + ".mode")) { SharedPreferences.Editor editor = sharedPref.edit(); - editor.putInt(Constants.PREFERENCE_MODE, sharedPreferences.getInt(Constants.LOG_TAG + ".mode", Constants.Mode.OFF.ordinal())); - editor.putString(Constants.PREFERENCE_PACKAGE_LIST, sharedPreferences.getString(Constants.LOG_TAG + ".packageList", "")); - editor.putBoolean(Constants.PREFERENCE_NOTIFICATIONS_ONLY, sharedPreferences.getBoolean(Constants.LOG_TAG + ".notificationsOnly", true)); - editor.putBoolean(Constants.PREFERENCE_NOTIFICATION_EXTRA, sharedPreferences.getBoolean(Constants.LOG_TAG + ".fetchNotificationExtras", false)); + editor.putInt(Constants.PREFERENCE_MODE, + sharedPreferences.getInt(Constants.LOG_TAG + ".mode", Constants.Mode.OFF.ordinal())); + editor.putString(Constants.PREFERENCE_PACKAGE_LIST, + sharedPreferences.getString(Constants.LOG_TAG + ".packageList", "")); + editor.putBoolean(Constants.PREFERENCE_NOTIFICATIONS_ONLY, + sharedPreferences.getBoolean(Constants.LOG_TAG + ".notificationsOnly", true)); + editor.putBoolean(Constants.PREFERENCE_NOTIFICATION_EXTRA, + sharedPreferences.getBoolean(Constants.LOG_TAG + ".fetchNotificationExtras", false)); editor.commit(); - //clear out all old preferences + // clear out all old preferences editor = sharedPreferences.edit(); editor.clear(); editor.commit(); @@ -438,25 +493,26 @@ private void loadPrefs() { notification_extras = sharedPref.getBoolean(Constants.PREFERENCE_NOTIFICATION_EXTRA, false); notifScreenOn = sharedPref.getBoolean(Constants.PREFERENCE_NOTIF_SCREEN_ON, true); quiet_hours = sharedPref.getBoolean(Constants.PREFERENCE_QUIET_HOURS, false); - try{ + try { converts = new JSONArray(sharedPref.getString(Constants.PREFERENCE_CONVERTS, "[]")); - } catch (JSONException e){ + } catch (JSONException e) { converts = new JSONArray(); } - try{ + try { ignores = new JSONArray(sharedPref.getString(Constants.PREFERENCE_IGNORE, "[]")); - } catch (JSONException e){ + } catch (JSONException e) { ignores = new JSONArray(); } - try{ + try { pkg_renames = new JSONArray(sharedPref.getString(Constants.PREFERENCE_PKG_RENAMES, "[]")); - } catch (JSONException e){ + } catch (JSONException e) { pkg_renames = new JSONArray(); } - //we only need to pull this if quiet hours are enabled. Save the cycles for the cpu! (haha) - if(quiet_hours){ + // we only need to pull this if quiet hours are enabled. Save the cycles + // for the cpu! (haha) + if (quiet_hours) { String[] pieces = sharedPref.getString(Constants.PREFERENCE_QUIET_HOURS_BEFORE, "00:00").split(":"); - quiet_hours_before= new Date(0, 0, 0, Integer.parseInt(pieces[0]), Integer.parseInt(pieces[1])); + quiet_hours_before = new Date(0, 0, 0, Integer.parseInt(pieces[0]), Integer.parseInt(pieces[1])); pieces = sharedPref.getString(Constants.PREFERENCE_QUIET_HOURS_AFTER, "23:59").split(":"); quiet_hours_after = new Date(0, 0, 0, Integer.parseInt(pieces[0]), Integer.parseInt(pieces[1])); } @@ -541,7 +597,7 @@ private String dumpViewGroup(int depth, ViewGroup vg, String existing_text) { if (v instanceof TextView) { TextView tv = (TextView) v; - if (tv.getText().toString() == "..." || tv.getText().toString() == "�" + if (tv.getText().toString() == "..." || tv.getText().toString() == "���" || isInteger(tv.getText().toString()) || tv.getText().toString().trim().equalsIgnoreCase(existing_text)) { if (Constants.IS_LOGGABLE) { diff --git a/src/com/dattasmoon/sony/plugin/SonyExtensionReceiver.java b/src/com/dattasmoon/sony/plugin/SonyExtensionReceiver.java new file mode 100644 index 0000000..8039ebf --- /dev/null +++ b/src/com/dattasmoon/sony/plugin/SonyExtensionReceiver.java @@ -0,0 +1,31 @@ +/* +Copyright (c) 2013 Dattas Moonchaser + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.dattasmoon.sony.plugin; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import com.dattasmoon.pebble.plugin.Constants; + +/** + * The extension receiver receives the extension intents and starts the + * extension service when it arrives. + */ +public class SonyExtensionReceiver extends BroadcastReceiver { + + @Override + public void onReceive(final Context context, final Intent intent) { + Log.d(Constants.LOG_TAG, "onReceive: " + intent.getAction()); + intent.setClass(context, SonyExtensionService.class); + context.startService(intent); + } +} diff --git a/src/com/dattasmoon/sony/plugin/SonyExtensionService.java b/src/com/dattasmoon/sony/plugin/SonyExtensionService.java new file mode 100644 index 0000000..f4a639d --- /dev/null +++ b/src/com/dattasmoon/sony/plugin/SonyExtensionService.java @@ -0,0 +1,201 @@ +/* +Copyright (c) 2013 Dattas Moonchaser + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.dattasmoon.sony.plugin; + +import android.content.ContentValues; +import android.content.Intent; +import android.database.SQLException; +import android.os.Bundle; +import android.util.Log; + +import com.dattasmoon.pebble.plugin.Constants; +import com.sonyericsson.extras.liveware.aef.notification.Notification; +import com.sonyericsson.extras.liveware.extension.util.ExtensionService; +import com.sonyericsson.extras.liveware.extension.util.notification.NotificationUtil; +import com.sonyericsson.extras.liveware.extension.util.registration.RegistrationInformation; + +/** + * The sample extension service handles extension registration and inserts data + * into the notification database. + */ +public class SonyExtensionService extends ExtensionService { + + public SonyExtensionService() { + super(Constants.EXTENSION_KEY); + } + + /** + * {@inheritDoc} + * + * @see android.app.Service#onCreate() + */ + @Override + public void onCreate() { + super.onCreate(); + Log.d(Constants.LOG_TAG, "onCreate"); + } + + /** + * {@inheritDoc} + * + * @see android.app.Service#onStartCommand() + */ + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + int retVal = super.onStartCommand(intent, flags, startId); + if (intent != null && Constants.INTENT_ACTION_ADD.equals(intent.getAction())) { + Log.d(Constants.LOG_TAG, "onStart action: INTENT_ACTION_ADD"); + Bundle extras = intent.getExtras(); + addData((String) extras.get("title"), (String) extras.get("body")); + stopSelfCheck(); + } + + return retVal; + } + + /** + * {@inheritDoc} + * + * @see android.app.Service#onDestroy() + */ + @Override + public void onDestroy() { + super.onDestroy(); + Log.d(Constants.LOG_TAG, "onDestroy"); + } + + /** + * Add some "random" data + */ + private void addData(String name, String message) { + long time = System.currentTimeMillis(); + long sourceId = NotificationUtil.getSourceId(this, Constants.EXTENSION_SPECIFIC_ID); + if (sourceId == NotificationUtil.INVALID_ID) { + Log.e(Constants.LOG_TAG, "Failed to insert data"); + return; + } + ContentValues eventValues = new ContentValues(); + eventValues.put(Notification.EventColumns.EVENT_READ_STATUS, false); + eventValues.put(Notification.EventColumns.DISPLAY_NAME, name); + eventValues.put(Notification.EventColumns.MESSAGE, message); + eventValues.put(Notification.EventColumns.PERSONAL, 1); + eventValues.put(Notification.EventColumns.PUBLISHED_TIME, time); + eventValues.put(Notification.EventColumns.SOURCE_ID, sourceId); + + try { + getContentResolver().insert(Notification.Event.URI, eventValues); + } catch (IllegalArgumentException e) { + Log.e(Constants.LOG_TAG, "Failed to insert event", e); + } catch (SecurityException e) { + Log.e(Constants.LOG_TAG, "Failed to insert event, is Live Ware Manager installed?", e); + } catch (SQLException e) { + Log.e(Constants.LOG_TAG, "Failed to insert event", e); + } + } + + @Override + protected void onViewEvent(Intent intent) { + // String action = + // intent.getStringExtra(Notification.Intents.EXTRA_ACTION); + // String hostAppPackageName = intent + // .getStringExtra(Registration.Intents.EXTRA_AHA_PACKAGE_NAME); + // boolean advancedFeaturesSupported = + // DeviceInfoHelper.isSmartWatch2ApiAndScreenDetected( + // this, hostAppPackageName); + // + // int eventId = intent.getIntExtra(Notification.Intents.EXTRA_EVENT_ID, + // -1); + // if (Notification.SourceColumns.ACTION_1.equals(action)) { + // doAction1(eventId); + // } else if (Notification.SourceColumns.ACTION_2.equals(action)) { + // // Here we can take different actions depending on the device. + // if (advancedFeaturesSupported) { + // Toast.makeText(this, "Action 2 API level 2", + // Toast.LENGTH_LONG).show(); + // } else { + // Toast.makeText(this, "Action 2", Toast.LENGTH_LONG).show(); + // } + // } else if (Notification.SourceColumns.ACTION_3.equals(action)) { + // Toast.makeText(this, "Action 3", Toast.LENGTH_LONG).show(); + // } + } + + @Override + protected void onRefreshRequest() { + // Do nothing here, only relevant for polling extensions, this + // extension is always up to date + } + + // /** + // * Show toast with event information + // * + // * @param eventId The event id + // */ + // public void doAction1(int eventId) { + // Log.d(LOG_TAG, "doAction1 event id: " + eventId); + // Cursor cursor = null; + // try { + // String name = ""; + // String message = ""; + // cursor = getContentResolver().query(Notification.Event.URI, null, + // Notification.EventColumns._ID + " = " + eventId, null, null); + // if (cursor != null && cursor.moveToFirst()) { + // int nameIndex = + // cursor.getColumnIndex(Notification.EventColumns.DISPLAY_NAME); + // int messageIndex = + // cursor.getColumnIndex(Notification.EventColumns.MESSAGE); + // name = cursor.getString(nameIndex); + // message = cursor.getString(messageIndex); + // } + // + // String toastMessage = getText(R.string.action_event_1) + ", Event: " + + // eventId + // + ", Name: " + name + ", Message: " + message; + // Toast.makeText(this, toastMessage, Toast.LENGTH_LONG).show(); + // } catch (SQLException e) { + // Log.e(LOG_TAG, "Failed to query event", e); + // } catch (SecurityException e) { + // Log.e(LOG_TAG, "Failed to query event", e); + // } catch (IllegalArgumentException e) { + // Log.e(LOG_TAG, "Failed to query event", e); + // } finally { + // if (cursor != null) { + // cursor.close(); + // } + // } + // } + + /** + * Called when extension and sources has been successfully registered. + * Override this method to take action after a successful registration. + */ + @Override + public void onRegisterResult(boolean result) { + super.onRegisterResult(result); + Log.d(Constants.LOG_TAG, "onRegisterResult"); + } + + @Override + protected RegistrationInformation getRegistrationInformation() { + return new SonyRegistrationInformation(this); + } + + /* + * (non-Javadoc) + * + * @see com.sonyericsson.extras.liveware.aef.util.ExtensionService# + * keepRunningWhenConnected() + */ + @Override + protected boolean keepRunningWhenConnected() { + return false; + } +} diff --git a/src/com/dattasmoon/sony/plugin/SonyPreferenceActivity.java b/src/com/dattasmoon/sony/plugin/SonyPreferenceActivity.java new file mode 100644 index 0000000..50e337a --- /dev/null +++ b/src/com/dattasmoon/sony/plugin/SonyPreferenceActivity.java @@ -0,0 +1,130 @@ +/* +Copyright (c) 2013 Dattas Moonchaser + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.dattasmoon.sony.plugin; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.AsyncTask; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; +import android.preference.PreferenceActivity; +import android.util.Log; +import android.widget.Toast; + +import com.dattasmoon.pebble.plugin.Constants; +import com.dattasmoon.pebble.plugin.R; +import com.sonyericsson.extras.liveware.extension.util.ExtensionUtils; +import com.sonyericsson.extras.liveware.extension.util.notification.NotificationUtil; + +/** + * The sample preference activity lets the user toggle start/stop of periodic + * data insertion. It also allows the user to clear all events associated with + * this extension. + */ +public class SonyPreferenceActivity extends PreferenceActivity { + + private static final int DIALOG_READ_ME = 1; + + private static final int DIALOG_CLEAR = 2; + + @SuppressWarnings("deprecation") + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.preferences); + + // Handle clear all events + Preference preference = findPreference(getString(R.string.pref_key_clear)); + preference.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + showDialog(DIALOG_CLEAR); + return true; + } + }); + + // Remove preferences that are not supported by the accessory + if (!ExtensionUtils.supportsHistory(getIntent())) { + preference = findPreference(getString(R.string.pref_key_clear)); + getPreferenceScreen().removePreference(preference); + } + } + + @Override + protected Dialog onCreateDialog(int id) { + Dialog dialog = null; + + switch (id) { + case DIALOG_CLEAR: + dialog = createClearDialog(); + break; + default: + Log.w(Constants.LOG_TAG, "Not a valid dialog id: " + id); + break; + } + + return dialog; + } + + /** + * Create the Clear events dialog + * + * @return the Dialog + */ + private Dialog createClearDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.pref_option_clear_txt).setTitle(R.string.pref_option_clear) + .setIcon(android.R.drawable.ic_input_delete) + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + new ClearEventsTask().execute(); + } + }).setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + return builder.create(); + } + + /** + * Clear all messaging events + */ + private class ClearEventsTask extends AsyncTask { + + @Override + protected void onPreExecute() { + } + + @Override + protected Integer doInBackground(Void... params) { + int nbrDeleted = 0; + nbrDeleted = NotificationUtil.deleteAllEvents(SonyPreferenceActivity.this); + return nbrDeleted; + } + + @Override + protected void onPostExecute(Integer id) { + if (id != NotificationUtil.INVALID_ID) { + Toast.makeText(SonyPreferenceActivity.this, R.string.clear_success, Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(SonyPreferenceActivity.this, R.string.clear_failure, Toast.LENGTH_SHORT).show(); + } + } + + } +} diff --git a/src/com/dattasmoon/sony/plugin/SonyRegistrationInformation.java b/src/com/dattasmoon/sony/plugin/SonyRegistrationInformation.java new file mode 100644 index 0000000..d3e6b3b --- /dev/null +++ b/src/com/dattasmoon/sony/plugin/SonyRegistrationInformation.java @@ -0,0 +1,132 @@ +/* +Copyright (c) 2013 Dattas Moonchaser + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.dattasmoon.sony.plugin; + +import java.util.ArrayList; +import java.util.List; + +import android.content.ContentValues; +import android.content.Context; + +import com.dattasmoon.pebble.plugin.Constants; +import com.dattasmoon.pebble.plugin.R; +import com.sonyericsson.extras.liveware.aef.notification.Notification; +import com.sonyericsson.extras.liveware.aef.registration.Registration; +import com.sonyericsson.extras.liveware.extension.util.ExtensionUtils; +import com.sonyericsson.extras.liveware.extension.util.registration.RegistrationInformation; + +public class SonyRegistrationInformation extends RegistrationInformation { + + final Context mContext; + + /** + * Create notification registration object + * + * @param context + * The context + */ + protected SonyRegistrationInformation(Context context) { + if (context == null) { + throw new IllegalArgumentException("context == null"); + } + mContext = context; + } + + @Override + public int getRequiredNotificationApiVersion() { + return 1; + } + + @Override + public int getRequiredWidgetApiVersion() { + return 0; + } + + @Override + public int getRequiredControlApiVersion() { + return 0; + } + + @Override + public int getRequiredSensorApiVersion() { + return 0; + } + + @Override + public ContentValues getExtensionRegistrationConfiguration() { + String extensionIcon = ExtensionUtils.getUriString(mContext, R.drawable.icon_extension); + String iconHostapp = ExtensionUtils.getUriString(mContext, R.drawable.ic_launcher); + String extensionIcon48 = ExtensionUtils.getUriString(mContext, R.drawable.icon_extension_48); + + String configurationText = mContext.getString(R.string.configuration_text); + String extensionName = mContext.getString(R.string.extension_name); + + ContentValues values = new ContentValues(); + values.put(Registration.ExtensionColumns.CONFIGURATION_ACTIVITY, SonyPreferenceActivity.class.getName()); + values.put(Registration.ExtensionColumns.CONFIGURATION_TEXT, configurationText); + values.put(Registration.ExtensionColumns.EXTENSION_ICON_URI, extensionIcon); + values.put(Registration.ExtensionColumns.EXTENSION_48PX_ICON_URI, extensionIcon48); + + values.put(Registration.ExtensionColumns.EXTENSION_KEY, Constants.EXTENSION_KEY); + values.put(Registration.ExtensionColumns.HOST_APP_ICON_URI, iconHostapp); + values.put(Registration.ExtensionColumns.NAME, extensionName); + values.put(Registration.ExtensionColumns.NOTIFICATION_API_VERSION, getRequiredNotificationApiVersion()); + values.put(Registration.ExtensionColumns.PACKAGE_NAME, mContext.getPackageName()); + + return values; + } + + @Override + public ContentValues[] getSourceRegistrationConfigurations() { + List bulkValues = new ArrayList(); + bulkValues.add(getSourceRegistrationConfiguration(Constants.EXTENSION_SPECIFIC_ID)); + return bulkValues.toArray(new ContentValues[bulkValues.size()]); + } + + /** + * Get source configuration associated with extensions specific id + * + * @param extensionSpecificId + * @return The source configuration + */ + public ContentValues getSourceRegistrationConfiguration(String extensionSpecificId) { + ContentValues sourceValues = null; + + String iconSource1 = ExtensionUtils.getUriString(mContext, R.drawable.icn_30x30_message_notification); + String iconSource2 = ExtensionUtils.getUriString(mContext, R.drawable.icn_18x18_message_notification); + String iconBw = ExtensionUtils.getUriString(mContext, R.drawable.icn_18x18_black_white_message_notification); + String textToSpeech = mContext.getString(R.string.text_to_speech); + sourceValues = new ContentValues(); + sourceValues.put(Notification.SourceColumns.ENABLED, true); + sourceValues.put(Notification.SourceColumns.ICON_URI_1, iconSource1); + sourceValues.put(Notification.SourceColumns.ICON_URI_2, iconSource2); + sourceValues.put(Notification.SourceColumns.ICON_URI_BLACK_WHITE, iconBw); + sourceValues.put(Notification.SourceColumns.UPDATE_TIME, System.currentTimeMillis()); + sourceValues.put(Notification.SourceColumns.NAME, mContext.getString(R.string.source_name)); + sourceValues.put(Notification.SourceColumns.EXTENSION_SPECIFIC_ID, extensionSpecificId); + sourceValues.put(Notification.SourceColumns.PACKAGE_NAME, mContext.getPackageName()); + sourceValues.put(Notification.SourceColumns.TEXT_TO_SPEECH, textToSpeech); + // sourceValues.put(Notification.SourceColumns.ACTION_1, + // mContext.getString(R.string.action_event_1)); + // sourceValues.put(Notification.SourceColumns.ACTION_2, + // mContext.getString(R.string.action_event_2)); + // sourceValues.put(Notification.SourceColumns.ACTION_3, + // mContext.getString(R.string.action_event_3)); + // sourceValues.put(Notification.SourceColumns.ACTION_ICON_1, + // ExtensionUtils.getUriString(mContext, R.drawable.actions_1)); + // sourceValues.put(Notification.SourceColumns.ACTION_ICON_2, + // ExtensionUtils.getUriString(mContext, R.drawable.actions_2)); + // sourceValues.put(Notification.SourceColumns.ACTION_ICON_3, + // ExtensionUtils.getUriString(mContext, R.drawable.actions_3)); + return sourceValues; + } + +} From 75139d03fbecff399caca363ac13842c187e1d74 Mon Sep 17 00:00:00 2001 From: Mike C Date: Wed, 4 Dec 2013 16:14:25 -0500 Subject: [PATCH 2/7] Refactored Sony preferences to force users to launch the app for configuration --- project.properties | 6 +- res/values/strings.xml | 4 +- res/xml/sony_preferences.xml | 11 ++ .../dattasmoon/pebble/plugin/Constants.java | 1 + .../pebble/plugin/SettingsActivity.java | 121 ++++++++++++++++-- .../sony/plugin/SonyPreferenceActivity.java | 37 ++++-- .../plugin/SonyRegistrationInformation.java | 2 +- 7 files changed, 150 insertions(+), 32 deletions(-) create mode 100644 res/xml/sony_preferences.xml diff --git a/project.properties b/project.properties index 4dab79b..1814817 100644 --- a/project.properties +++ b/project.properties @@ -11,6 +11,6 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=Sony:Sony Add-on SDK 2.1:16 -android.library.reference.1=../../locale-api -android.library.reference.2=../SmartExtensionUtils +target=android-17 +android.library.reference.1=..\\locale-api +android.library.reference.2=../workspace_android/SmartExtensionUtils diff --git a/res/values/strings.xml b/res/values/strings.xml index e9b0be7..825a704 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -87,12 +87,14 @@ Clear All Events "All events on device will be cleared, continue?" + Launch Configuration App + Select which notifications to show and other notification options preference_key_clear + preference_key_launch_app Settings All events have been cleared Failed to clear events New notification from Smart Watch Notifier - Settings Notifier Source \ No newline at end of file diff --git a/res/xml/sony_preferences.xml b/res/xml/sony_preferences.xml new file mode 100644 index 0000000..a81f591 --- /dev/null +++ b/res/xml/sony_preferences.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/src/com/dattasmoon/pebble/plugin/Constants.java b/src/com/dattasmoon/pebble/plugin/Constants.java index 8002cb2..27ca013 100644 --- a/src/com/dattasmoon/pebble/plugin/Constants.java +++ b/src/com/dattasmoon/pebble/plugin/Constants.java @@ -64,6 +64,7 @@ public final class Constants { public static final String EXTENSION_SPECIFIC_ID = "COM_DATTASMOON_SONY_PLUGIN_SONY_EXTENSION_ID"; public static final String EXTENSION_KEY = "com.dattasmoon.sony.plugin.key"; public static final String INTENT_ACTION_ADD = "com.dattasmoon.sony.plugin.notification"; + public static final int DIALOG_CLEAR = 2; public static enum Type { NOTIFICATION, SETTINGS diff --git a/src/com/dattasmoon/pebble/plugin/SettingsActivity.java b/src/com/dattasmoon/pebble/plugin/SettingsActivity.java index 17ff2f8..c06826f 100644 --- a/src/com/dattasmoon/pebble/plugin/SettingsActivity.java +++ b/src/com/dattasmoon/pebble/plugin/SettingsActivity.java @@ -21,22 +21,30 @@ of this software and associated documentation files (the "Software"), to deal */ package com.dattasmoon.pebble.plugin; +import java.io.File; +import java.io.IOException; + +import android.app.AlertDialog; import android.app.Dialog; +import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceActivity; import android.preference.PreferenceCategory; +import android.util.Log; import android.view.View; import android.view.Window; import android.widget.Toast; -import java.io.File; -import java.io.IOException; +import com.sonyericsson.extras.liveware.extension.util.ExtensionUtils; +import com.sonyericsson.extras.liveware.extension.util.notification.NotificationUtil; /** * This activity handles any logic for the settings screen (of which there is\ @@ -55,17 +63,22 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SharedPreferences sharedPreferences = getSharedPreferences(Constants.LOG_TAG, MODE_MULTI_PROCESS | MODE_PRIVATE); - //if old preferences exist, convert them. - if(sharedPreferences.contains(Constants.LOG_TAG + ".mode")){ - SharedPreferences sharedPref = getSharedPreferences(Constants.LOG_TAG + "_preferences", MODE_MULTI_PROCESS | MODE_PRIVATE); + // if old preferences exist, convert them. + if (sharedPreferences.contains(Constants.LOG_TAG + ".mode")) { + SharedPreferences sharedPref = getSharedPreferences(Constants.LOG_TAG + "_preferences", MODE_MULTI_PROCESS + | MODE_PRIVATE); SharedPreferences.Editor editor = sharedPref.edit(); - editor.putInt(Constants.PREFERENCE_MODE, sharedPreferences.getInt(Constants.LOG_TAG + ".mode", Constants.Mode.OFF.ordinal())); - editor.putString(Constants.PREFERENCE_PACKAGE_LIST, sharedPreferences.getString(Constants.LOG_TAG + ".packageList", "")); - editor.putBoolean(Constants.PREFERENCE_NOTIFICATIONS_ONLY, sharedPreferences.getBoolean(Constants.LOG_TAG + ".notificationsOnly", true)); - editor.putBoolean(Constants.PREFERENCE_NOTIFICATION_EXTRA, sharedPreferences.getBoolean(Constants.LOG_TAG + ".fetchNotificationExtras", false)); + editor.putInt(Constants.PREFERENCE_MODE, + sharedPreferences.getInt(Constants.LOG_TAG + ".mode", Constants.Mode.OFF.ordinal())); + editor.putString(Constants.PREFERENCE_PACKAGE_LIST, + sharedPreferences.getString(Constants.LOG_TAG + ".packageList", "")); + editor.putBoolean(Constants.PREFERENCE_NOTIFICATIONS_ONLY, + sharedPreferences.getBoolean(Constants.LOG_TAG + ".notificationsOnly", true)); + editor.putBoolean(Constants.PREFERENCE_NOTIFICATION_EXTRA, + sharedPreferences.getBoolean(Constants.LOG_TAG + ".fetchNotificationExtras", false)); editor.commit(); - //clear out all old preferences + // clear out all old preferences editor = sharedPreferences.edit(); editor.clear(); editor.commit(); @@ -89,7 +102,7 @@ protected void onCreate(Bundle savedInstanceState) { @Override public boolean onPreferenceClick(Preference preference) { pref_version_clicks++; - if(pref_version_clicks > 5){ + if (pref_version_clicks > 5) { final Dialog easterDialog = new Dialog(SettingsActivity.this); easterDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE); easterDialog.setContentView(getLayoutInflater().inflate(R.layout.dialog_easter_hidden, null)); @@ -104,14 +117,14 @@ public void onClick(View v) { } return true; - } }); Preference pref_donate = findPreference("pref_donate"); pref_donate.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override public boolean onPreferenceClick(Preference preference) { - //send intent + // send intent Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse(Constants.DONATION_URL)); startActivity(i); @@ -119,11 +132,25 @@ public boolean onPreferenceClick(Preference preference) { } }); + // Handle clear all events + Preference preference = findPreference(getString(R.string.pref_key_clear)); + preference.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + showDialog(Constants.DIALOG_CLEAR); + return true; + } + }); + // Remove preferences that are not supported by the accessory + if (!ExtensionUtils.supportsHistory(getIntent())) { + preference = findPreference(getString(R.string.pref_key_clear)); + getPreferenceScreen().removePreference(preference); + } } @Override - protected void onPause(){ + protected void onPause() { File watchFile = new File(getFilesDir() + "PrefsChanged.none"); if (!watchFile.exists()) { try { @@ -137,4 +164,70 @@ protected void onPause(){ super.onPause(); } + @Override + protected Dialog onCreateDialog(int id) { + Dialog dialog = null; + + switch (id) { + case Constants.DIALOG_CLEAR: + dialog = createClearDialog(); + break; + default: + Log.w(Constants.LOG_TAG, "Not a valid dialog id: " + id); + break; + } + + return dialog; + } + + /** + * Create the Clear events dialog + * + * @return the Dialog + */ + private Dialog createClearDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.pref_option_clear_txt).setTitle(R.string.pref_option_clear) + .setIcon(android.R.drawable.ic_input_delete) + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + new ClearEventsTask().execute(); + } + }).setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + return builder.create(); + } + + /** + * Clear all messaging events + */ + private class ClearEventsTask extends AsyncTask { + + @Override + protected void onPreExecute() { + } + + @Override + protected Integer doInBackground(Void... params) { + int nbrDeleted = 0; + nbrDeleted = NotificationUtil.deleteAllEvents(SettingsActivity.this); + return nbrDeleted; + } + + @Override + protected void onPostExecute(Integer id) { + if (id != NotificationUtil.INVALID_ID) { + Toast.makeText(SettingsActivity.this, R.string.clear_success, Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(SettingsActivity.this, R.string.clear_failure, Toast.LENGTH_SHORT).show(); + } + } + + } + } diff --git a/src/com/dattasmoon/sony/plugin/SonyPreferenceActivity.java b/src/com/dattasmoon/sony/plugin/SonyPreferenceActivity.java index 50e337a..280ab2a 100644 --- a/src/com/dattasmoon/sony/plugin/SonyPreferenceActivity.java +++ b/src/com/dattasmoon/sony/plugin/SonyPreferenceActivity.java @@ -13,11 +13,13 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; +import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceActivity; +import android.preference.PreferenceCategory; import android.util.Log; import android.widget.Toast; @@ -27,30 +29,39 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import com.sonyericsson.extras.liveware.extension.util.notification.NotificationUtil; /** - * The sample preference activity lets the user toggle start/stop of periodic - * data insertion. It also allows the user to clear all events associated with - * this extension. + * Create the few preferences needed for the Sony preference activity that is + * launched via Sony Smart Connect */ public class SonyPreferenceActivity extends PreferenceActivity { - private static final int DIALOG_READ_ME = 1; - - private static final int DIALOG_CLEAR = 2; - - @SuppressWarnings("deprecation") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // Load the preferences from an XML resource - addPreferencesFromResource(R.xml.preferences); + // Add the minimal set of preferences specific to Sony Smart Connect + addPreferencesFromResource(R.xml.sony_preferences); + + // Add a preference to launch the main app for primary configuration + Preference preference = new Preference(this); + preference.setTitle(R.string.pref_option_launch_app); + preference.setSummary(R.string.pref_option_launch_app_txt); + PreferenceCategory pc = (PreferenceCategory) findPreference("Sony SW2"); + pc.addPreference(preference); + preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage("com.dattasmoon.pebble.plugin"); + startActivity(LaunchIntent); + return true; + } + }); // Handle clear all events - Preference preference = findPreference(getString(R.string.pref_key_clear)); + preference = findPreference(getString(R.string.pref_key_clear)); preference.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { - showDialog(DIALOG_CLEAR); + showDialog(Constants.DIALOG_CLEAR); return true; } }); @@ -67,7 +78,7 @@ protected Dialog onCreateDialog(int id) { Dialog dialog = null; switch (id) { - case DIALOG_CLEAR: + case Constants.DIALOG_CLEAR: dialog = createClearDialog(); break; default: diff --git a/src/com/dattasmoon/sony/plugin/SonyRegistrationInformation.java b/src/com/dattasmoon/sony/plugin/SonyRegistrationInformation.java index d3e6b3b..280cde4 100644 --- a/src/com/dattasmoon/sony/plugin/SonyRegistrationInformation.java +++ b/src/com/dattasmoon/sony/plugin/SonyRegistrationInformation.java @@ -66,7 +66,7 @@ public ContentValues getExtensionRegistrationConfiguration() { String iconHostapp = ExtensionUtils.getUriString(mContext, R.drawable.ic_launcher); String extensionIcon48 = ExtensionUtils.getUriString(mContext, R.drawable.icon_extension_48); - String configurationText = mContext.getString(R.string.configuration_text); + String configurationText = mContext.getString(R.string.pref_sony_activity_title); String extensionName = mContext.getString(R.string.extension_name); ContentValues values = new ContentValues(); From 808cca6027ad93f48c67c9d64a5e32a2f99792f2 Mon Sep 17 00:00:00 2001 From: Mike C Date: Wed, 4 Dec 2013 18:53:11 -0500 Subject: [PATCH 3/7] Include notification / app icon's in SW2 notifications --- AndroidManifest.xml | 4 +- res/values/strings.xml | 3 ++ res/xml/preferences.xml | 6 ++- .../dattasmoon/pebble/plugin/Constants.java | 1 + .../pebble/plugin/NotificationService.java | 46 +++++++++++++++++-- .../pebble/plugin/SettingsActivity.java | 2 + .../sony/plugin/SonyExtensionService.java | 11 ++++- .../plugin/SonyRegistrationInformation.java | 1 - 8 files changed, 65 insertions(+), 9 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index f70635c..81b5e0a 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="25" + android:versionName="3.0" > Clear All Events "All events on device will be cleared, continue?" + Use App Icons + Use the apps icon instead of notification icon for watch notifications Launch Configuration App Select which notifications to show and other notification options preference_key_clear + preference_key_app_icon preference_key_launch_app Settings All events have been cleared diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 64dc70e..6735ea6 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -61,7 +61,11 @@ - + diff --git a/src/com/dattasmoon/pebble/plugin/Constants.java b/src/com/dattasmoon/pebble/plugin/Constants.java index 27ca013..903a25e 100644 --- a/src/com/dattasmoon/pebble/plugin/Constants.java +++ b/src/com/dattasmoon/pebble/plugin/Constants.java @@ -50,6 +50,7 @@ public final class Constants { public static final String PREFERENCE_CONVERTS = "pref_converts"; public static final String PREFERENCE_IGNORE = "pref_ignore"; public static final String PREFERENCE_PKG_RENAMES = "pref_pkg_renames"; + public static final String PREFERENCE_APP_ICONS = "preference_key_app_icon"; // Intents public static final String INTENT_SEND_PEBBLE_NOTIFICATION = "com.getpebble.action.SEND_NOTIFICATION"; diff --git a/src/com/dattasmoon/pebble/plugin/NotificationService.java b/src/com/dattasmoon/pebble/plugin/NotificationService.java index 724a192..b253a25 100644 --- a/src/com/dattasmoon/pebble/plugin/NotificationService.java +++ b/src/com/dattasmoon/pebble/plugin/NotificationService.java @@ -29,11 +29,15 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.TargetApi; import android.app.Notification; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources; +import android.net.Uri; import android.os.Build; import android.os.Handler; import android.os.Parcelable; @@ -65,6 +69,7 @@ public queueItem(String title, String body) { private boolean notifications_only = false; private boolean no_ongoing_notifs = false; private boolean notification_extras = false; + private boolean useAppIcons = false; private boolean quiet_hours = false; private boolean notifScreenOn = true; private JSONArray converts = new JSONArray(); @@ -250,6 +255,38 @@ public void onAccessibilityEvent(AccessibilityEvent event) { title = eventPackageName; } + // get the icon for the app that posted the notification + String iconURIPath = null; + + try { + String mPackageName = event.getPackageName().toString(); + + int resId = 0; + if (useAppIcons) { + ApplicationInfo ai = pm.getApplicationInfo(mPackageName, 0); + resId = ai.icon; + } else { + Notification parcelable = (Notification) event.getParcelableData(); + resId = parcelable.icon; + } + + Context remotePackageContext = getApplicationContext().createPackageContext(mPackageName, 0); + Resources resources = remotePackageContext.getResources(); + String tempURI = ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + resources.getResourcePackageName(resId) + + '/' + resources.getResourceTypeName(resId) + '/' + resources.getResourceEntryName(resId); + Uri iconURI = Uri.parse(tempURI); // Make sure this is a valid URI + // before assigning it to the path + // we pass on + + iconURIPath = tempURI; + if (Constants.IS_LOGGABLE) { + Log.i(Constants.LOG_TAG, "Notification icon URI object: " + iconURI); + Log.i(Constants.LOG_TAG, "Notification icon URI path: " + iconURIPath); + } + } catch (Exception e) { + e.printStackTrace(); + } + // get the notification text String notificationText = event.getText().toString(); // strip the first and last characters which are [ and ] @@ -319,7 +356,7 @@ public void onAccessibilityEvent(AccessibilityEvent event) { // Send the alert to Pebble sendToPebble(title, notificationText); - sendToSmartWatch(title, notificationText); + sendToSmartWatch(iconURIPath, title, notificationText); if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, event.toString()); @@ -376,7 +413,7 @@ private void sendToPebble(String title, String notificationText) { } - private void sendToSmartWatch(String title, String notificationText) { + private void sendToSmartWatch(String iconURI, String title, String notificationText) { title = title.trim(); notificationText = notificationText.trim(); if (title.trim().isEmpty() || notificationText.isEmpty()) { @@ -407,6 +444,7 @@ private void sendToSmartWatch(String title, String notificationText) { i.putExtra("sender", getString(R.string.app_name)); i.putExtra("title", title); i.putExtra("body", notificationText); + i.putExtra("iconURI", iconURI); // Send the alert to Pebble if (Constants.IS_LOGGABLE) { @@ -432,7 +470,6 @@ protected void onServiceConnected() { try { watchFile.createNewFile(); } catch (IOException e) { - // TODO Auto-generated catch block e.printStackTrace(); } watchFile.setLastModified(System.currentTimeMillis()); @@ -465,6 +502,8 @@ private void loadPrefs() { sharedPreferences.getString(Constants.LOG_TAG + ".packageList", "")); editor.putBoolean(Constants.PREFERENCE_NOTIFICATIONS_ONLY, sharedPreferences.getBoolean(Constants.LOG_TAG + ".notificationsOnly", true)); + editor.putBoolean(Constants.PREFERENCE_APP_ICONS, + sharedPreferences.getBoolean(Constants.LOG_TAG + ".appIcons", false)); editor.putBoolean(Constants.PREFERENCE_NOTIFICATION_EXTRA, sharedPreferences.getBoolean(Constants.LOG_TAG + ".fetchNotificationExtras", false)); editor.commit(); @@ -489,6 +528,7 @@ private void loadPrefs() { packages = sharedPref.getString(Constants.PREFERENCE_PACKAGE_LIST, "").split(","); notifications_only = sharedPref.getBoolean(Constants.PREFERENCE_NOTIFICATIONS_ONLY, true); no_ongoing_notifs = sharedPref.getBoolean(Constants.PREFERENCE_NO_ONGOING_NOTIF, false); + useAppIcons = sharedPref.getBoolean(Constants.PREFERENCE_APP_ICONS, false); min_notification_wait = sharedPref.getInt(Constants.PREFERENCE_MIN_NOTIFICATION_WAIT, 0) * 1000; notification_extras = sharedPref.getBoolean(Constants.PREFERENCE_NOTIFICATION_EXTRA, false); notifScreenOn = sharedPref.getBoolean(Constants.PREFERENCE_NOTIF_SCREEN_ON, true); diff --git a/src/com/dattasmoon/pebble/plugin/SettingsActivity.java b/src/com/dattasmoon/pebble/plugin/SettingsActivity.java index c06826f..5110959 100644 --- a/src/com/dattasmoon/pebble/plugin/SettingsActivity.java +++ b/src/com/dattasmoon/pebble/plugin/SettingsActivity.java @@ -74,6 +74,8 @@ protected void onCreate(Bundle savedInstanceState) { sharedPreferences.getString(Constants.LOG_TAG + ".packageList", "")); editor.putBoolean(Constants.PREFERENCE_NOTIFICATIONS_ONLY, sharedPreferences.getBoolean(Constants.LOG_TAG + ".notificationsOnly", true)); + editor.putBoolean(Constants.PREFERENCE_APP_ICONS, + sharedPreferences.getBoolean(Constants.LOG_TAG + "appIcons", false)); editor.putBoolean(Constants.PREFERENCE_NOTIFICATION_EXTRA, sharedPreferences.getBoolean(Constants.LOG_TAG + ".fetchNotificationExtras", false)); editor.commit(); diff --git a/src/com/dattasmoon/sony/plugin/SonyExtensionService.java b/src/com/dattasmoon/sony/plugin/SonyExtensionService.java index f4a639d..08e3ab5 100644 --- a/src/com/dattasmoon/sony/plugin/SonyExtensionService.java +++ b/src/com/dattasmoon/sony/plugin/SonyExtensionService.java @@ -54,7 +54,11 @@ public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null && Constants.INTENT_ACTION_ADD.equals(intent.getAction())) { Log.d(Constants.LOG_TAG, "onStart action: INTENT_ACTION_ADD"); Bundle extras = intent.getExtras(); - addData((String) extras.get("title"), (String) extras.get("body")); + String iconURI = null; + if (extras.containsKey("iconURI")) { + iconURI = (String) extras.get("iconURI"); + } + addData(iconURI, (String) extras.get("title"), (String) extras.get("body")); stopSelfCheck(); } @@ -75,7 +79,7 @@ public void onDestroy() { /** * Add some "random" data */ - private void addData(String name, String message) { + private void addData(String imageURI, String name, String message) { long time = System.currentTimeMillis(); long sourceId = NotificationUtil.getSourceId(this, Constants.EXTENSION_SPECIFIC_ID); if (sourceId == NotificationUtil.INVALID_ID) { @@ -89,6 +93,9 @@ private void addData(String name, String message) { eventValues.put(Notification.EventColumns.PERSONAL, 1); eventValues.put(Notification.EventColumns.PUBLISHED_TIME, time); eventValues.put(Notification.EventColumns.SOURCE_ID, sourceId); + if (imageURI != null) { + eventValues.put(Notification.EventColumns.IMAGE_URI, imageURI); + } try { getContentResolver().insert(Notification.Event.URI, eventValues); diff --git a/src/com/dattasmoon/sony/plugin/SonyRegistrationInformation.java b/src/com/dattasmoon/sony/plugin/SonyRegistrationInformation.java index 280cde4..ea859f7 100644 --- a/src/com/dattasmoon/sony/plugin/SonyRegistrationInformation.java +++ b/src/com/dattasmoon/sony/plugin/SonyRegistrationInformation.java @@ -128,5 +128,4 @@ public ContentValues getSourceRegistrationConfiguration(String extensionSpecific // ExtensionUtils.getUriString(mContext, R.drawable.actions_3)); return sourceValues; } - } From 5ec8454bb41814b9a1ffe0b00144c0cc713fbec7 Mon Sep 17 00:00:00 2001 From: Mike C Date: Wed, 11 Dec 2013 15:31:25 -0500 Subject: [PATCH 4/7] Embedded locale-api Conflicts: res/values/strings.xml --- ...twofortyfouram_locale_ic_menu_dontsave.png | Bin 0 -> 243 bytes .../twofortyfouram_locale_ic_menu_help.png | Bin 0 -> 314 bytes .../twofortyfouram_locale_ic_menu_save.png | Bin 0 -> 953 bytes ...twofortyfouram_locale_ic_menu_dontsave.png | Bin 0 -> 162 bytes .../twofortyfouram_locale_ic_menu_help.png | Bin 0 -> 208 bytes .../twofortyfouram_locale_ic_menu_save.png | Bin 0 -> 512 bytes ...twofortyfouram_locale_ic_menu_dontsave.png | Bin 0 -> 195 bytes .../twofortyfouram_locale_ic_menu_help.png | Bin 0 -> 248 bytes .../twofortyfouram_locale_ic_menu_save.png | Bin 0 -> 707 bytes ...twofortyfouram_locale_ic_menu_dontsave.png | Bin 0 -> 282 bytes .../twofortyfouram_locale_ic_menu_help.png | Bin 0 -> 373 bytes .../twofortyfouram_locale_ic_menu_save.png | Bin 0 -> 1242 bytes ...twofortyfouram_locale_ic_menu_dontsave.xml | 17 ++ .../twofortyfouram_locale_ic_menu_help.xml | 17 ++ .../twofortyfouram_locale_ic_menu_save.xml | 17 ++ ...ofortyfouram_locale_help_save_dontsave.xml | 48 ++++ res/values/strings.xml | 15 ++ res/values/styles.xml | 26 ++ res/values/twofortyfouram_locale_id.xml | 27 ++ .../pebble/plugin/AbstractPluginActivity.java | 238 +++++++++--------- .../twofortyfouram/locale/BreadCrumber.java | 98 ++++++++ src/com/twofortyfouram/locale/Constants.java | 48 ++++ src/com/twofortyfouram/locale/Intent.java | 195 ++++++++++++++ 23 files changed, 632 insertions(+), 114 deletions(-) create mode 100644 res/drawable-hdpi/twofortyfouram_locale_ic_menu_dontsave.png create mode 100644 res/drawable-hdpi/twofortyfouram_locale_ic_menu_help.png create mode 100644 res/drawable-hdpi/twofortyfouram_locale_ic_menu_save.png create mode 100644 res/drawable-ldpi/twofortyfouram_locale_ic_menu_dontsave.png create mode 100644 res/drawable-ldpi/twofortyfouram_locale_ic_menu_help.png create mode 100644 res/drawable-ldpi/twofortyfouram_locale_ic_menu_save.png create mode 100644 res/drawable-mdpi/twofortyfouram_locale_ic_menu_dontsave.png create mode 100644 res/drawable-mdpi/twofortyfouram_locale_ic_menu_help.png create mode 100644 res/drawable-mdpi/twofortyfouram_locale_ic_menu_save.png create mode 100644 res/drawable-xhdpi/twofortyfouram_locale_ic_menu_dontsave.png create mode 100644 res/drawable-xhdpi/twofortyfouram_locale_ic_menu_help.png create mode 100644 res/drawable-xhdpi/twofortyfouram_locale_ic_menu_save.png create mode 100644 res/drawable/twofortyfouram_locale_ic_menu_dontsave.xml create mode 100644 res/drawable/twofortyfouram_locale_ic_menu_help.xml create mode 100644 res/drawable/twofortyfouram_locale_ic_menu_save.xml create mode 100644 res/menu/twofortyfouram_locale_help_save_dontsave.xml create mode 100644 res/values/styles.xml create mode 100644 res/values/twofortyfouram_locale_id.xml create mode 100644 src/com/twofortyfouram/locale/BreadCrumber.java create mode 100644 src/com/twofortyfouram/locale/Constants.java create mode 100644 src/com/twofortyfouram/locale/Intent.java diff --git a/res/drawable-hdpi/twofortyfouram_locale_ic_menu_dontsave.png b/res/drawable-hdpi/twofortyfouram_locale_ic_menu_dontsave.png new file mode 100644 index 0000000000000000000000000000000000000000..9b2082225991c248cd4e0cd8ec271b82ae485574 GIT binary patch literal 243 zcmV<%z;I9ihJ%7JI7*MHC_P3G(r=mmrPhD;`X8hH(cyo%>dO!R0!?4SS{C_s t*C4x#qTN;6v)Qn3$7tFy`i7PBcmPyLNZwBy!ax83002ovPDHLkV1fhzV<-Rs literal 0 HcmV?d00001 diff --git a/res/drawable-hdpi/twofortyfouram_locale_ic_menu_help.png b/res/drawable-hdpi/twofortyfouram_locale_ic_menu_help.png new file mode 100644 index 0000000000000000000000000000000000000000..f7b483de01777fcb1c397cf3addfe93651e958c8 GIT binary patch literal 314 zcmV-A0mc4_P)J+L$H#^Fua{bZ-B zm2=kM0d|nyIDiMsbY~Tj83d4sL}2ccS-}C)7uY*wQiYUM>6g?2(^D#R5DGno6o|QQ z+6|b(T1{S!?kS~T8ruQ&;hZ}W+U{uZKsXnBTpPn6$O$M6H!KUeVs^`k-w^)O{NI>hK%CQoLx|+E_(RM3z;F*6dE<^ zT3UM$fUWaKJ{TjIC1fl}!oR8XO?C)1w$u1;tIoopK-w}QSf?NB36~GVX!e87b^rhX M07*qoM6N<$g3=y;q?nK8}@ZVWc`Y`VP|E1@zde8dOF{kt6RCg!6a_0)qu1WcsTQ6)k zo%$%|==80#4Zq0FwP0txfA#F%yO+Du88zPh{?$9f`Awsv>iWYM3g-Nt80b2G#h02Q zod*xIS@y2$^*3L)MU#n*Q!8OmHKTBPI@X({Ch;M%< zJx@OUsj~D>ages)d*=J=rKbEgJ=x6nS~|^WuO?UF;oO;bCg=YAU6`ugDt`W!XzTOu zmwGPpoMqd4BkBHvx`TfkpDsvmXSMxtRFLUi|KU5<>aBa~UEJ0L>wK8X?Yh%mcwa$b zU+Z>vCcT*Hi}rK;NGQxS*mqnsC9*BZyh`>%QQ=|k&t~=si_71u=!<_>+dpO6=?nH8 z|7$;Xur7XK?0-mHd)~%^71F0T%7<6EJZe_h-#A*k klyiMl#lQMLAAhjiTWGnxl}APum}D3{UHx3vIVCg!0PaF>>i_@% literal 0 HcmV?d00001 diff --git a/res/drawable-ldpi/twofortyfouram_locale_ic_menu_dontsave.png b/res/drawable-ldpi/twofortyfouram_locale_ic_menu_dontsave.png new file mode 100644 index 0000000000000000000000000000000000000000..b9a66c85547fab5cce88a3d64215a0f0b8957a14 GIT binary patch literal 162 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@RheOivfbkcwMtr`+abP~c&nd(1TE zz}(mab5}7g{3qKg^6Bz2cDq~4Iy&l1qYbYtz9+wF-8L@Q6LouII~TfWC31N7>KO3s z%}L;w<`!sUT*AQ2afsm&V`P8Y-kjH;qwSaEy5u-#M=NhTTE-w?EPKBNpz! literal 0 HcmV?d00001 diff --git a/res/drawable-ldpi/twofortyfouram_locale_ic_menu_help.png b/res/drawable-ldpi/twofortyfouram_locale_ic_menu_help.png new file mode 100644 index 0000000000000000000000000000000000000000..da13c6ff9445faecb47118371fd365725d33cdec GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rhe>7Fi*Ar_~T6Am!_`~N?m|A=?v z4<4a=EJy5kjxa5FRAs_^q0n|C+gAaD7d(M_%vz5ctFr9{mNRZN^iZC{Z=9jFaa|Cz zWP{qX<~LewMT}QUr%1NElM1kylZ!ztNr?v-gV@-f+RJ6B9x^H7?OHO;(Z=IthW)|=Yz&Wfr8p$YtY8N^k-^i|&t;uc GLK6Ubdq_|K literal 0 HcmV?d00001 diff --git a/res/drawable-ldpi/twofortyfouram_locale_ic_menu_save.png b/res/drawable-ldpi/twofortyfouram_locale_ic_menu_save.png new file mode 100644 index 0000000000000000000000000000000000000000..e62bab482ca8dec9f63c1a36bea48d69ebb912ad GIT binary patch literal 512 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 BCT0Kt literal 0 HcmV?d00001 diff --git a/res/drawable/twofortyfouram_locale_ic_menu_dontsave.xml b/res/drawable/twofortyfouram_locale_ic_menu_dontsave.xml new file mode 100644 index 0000000..e12356d --- /dev/null +++ b/res/drawable/twofortyfouram_locale_ic_menu_dontsave.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/res/drawable/twofortyfouram_locale_ic_menu_help.xml b/res/drawable/twofortyfouram_locale_ic_menu_help.xml new file mode 100644 index 0000000..94d3ed3 --- /dev/null +++ b/res/drawable/twofortyfouram_locale_ic_menu_help.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/res/drawable/twofortyfouram_locale_ic_menu_save.xml b/res/drawable/twofortyfouram_locale_ic_menu_save.xml new file mode 100644 index 0000000..bcf17fd --- /dev/null +++ b/res/drawable/twofortyfouram_locale_ic_menu_save.xml @@ -0,0 +1,17 @@ + + + + diff --git a/res/menu/twofortyfouram_locale_help_save_dontsave.xml b/res/menu/twofortyfouram_locale_help_save_dontsave.xml new file mode 100644 index 0000000..52eade3 --- /dev/null +++ b/res/menu/twofortyfouram_locale_help_save_dontsave.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 4428f72..134fa65 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -100,4 +100,19 @@ New notification from Smart Watch Notifier Notifier Source + + + %1$s%2$s%3$s + + + \u0020>\u0020 + + + Cancel + + + Help + + + Done \ No newline at end of file diff --git a/res/values/styles.xml b/res/values/styles.xml new file mode 100644 index 0000000..c329d5c --- /dev/null +++ b/res/values/styles.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 134fa65..d538027 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -102,10 +102,10 @@ Notifier Source - %1$s%2$s%3$s + %1$s%2$s%3$s - \u0020>\u0020 + \u0020>\u0020 Cancel diff --git a/src/com/dattasmoon/pebble/plugin/AbstractPluginActivity.java b/src/com/dattasmoon/pebble/plugin/AbstractPluginActivity.java index 8a9a211..099ba08 100644 --- a/src/com/dattasmoon/pebble/plugin/AbstractPluginActivity.java +++ b/src/com/dattasmoon/pebble/plugin/AbstractPluginActivity.java @@ -22,128 +22,117 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import com.twofortyfouram.locale.BreadCrumber; public abstract class AbstractPluginActivity extends Activity { - public enum Mode { - STANDARD, LOCALE - }; - - private boolean mIsCancelled = false; - protected Mode mode = Mode.STANDARD; - Bundle localeBundle = null; - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - PreferenceManager.setDefaultValues(this, R.xml.preferences, false); - localeBundle = getIntent().getBundleExtra( - com.twofortyfouram.locale.Intent.EXTRA_BUNDLE); - - if (getIntent().getAction() == "com.twofortyfouram.locale.intent.action.EDIT_SETTING") { - mode = Mode.LOCALE; - if (Constants.IS_LOGGABLE) { - Log.i(Constants.LOG_TAG, "Activity mode is set to locale"); - } - } else { - mode = Mode.STANDARD; - if (Constants.IS_LOGGABLE) { - Log.i(Constants.LOG_TAG, "Activity mode is set to standard"); - } - } - - if (mode == Mode.LOCALE) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - setupTitleApi11(); - } else { - setTitle(BreadCrumber.generateBreadcrumb( - getApplicationContext(), getIntent(), - getString(R.string.app_name))); - } - } - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - private void setupTitleApi11() { - CharSequence callingApplicationLabel = null; - try { - callingApplicationLabel = getPackageManager().getApplicationLabel( - getPackageManager().getApplicationInfo(getCallingPackage(), - 0)); - } catch (final NameNotFoundException e) { - if (Constants.IS_LOGGABLE) { - Log.e(Constants.LOG_TAG, "Calling package couldn't be found", e); - } - } - if (null != callingApplicationLabel) { - setTitle(callingApplicationLabel); - } - } - - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - super.onCreateOptionsMenu(menu); - if (mode == Mode.LOCALE) { - getMenuInflater().inflate( - R.menu.twofortyfouram_locale_help_save_dontsave, menu); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - setupActionBarApi11(); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - setupActionBarApi14(); - } - return true; - } - return false; - - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - private void setupActionBarApi11() { - getActionBar().setSubtitle( - BreadCrumber.generateBreadcrumb(getApplicationContext(), - getIntent(), getString(R.string.app_name))); - } - - @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) - private void setupActionBarApi14() { - getActionBar().setDisplayHomeAsUpEnabled(true); - try { - getActionBar() - .setIcon( - getPackageManager().getApplicationIcon( - getCallingPackage())); - } catch (final NameNotFoundException e) { - if (Constants.IS_LOGGABLE) { - Log.w(Constants.LOG_TAG, - "An error occurred loading the host's icon", e); - } - } - } - - @Override - public boolean onMenuItemSelected(final int featureId, final MenuItem item) { - if (Constants.IS_LOGGABLE) { - Log.i(Constants.LOG_TAG, "Abstract plugin: Selected menu item id: " - + String.valueOf(item.getItemId())); - } - final int id = item.getItemId(); - - if (android.R.id.home == id) { - finish(); - return true; - } else if (R.id.twofortyfouram_locale_menu_dontsave == id) { - mIsCancelled = true; - finish(); - return true; - } else if (R.id.twofortyfouram_locale_menu_save == id) { - finish(); - return true; - } - - return super.onOptionsItemSelected(item); - } - - protected boolean isCanceled() { - return mIsCancelled; - } + public enum Mode { + STANDARD, LOCALE + }; + + private boolean mIsCancelled = false; + protected Mode mode = Mode.STANDARD; + Bundle localeBundle = null; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + PreferenceManager.setDefaultValues(this, R.xml.preferences, false); + localeBundle = getIntent().getBundleExtra(com.twofortyfouram.locale.Intent.EXTRA_BUNDLE); + + if (getIntent().getAction() == "com.twofortyfouram.locale.intent.action.EDIT_SETTING") { + mode = Mode.LOCALE; + if (Constants.IS_LOGGABLE) { + Log.i(Constants.LOG_TAG, "Activity mode is set to locale"); + } + } else { + mode = Mode.STANDARD; + if (Constants.IS_LOGGABLE) { + Log.i(Constants.LOG_TAG, "Activity mode is set to standard"); + } + } + + if (mode == Mode.LOCALE) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + setupTitleApi11(); + } else { + setTitle(BreadCrumber.generateBreadcrumb(getApplicationContext(), getIntent(), + getString(R.string.app_name))); + } + } + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + private void setupTitleApi11() { + CharSequence callingApplicationLabel = null; + try { + callingApplicationLabel = getPackageManager().getApplicationLabel( + getPackageManager().getApplicationInfo(getCallingPackage(), 0)); + } catch (final NameNotFoundException e) { + if (Constants.IS_LOGGABLE) { + Log.e(Constants.LOG_TAG, "Calling package couldn't be found", e); + } + } + if (null != callingApplicationLabel) { + setTitle(callingApplicationLabel); + } + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + super.onCreateOptionsMenu(menu); + if (mode == Mode.LOCALE) { + getMenuInflater().inflate(R.menu.twofortyfouram_locale_help_save_dontsave, menu); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + setupActionBarApi11(); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + setupActionBarApi14(); + } + return true; + } + return false; + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + private void setupActionBarApi11() { + getActionBar().setSubtitle( + BreadCrumber.generateBreadcrumb(getApplicationContext(), getIntent(), getString(R.string.app_name))); + } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + private void setupActionBarApi14() { + getActionBar().setDisplayHomeAsUpEnabled(true); + try { + getActionBar().setIcon(getPackageManager().getApplicationIcon(getCallingPackage())); + } catch (final NameNotFoundException e) { + if (Constants.IS_LOGGABLE) { + Log.w(Constants.LOG_TAG, "An error occurred loading the host's icon", e); + } + } + } + + @Override + public boolean onMenuItemSelected(final int featureId, final MenuItem item) { + if (Constants.IS_LOGGABLE) { + Log.i(Constants.LOG_TAG, "Abstract plugin: Selected menu item id: " + String.valueOf(item.getItemId())); + } + final int id = item.getItemId(); + + if (android.R.id.home == id) { + finish(); + return true; + } else if (R.id.twofortyfouram_locale_menu_dontsave == id) { + mIsCancelled = true; + finish(); + return true; + } else if (R.id.twofortyfouram_locale_menu_save == id) { + finish(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + protected boolean isCanceled() { + return mIsCancelled; + } } diff --git a/src/com/dattasmoon/pebble/plugin/EditNotificationActivity.java b/src/com/dattasmoon/pebble/plugin/EditNotificationActivity.java index 17ca9ef..0026682 100644 --- a/src/com/dattasmoon/pebble/plugin/EditNotificationActivity.java +++ b/src/com/dattasmoon/pebble/plugin/EditNotificationActivity.java @@ -16,6 +16,10 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import java.util.Comparator; import java.util.List; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; @@ -30,19 +34,30 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; -import android.preference.PreferenceManager; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.text.TextUtils; import android.util.Log; -import android.view.*; +import android.view.ContextMenu; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; import android.view.View.OnClickListener; -import android.widget.*; +import android.view.ViewGroup; +import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.Spinner; +import android.widget.TextView; public class EditNotificationActivity extends AbstractPluginActivity { @@ -88,14 +103,14 @@ public void onNothingSelected(AdapterView parent) { } } }); - } @Override - public void onResume(){ + public void onResume() { super.onResume(); if (mode == Mode.STANDARD) { - sharedPreferences = getSharedPreferences(Constants.LOG_TAG+"_preferences", MODE_MULTI_PROCESS | MODE_PRIVATE); + sharedPreferences = getSharedPreferences(Constants.LOG_TAG + "_preferences", MODE_MULTI_PROCESS + | MODE_PRIVATE); if (sharedPreferences.getBoolean(Constants.PREFERENCE_TASKER_SET, false)) { tvTaskerNotice.setVisibility(View.VISIBLE); } @@ -126,7 +141,7 @@ public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater menuInflater = getMenuInflater(); menuInflater.inflate(R.menu.activity_edit_notifications, menu); - if(mode == Mode.LOCALE){ + if (mode == Mode.LOCALE) { menu.removeItem(R.id.btnSettings); } return true; @@ -150,9 +165,11 @@ public boolean onOptionsItemSelected(MenuItem item) { builder.setMessage(getString(R.string.dialog_uncheck_message)); builder.setCancelable(false); builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() { + @Override public void onClick(DialogInterface dialog, int buttonId) { - if (lvPackages == null || lvPackages.getAdapter() == null || ((packageAdapter) lvPackages.getAdapter()).selected == null){ - //something went wrong + if (lvPackages == null || lvPackages.getAdapter() == null + || ((packageAdapter) lvPackages.getAdapter()).selected == null) { + // something went wrong return; } ((packageAdapter) lvPackages.getAdapter()).selected.clear(); @@ -160,8 +177,9 @@ public void onClick(DialogInterface dialog, int buttonId) { } }); builder.setNegativeButton(R.string.decline, new DialogInterface.OnClickListener() { + @Override public void onClick(DialogInterface dialog, int buttonId) { - //do nothing! + // do nothing! } }); builder.setIcon(android.R.drawable.ic_dialog_alert); @@ -181,18 +199,18 @@ public void onClick(DialogInterface dialog, int buttonId) { startActivity(settings); return true; case R.id.btnRename: - contextInfo = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); + contextInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); int position = contextInfo.position; long id = contextInfo.id; // the child view who's info we're viewing (should be equal to v) v = contextInfo.targetView; - app_name = ((TextView)v.findViewById(R.id.tvPackage)).getText().toString(); + app_name = ((TextView) v.findViewById(R.id.tvPackage)).getText().toString(); viewHolder = (ListViewHolder) v.getTag(); - if (viewHolder == null || viewHolder.chkEnabled == null){ - //failure + if (viewHolder == null || viewHolder.chkEnabled == null) { + // failure return true; } - package_name = (String)viewHolder.chkEnabled.getTag(); + package_name = (String) viewHolder.chkEnabled.getTag(); builder.setTitle(R.string.dialog_title_rename_notification); final EditText input = new EditText(this); input.setHint(app_name); @@ -201,7 +219,7 @@ public void onClick(DialogInterface dialog, int buttonId) { builder.setNegativeButton(R.string.decline, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - //do nothing + // do nothing } }); final AlertDialog d = builder.create(); @@ -213,10 +231,11 @@ public void onShow(DialogInterface dialog) { b.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - //can't be nothing - if(input.getText().length() > 0){ - if(Constants.IS_LOGGABLE){ - Log.i(Constants.LOG_TAG, "Adding rename for "+ package_name + " to " + input.getText()); + // can't be nothing + if (input.getText().length() > 0) { + if (Constants.IS_LOGGABLE) { + Log.i(Constants.LOG_TAG, + "Adding rename for " + package_name + " to " + input.getText()); } JSONObject rename = new JSONObject(); try { @@ -226,7 +245,7 @@ public void onClick(View v) { } catch (JSONException e) { e.printStackTrace(); } - ((packageAdapter)lvPackages.getAdapter()).notifyDataSetChanged(); + ((packageAdapter) lvPackages.getAdapter()).notifyDataSetChanged(); d.dismiss(); } else { @@ -243,47 +262,47 @@ public void onClick(View v) { return true; case R.id.btnRemoveRename: - contextInfo = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); + contextInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); // the child view who's info we're viewing (should be equal to v) v = contextInfo.targetView; - app_name = ((TextView)v.findViewById(R.id.tvPackage)).getText().toString(); + app_name = ((TextView) v.findViewById(R.id.tvPackage)).getText().toString(); viewHolder = (ListViewHolder) v.getTag(); - if (viewHolder == null || viewHolder.chkEnabled == null){ - if(Constants.IS_LOGGABLE){ + if (viewHolder == null || viewHolder.chkEnabled == null) { + if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, "Viewholder is null or chkEnabled is null"); } - //failure + // failure return true; } - package_name = (String)viewHolder.chkEnabled.getTag(); + package_name = (String) viewHolder.chkEnabled.getTag(); builder.setTitle(getString(R.string.dialog_title_remove_rename) + app_name + " (" + package_name + ")?"); - builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener(){ + builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - if(Constants.IS_LOGGABLE){ + if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, "Before remove is: " + String.valueOf(arrayRenames.length())); } JSONArray tmp = new JSONArray(); - try{ - for(int i = 0; i < arrayRenames.length(); i++){ - if(!arrayRenames.getJSONObject(i).getString("pkg").equalsIgnoreCase(package_name)){ + try { + for (int i = 0; i < arrayRenames.length(); i++) { + if (!arrayRenames.getJSONObject(i).getString("pkg").equalsIgnoreCase(package_name)) { tmp.put(arrayRenames.getJSONObject(i)); } } - } catch (JSONException e){ + } catch (JSONException e) { e.printStackTrace(); } arrayRenames = tmp; - if(Constants.IS_LOGGABLE){ + if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, "After remove is: " + String.valueOf(arrayRenames.length())); } - ((packageAdapter)lvPackages.getAdapter()).notifyDataSetChanged(); + ((packageAdapter) lvPackages.getAdapter()).notifyDataSetChanged(); } }); builder.setNegativeButton(R.string.decline, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - //do nothing + // do nothing } }); builder.show(); @@ -459,17 +478,18 @@ public void finish() { private class LoadAppsTask extends AsyncTask { public ArrayList selected; - List pkgAppsList; - List appsList; - JSONArray jsonRenames; + List pkgAppsList; + List appsList; + JSONArray jsonRenames; @Override - protected void onPreExecute(){ + protected void onPreExecute() { PackageManager pm = getPackageManager(); - try{ + try { pkgAppsList = pm.getInstalledPackages(0); - } catch (RuntimeException e){ - //this is usually thrown when people have too many things installed (or bloatware in the case of Samsung devices) + } catch (RuntimeException e) { + // this is usually thrown when people have too many things + // installed (or bloatware in the case of Samsung devices) pm = getPackageManager(); appsList = pm.getInstalledApplications(0); } @@ -479,12 +499,12 @@ protected void onPreExecute(){ @Override protected Void doInBackground(Void... unused) { if (pkgAppsList == null && appsList == null) { - //something went really bad here + // something went really bad here return null; } if (appsList == null) { appsList = new ArrayList(); - for(PackageInfo pkg : pkgAppsList){ + for (PackageInfo pkg : pkgAppsList) { appsList.add(pkg.applicationInfo); } } @@ -494,7 +514,7 @@ protected Void doInBackground(Void... unused) { String packageList; String packageRenames; if (mode == Mode.LOCALE) { - if(Constants.IS_LOGGABLE){ + if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, "Locale mode"); } if (localeBundle != null) { @@ -504,28 +524,28 @@ protected Void doInBackground(Void... unused) { // this can be null if it doesn't currently exist in the // locale bundle, handle gracefully packageList = ""; - if(Constants.IS_LOGGABLE){ + if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, "Package list from locale bundle is currently null"); } } - if (packageRenames == null){ + if (packageRenames == null) { packageRenames = "[]"; } } else { packageList = ""; packageRenames = "[]"; - if(Constants.IS_LOGGABLE){ + if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, "Locale bundle is null"); } } } else { - if(Constants.IS_LOGGABLE){ + if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, "I am pulling from sharedPrefs"); } packageList = sharedPreferences.getString(Constants.PREFERENCE_PACKAGE_LIST, ""); packageRenames = sharedPreferences.getString(Constants.PREFERENCE_PKG_RENAMES, "[]"); } - if(Constants.IS_LOGGABLE){ + if (Constants.IS_LOGGABLE) { Log.i(Constants.LOG_TAG, "Package list is: " + packageList); } for (String strPackage : packageList.split(",")) { @@ -537,9 +557,9 @@ protected Void doInBackground(Void... unused) { } } } - try{ + try { jsonRenames = new JSONArray(packageRenames); - } catch (JSONException e){ + } catch (JSONException e) { e.printStackTrace(); } return null; @@ -548,10 +568,10 @@ protected Void doInBackground(Void... unused) { @Override protected void onPostExecute(Void unused) { if (appsList == null) { - //something went wrong + // something went wrong return; } - if(jsonRenames == null){ + if (jsonRenames == null) { arrayRenames = new JSONArray(); } else { arrayRenames = jsonRenames; @@ -566,12 +586,13 @@ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.Context AdapterView.AdapterContextMenuInfo contextInfo = (AdapterView.AdapterContextMenuInfo) menuInfo; int position = contextInfo.position; long id = contextInfo.id; - // the child view who's info we're viewing (should be equal to v) + // the child view who's info we're viewing (should + // be equal to v) View v = contextInfo.targetView; MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.list_application_menu, menu); ListViewHolder viewHolder = (ListViewHolder) v.getTag(); - if(viewHolder.renamed){ + if (viewHolder.renamed) { menu.findItem(R.id.btnRename).setVisible(false); menu.findItem(R.id.btnRemoveRename).setVisible(true); } @@ -582,11 +603,12 @@ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.Context } } - private class packageAdapter extends ArrayAdapter implements OnCheckedChangeListener, OnClickListener { - private final Context context; - private final PackageManager pm; + private class packageAdapter extends ArrayAdapter implements OnCheckedChangeListener, + OnClickListener { + private final Context context; + private final PackageManager pm; private final ApplicationInfo[] packages; - public ArrayList selected; + public ArrayList selected; public packageAdapter(Context context, ApplicationInfo[] packages, ArrayList selected) { super(context, R.layout.list_application_item, packages); @@ -610,9 +632,9 @@ public View getView(int position, View rowView, ViewGroup parent) { viewHolder.chkEnabled = (CheckBox) rowView.findViewById(R.id.chkEnabled); viewHolder.chkEnabled.setOnCheckedChangeListener(this); - rowView.setOnClickListener(this); - //really wish we didn't have to do this, but if we don't the rowview will gobble this event up. + // really wish we didn't have to do this, but if we don't the + // rowview will gobble this event up. rowView.setOnCreateContextMenuListener(null); rowView.setTag(viewHolder); } else { @@ -623,24 +645,24 @@ public View getView(int position, View rowView, ViewGroup parent) { String appName = null; viewHolder.renamed = false; try { - for(int i = 0; i < arrayRenames.length(); i++){ - if(arrayRenames.getJSONObject(i).getString("pkg").equalsIgnoreCase(info.packageName)){ + for (int i = 0; i < arrayRenames.length(); i++) { + if (arrayRenames.getJSONObject(i).getString("pkg").equalsIgnoreCase(info.packageName)) { viewHolder.renamed = true; appName = arrayRenames.getJSONObject(i).getString("to"); viewHolder.textView.setTag(appName); break; } } - if(!viewHolder.renamed){ + if (!viewHolder.renamed) { appName = info.loadLabel(pm).toString(); } - } catch (NullPointerException e ){ + } catch (NullPointerException e) { appName = null; - } catch (JSONException e){ + } catch (JSONException e) { appName = null; } - if(appName != null){ + if (appName != null) { viewHolder.textView.setText(appName); } else { viewHolder.textView.setText(""); @@ -648,10 +670,10 @@ public View getView(int position, View rowView, ViewGroup parent) { Drawable icon; try { icon = info.loadIcon(pm); - } catch (NullPointerException e){ + } catch (NullPointerException e) { icon = null; } - if(icon != null){ + if (icon != null) { viewHolder.imageView.setImageDrawable(icon); } viewHolder.chkEnabled.setTag(info.packageName); @@ -705,18 +727,20 @@ public void onClick(View rowView) { } public static class ListViewHolder { - public boolean renamed; + public boolean renamed; public TextView textView; public CheckBox chkEnabled; public ImageView imageView; - public ListViewHolder(){ + + public ListViewHolder() { renamed = false; } } public class AppComparator implements Comparator { final PackageManager pm; - public AppComparator(Context context){ + + public AppComparator(Context context) { this.pm = context.getPackageManager(); } From 59f3ce7b4bfa034c3858290dd5035c8189afc3c0 Mon Sep 17 00:00:00 2001 From: Mike C Date: Wed, 11 Dec 2013 16:25:46 -0500 Subject: [PATCH 7/7] Add Tasker plugin api --- .../android/tasker/TaskerPlugin.java | 441 ++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 src/net/dinglisch/android/tasker/TaskerPlugin.java diff --git a/src/net/dinglisch/android/tasker/TaskerPlugin.java b/src/net/dinglisch/android/tasker/TaskerPlugin.java new file mode 100644 index 0000000..6eaf4a4 --- /dev/null +++ b/src/net/dinglisch/android/tasker/TaskerPlugin.java @@ -0,0 +1,441 @@ +//package com.yourcompany.yoursetting; +package net.dinglisch.android.tasker; + +import java.net.URISyntaxException; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; + +// Constants and functions for Tasker *extensions* to the plugin protocol +// See Also: http://tasker.dinglisch.net/plugins.html +// v1.0b5 + +public class TaskerPlugin { + + private final static String TAG = "TaskerPlugin"; + + private final static String BASE_KEY = "net.dinglisch.android.tasker"; + private final static String EXTRAS_PREFIX = BASE_KEY + ".extras."; + + /** + * @see #addVariableBundle(Bundle, Bundle) + * @see Host#getVariablesBundle(Intent) + */ + private final static String EXTRA_VARIABLES_BUNDLE = EXTRAS_PREFIX + "VARIABLES"; + + /** + * Host capabilities, passed to plugin with condition or setting edit intents + */ + private final static String EXTRA_HOST_CAPABILITIES = EXTRAS_PREFIX + "HOST_CAPABILITIES"; + + /** + * @see Setting#hostSupportsVariableReturn(Bundle) + */ + public final static int EXTRA_HOST_CAPABILITY_SETTING_RETURN_VARIABLES = 2; + + /** + * @see Condition#hostSupportsVariableReturn(Bundle) + */ + public final static int EXTRA_HOST_CAPABILITY_CONDITION_RETURN_VARIABLES = 4; + + /** + * @see Setting#hostSupportsOnFireVariableReplacement(Bundle) + */ + public final static int EXTRA_HOST_CAPABILITY_SETTING_FIRE_VARIABLE_REPLACEMENT = 8; + + /** + * @see Setting#hostSupportsVariableReturn(Bundle) + */ + private final static int EXTRA_HOST_CAPABILITY_RELEVANT_VARIABLES = 16; + + /** + * + */ + public final static int EXTRA_HOST_CAPABILITY_SETTING_SYNCHRONOUS_EXECUTION = 32; + + + public final static int EXTRA_HOST_CAPABILITY_ALL = + EXTRA_HOST_CAPABILITY_SETTING_RETURN_VARIABLES | + EXTRA_HOST_CAPABILITY_CONDITION_RETURN_VARIABLES | + EXTRA_HOST_CAPABILITY_SETTING_FIRE_VARIABLE_REPLACEMENT | + EXTRA_HOST_CAPABILITY_RELEVANT_VARIABLES| + EXTRA_HOST_CAPABILITY_SETTING_SYNCHRONOUS_EXECUTION; + ; + + // + /** + * + * @see #hostSupportsRelevantVariables(Bundle) + * @see #addRelevantVariableList(Bundle, String[]) + * @see #getRelevantVariableList(Bundle) + */ + private final static String BUNDLE_KEY_RELEVANT_VARIABLES = BASE_KEY + ".RELEVANT_VARIABLES"; + + public static boolean hostSupportsRelevantVariables( Bundle extrasFromHost ) { + return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_RELEVANT_VARIABLES ); + } + + /** + * Specifies to host which variables might be used by the plugin. + * + * Used in EditActivity, before setResult(). + * + * @param intentToHost the intent being returned to the host + * @param variableNames array of relevant variable names + */ + public static void addRelevantVariableList( Intent intentToHost, String [] variableNames ) { + intentToHost.putExtra( BUNDLE_KEY_RELEVANT_VARIABLES, variableNames ); + } + + /** + * Allows the plugin/host to indicate to each other a set of variables which they are referencing. + * The host may use this to e.g. show a variable selection list in it's UI. + * The host should use this if it previously indicated to the plugin that it supports relevant vars + * + * @param fromHostIntentExtras usually from getIntent().getExtras() + * @return variableNames an array of relevant variable names + */ + public static String [] getRelevantVariableList( Bundle fromHostIntentExtras ) { + + String [] relevantVars = (String []) getBundleValueSafe( fromHostIntentExtras, BUNDLE_KEY_RELEVANT_VARIABLES, String [].class, "getRelevantVariableList" ); + + if ( relevantVars == null ) + relevantVars = new String [0]; + + return relevantVars; + } + + /** + * Used by: plugin QueryReceiver, FireReceiver + * + * Add a bundle of variable name/value pairs. + * + * @param resultExtras the result extras from the receiver onReceive (from a call to getResultExtras()) + * @param variables the variables to send + * @see #hostSupportsVariableReturn(Bundle) + */ + public static void addVariableBundle( Bundle resultExtras, Bundle variables ) { + resultExtras.putBundle( EXTRA_VARIABLES_BUNDLE, variables ); + } + + // ----------------------------- SETTING PLUGIN ONLY --------------------------------- // + + public static class Setting { + + /** + * @see #setVariableReplaceKeys(Bundle, String[]) + */ + private final static String BUNDLE_KEY_VARIABLE_REPLACE_STRINGS = EXTRAS_PREFIX + "VARIABLE_REPLACE_KEYS"; + + /** + * @see #requestTimeoutMS(Intent, int) + */ + private final static String EXTRA_REQUESTED_TIMEOUT = EXTRAS_PREFIX + "REQUESTED_TIMEOUT"; + + /** + * @see #signalFinish(Context, Intent, Status, Bundle) + * @see Host#addCompletionIntent(Intent, Intent) + */ + private final static String EXTRA_PLUGIN_COMPLETION_INTENT = EXTRAS_PREFIX + "COMPLETION_INTENT"; + + /** + * @see #signalFinish(Context, Intent, Status, Bundle) + * @see Host#getSettingCompletionStatus(Intent) + */ + public final static String EXTRA_RESULT_CODE = EXTRAS_PREFIX + "RESULT_CODE"; + + /** + * @see #signalFinish(Context, Intent, Status, Bundle) + * @see Host#getSettingResultCode(Intent) + */ + + public final static int RESULT_CODE_OK = Activity.RESULT_OK; + public final static int RESULT_CODE_OK_MINOR_FAILURES = Activity.RESULT_FIRST_USER; + public final static int RESULT_CODE_FAILED = Activity.RESULT_FIRST_USER + 1; + public final static int RESULT_CODE_PENDING = Activity.RESULT_FIRST_USER + 2; + public final static int RESULT_CODE_UNKNOWN = Activity.RESULT_FIRST_USER + 3; + + /** + * Used by: plugin EditActivity. + * + * Indicates to plugin that host will replace variables in specified bundle keys. + * + * Replacement takes place every time the setting is fired, before the bundle is + * passed to the plugin FireReceiver. + * + * @param extrasFromHost intent extras from the intent received by the edit activity + * @see #setVariableReplaceKeys(Bundle, String[]) + */ + public static boolean hostSupportsOnFireVariableReplacement( Bundle extrasFromHost ) { + return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_SETTING_FIRE_VARIABLE_REPLACEMENT ); + } + + public static boolean hostSupportsSynchronousExecution( Bundle extrasFromHost ) { + return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_SETTING_SYNCHRONOUS_EXECUTION ); + } + + /** + * Request the host to wait the specified number of milliseconds before continuing. + * Note that the host may choose to ignore the request. + * + * Used in EditActivity, before setResult(). + * + * @param intentToHost the intent being returned to the host + * @param timeoutMS + */ + public static void requestTimeoutMS( Intent intentToHost, int timeoutMS ) { + intentToHost.putExtra( EXTRA_REQUESTED_TIMEOUT, timeoutMS ); + } + + /** + * Used by: plugin EditActivity + * + * Indicates to host which bundle keys should be replaced. + * + * @param resultBundleToHost the bundle being returned to the host + * @param listOfKeyNames which bundle keys to replace variables in when setting fires + * @see #hostSupportsOnFireVariableReplacement(Bundle) + */ + public static void setVariableReplaceKeys( Bundle resultBundleToHost, String [] listOfKeyNames ) { + + StringBuilder builder = new StringBuilder(); + + if ( listOfKeyNames != null ) { + + for ( String keyName : listOfKeyNames ) { + + if ( keyName.contains( " " ) ) + Log.w( TAG, "setVariableReplaceKeys: ignoring bad keyName containing space: " + keyName ); + else { + if ( builder.length() > 0 ) + builder.append( ' ' ); + + builder.append( keyName ); + } + + if ( builder.length() > 0 ) + resultBundleToHost.putString( BUNDLE_KEY_VARIABLE_REPLACE_STRINGS, builder.toString() ); + } + } + } + + /** + * Used by: plugin FireReceiver + * + * Indicates to plugin whether the host will process variables which it passes back + * + * @param extrasFromHost intent extras from the intent received by the FireReceiver + * @see #signalFinish(Context, Intent, Status, Bundle) + */ + public static boolean hostSupportsVariableReturn( Bundle extrasFromHost ) { + return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_SETTING_RETURN_VARIABLES ); + } + + /** + * Used by: plugin FireReceiver + * + * Tell the host that the plugin has finished execution. + * + * @param originalFireIntent the intent received from the host (via onReceive()) + * @param status level of success in performing the settings + * @param vars any variables that the plugin wants to set in the host + * @see #hostSupportsSynchronousSettings(Bundle) + * @see #setWantSynchronousExecution(Intent, int) + */ + public static boolean signalFinish( Context context, Intent originalFireIntent, int resultCode, Bundle vars ) { + + String errorPrefix = "signalFinish: "; + + boolean okFlag = false; + + String completionIntentString = (String) TaskerPlugin.getExtraValueSafe( originalFireIntent, Setting.EXTRA_PLUGIN_COMPLETION_INTENT, String.class, "signalFinish" ); + + if ( completionIntentString != null ) { + Uri completionIntentUri = null; + try { + completionIntentUri = Uri.parse( completionIntentString ); + } + // should only throw NullPointer but don't particularly trust it + catch ( Exception e ) { + Log.w( TAG, errorPrefix + "couldn't parse " + completionIntentString ); + } + + if ( completionIntentUri != null ) { + try { + Intent completionIntent = Intent.parseUri( completionIntentString, Intent.URI_INTENT_SCHEME ); + + completionIntent.putExtra( EXTRA_RESULT_CODE, resultCode ); + + if ( vars != null ) + completionIntent.putExtra( EXTRA_VARIABLES_BUNDLE, vars ); + + context.sendBroadcast( completionIntent ); + + okFlag = true; + } + catch ( URISyntaxException e ) { + Log.w( TAG, errorPrefix + "bad URI: " + completionIntentUri ); + } + } + } + + return okFlag; + } + } + + // ----------------------------- CONDITION PLUGIN ONLY --------------------------------- // + + public static class Condition { + + /** + * Used by: plugin QueryReceiver + * + * Indicates to plugin whether the host will process variables which it passes back + * + * @param extrasFromHost intent extras from the intent received by the QueryReceiver + * @see #addVariableBundle(Bundle, Bundle) + */ + public static boolean hostSupportsVariableReturn( Bundle extrasFromHost ) { + return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_CONDITION_RETURN_VARIABLES ); + } + } + + // ---------------------------------- HOST ----------------------------------------- // + + public static class Host { + + /** + * Tell the plugin what capabilities the host support. This should be called when sending + * intents to any EditActivity, FireReceiver or QueryReceiver. + * + * @param toPlugin the intent we're sending + * @return capabilites one or more of the EXTRA_HOST_CAPABILITY_XXX flags + */ + public static Intent addCapabilities( Intent toPlugin, int capabilities ) { + return toPlugin.putExtra( EXTRA_HOST_CAPABILITIES, capabilities ); + } + + /** + * Add an intent to the fire intent before it goes to the plugin FireReceiver, which the plugin + * can use to signal when it is finished. Only use if @code{pluginWantsSychronousExecution} is true. + * + * @param fireIntent fire intent going to the plugin + * @param completionIntent intent which will signal the host that the plugin is finished. + * Implementation is host-dependent. + */ + public static void addCompletionIntent( Intent fireIntent, Intent completionIntent ) { + fireIntent.putExtra( + Setting.EXTRA_PLUGIN_COMPLETION_INTENT, + completionIntent.toUri( Intent.URI_INTENT_SCHEME ) + ); + } + + /** + * When a setting plugin is finished, it sends the host the intent which was passed to it + * via @code{addCompletionIntent}. + * + * @param completionIntent intent returned from the plugin when it finished. + * @return completionStatus measure of plugin success, defaults to UNKNOWN + */ + public static int getSettingResultCode( Intent completionIntent ) { + + Integer val = (Integer) getExtraValueSafe( completionIntent, Setting.EXTRA_RESULT_CODE, String.class, "getSettingCompletionStatus" ); + + return ( val == null ) ? Setting.RESULT_CODE_UNKNOWN : val; + } + + /** + * Extract a bundle of variables from an intent received from the FireReceiver. This + * should be called if the host previously indicated to the plugin + * that it supports setting variable return. + * + * @param fromPlugin the intent we received + * @return variables a bundle of variable name/value pairs + * @see #addCapabilities(Intent, int) + */ + + public static Bundle getVariablesBundle( Bundle resultExtras ) { + return (Bundle) getBundleValueSafe( + resultExtras, EXTRA_VARIABLES_BUNDLE, Bundle.class, "getVariablesBundle" + ); + } + + public static boolean haveRequestedTimeout( Bundle extrasFromPluginEditActivity ) { + return extrasFromPluginEditActivity.containsKey( Setting.EXTRA_REQUESTED_TIMEOUT ); + } + + public static int getRequestedTimeoutMS( Bundle extrasFromPluginEditActivity ) { + return + (Integer) getBundleValueSafe( + extrasFromPluginEditActivity, Setting.EXTRA_REQUESTED_TIMEOUT, Integer.class, "getRequestedTimeout" + ) + ; + } + + public static String [] getSettingVariableReplaceKeys( Bundle fromPluginEditActivity ) { + + String spec = (String) TaskerPlugin.getBundleValueSafe( fromPluginEditActivity, Setting.BUNDLE_KEY_VARIABLE_REPLACE_STRINGS, String.class, "getSettingVariableReplaceKeys" ); + + String [] replaceKeys = null; + + if ( spec != null ) + replaceKeys = spec.split( " " ); + + return replaceKeys; + } + + public static boolean haveRelevantVariables( Bundle b ) { + return b.containsKey( BUNDLE_KEY_RELEVANT_VARIABLES ); + } + + public static void cleanRelevantVariables( Bundle b ) { + b.remove( BUNDLE_KEY_RELEVANT_VARIABLES ); + } + + public static void cleanRequestedTimeout( Bundle extras ) { + extras.remove( Setting.EXTRA_REQUESTED_TIMEOUT ); + } + + public static void cleanSettingReplaceVariables( Bundle b ) { + b.remove( Setting.BUNDLE_KEY_VARIABLE_REPLACE_STRINGS ); + } + } + + // ---------------------------------- HELPER FUNCTIONS -------------------------------- // + + private static Object getBundleValueSafe( Bundle b, String key, Class expectedClass, String funcName ) { + Object value = null; + + if ( b != null ) { + if ( b.containsKey( key ) ) { + Object obj = b.get( key ); + if ( obj == null ) + Log.w( TAG, funcName + ": " + key + ": null value" ); + else if ( obj.getClass() != expectedClass ) + Log.w( TAG, funcName + ": " + key + ": expected " + expectedClass.getClass().getName() + ", got " + obj.getClass().getName() ); + else + value = obj; + } + } + return value; + } + + private static Object getExtraValueSafe( Intent i, String key, Class expectedClass, String funcName ) { + return ( i.hasExtra( key ) ) ? + getBundleValueSafe( i.getExtras(), key, expectedClass, funcName ) : + null; + } + + private static boolean hostSupports( Bundle extrasFromHost, int capabilityFlag ) { + Integer flags = (Integer) getBundleValueSafe( extrasFromHost, EXTRA_HOST_CAPABILITIES, Integer.class, "hostSupports" ); + return + ( flags != null ) && + ( ( flags & capabilityFlag ) > 0 ) + ; + } + +} \ No newline at end of file