From ef0d34d32e9872e36d321e921d7da91f35be032d Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Tue, 23 Aug 2016 14:41:05 -0400 Subject: [PATCH] Add plugin controls to tuner Allow plugins to be manually turned off from within the tuner. This screen only shows itself if at some point in time a plugin has been active on this device. Plugins can also serface settings there by receiving the com.android.systemui.action.PLUGIN_SETTINGS action. Test: Manual Change-Id: Ifb043c85e383fc072c6445ae322293a6401a6f2c --- .../plugin/ExamplePlugin/AndroidManifest.xml | 10 +- .../res/layout/plugin_settings.xml | 24 ++++ .../ExamplePlugin/res/values/strings.xml | 24 ++++ .../testoverlayplugin/PluginSettings.java | 32 +++++ .../plugins/PluginInstanceManager.java | 2 +- .../systemui/plugins/PluginManager.java | 3 + .../android/systemui/plugins/PluginPrefs.java | 61 ++++++++++ .../layout/tuner_widget_settings_switch.xml | 47 ++++++++ packages/SystemUI/res/values/strings.xml | 4 + packages/SystemUI/res/xml/tuner_prefs.xml | 5 + .../systemui/tuner/PluginFragment.java | 111 ++++++++++++++++++ .../android/systemui/tuner/TunerFragment.java | 12 +- 12 files changed, 326 insertions(+), 9 deletions(-) create mode 100644 packages/SystemUI/plugin/ExamplePlugin/res/layout/plugin_settings.xml create mode 100644 packages/SystemUI/plugin/ExamplePlugin/res/values/strings.xml create mode 100644 packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/PluginSettings.java create mode 100644 packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginPrefs.java create mode 100644 packages/SystemUI/res/layout/tuner_widget_settings_switch.xml create mode 100644 packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java diff --git a/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml b/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml index bd2c71c38f5a2..ff89bbcb455f3 100644 --- a/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml +++ b/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml @@ -21,7 +21,15 @@ - + + + + + + + diff --git a/packages/SystemUI/plugin/ExamplePlugin/res/layout/plugin_settings.xml b/packages/SystemUI/plugin/ExamplePlugin/res/layout/plugin_settings.xml new file mode 100644 index 0000000000000..eb90283f08d0e --- /dev/null +++ b/packages/SystemUI/plugin/ExamplePlugin/res/layout/plugin_settings.xml @@ -0,0 +1,24 @@ + + + + diff --git a/packages/SystemUI/plugin/ExamplePlugin/res/values/strings.xml b/packages/SystemUI/plugin/ExamplePlugin/res/values/strings.xml new file mode 100644 index 0000000000000..a0bfe849e5c69 --- /dev/null +++ b/packages/SystemUI/plugin/ExamplePlugin/res/values/strings.xml @@ -0,0 +1,24 @@ + + + + + Plugin settings go here + Overlay Plugin + + diff --git a/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/PluginSettings.java b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/PluginSettings.java new file mode 100644 index 0000000000000..cf39075d958fc --- /dev/null +++ b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/PluginSettings.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.plugin.testoverlayplugin; + +import android.annotation.Nullable; +import android.app.Activity; +import android.os.Bundle; + +/** + * DO NOT Reference Plugin interfaces here, this runs in the plugin APK's process + * and is only for modifying settings. + */ +public class PluginSettings extends Activity { + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.plugin_settings); + } +} diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java index 2a7139c3a74c8..495771a3c8ec3 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java @@ -24,7 +24,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -163,6 +162,7 @@ public class PluginInstanceManager extends BroadcastReceiver { switch (msg.what) { case PLUGIN_CONNECTED: if (DEBUG) Log.d(TAG, "onPluginConnected"); + PluginPrefs.setHasPlugins(mContext); PluginInfo info = (PluginInfo) msg.obj; info.mPlugin.onCreate(mContext, info.mPluginContext); mListener.onPluginConnected(info.mPlugin); diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java index aa0b3c5867478..4bf6494995bc6 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java @@ -37,6 +37,7 @@ public class PluginManager { private final Context mContext; private final PluginInstanceManagerFactory mFactory; private final boolean isDebuggable; + private final PluginPrefs mPluginPrefs; private PluginManager(Context context) { this(context, new PluginInstanceManagerFactory(), Build.IS_DEBUGGABLE, @@ -51,6 +52,7 @@ public class PluginManager { mBackgroundThread = new HandlerThread("Plugins"); mBackgroundThread.start(); isDebuggable = debuggable; + mPluginPrefs = new PluginPrefs(mContext); PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler( defaultHandler); @@ -68,6 +70,7 @@ public class PluginManager { // Never ever ever allow these on production builds, they are only for prototyping. return; } + mPluginPrefs.addAction(action); PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener, allowMultiple, mBackgroundThread.getLooper(), version); p.startListening(); diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginPrefs.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginPrefs.java new file mode 100644 index 0000000000000..3671b3c1689f1 --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginPrefs.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.plugins; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.ArraySet; + +import java.util.Set; + +/** + * Storage for all plugin actions in SharedPreferences. + * + * This allows the list of actions that the Tuner needs to search for to be generated + * instead of hard coded. + */ +public class PluginPrefs { + + private static final String PREFS = "plugin_prefs"; + + private static final String PLUGIN_ACTIONS = "actions"; + private static final String HAS_PLUGINS = "plugins"; + + private final Set mPluginActions; + private final SharedPreferences mSharedPrefs; + + public PluginPrefs(Context context) { + mSharedPrefs = context.getSharedPreferences(PREFS, 0); + mPluginActions = new ArraySet<>(mSharedPrefs.getStringSet(PLUGIN_ACTIONS, null)); + } + + public Set getPluginList() { + return mPluginActions; + } + + public synchronized void addAction(String action) { + if (mPluginActions.add(action)){ + mSharedPrefs.edit().putStringSet(PLUGIN_ACTIONS, mPluginActions).commit(); + } + } + + public static boolean hasPlugins(Context context) { + return context.getSharedPreferences(PREFS, 0).getBoolean(HAS_PLUGINS, false); + } + + public static void setHasPlugins(Context context) { + context.getSharedPreferences(PREFS, 0).edit().putBoolean(HAS_PLUGINS, true).commit(); + } +} diff --git a/packages/SystemUI/res/layout/tuner_widget_settings_switch.xml b/packages/SystemUI/res/layout/tuner_widget_settings_switch.xml new file mode 100644 index 0000000000000..c89c02fd91716 --- /dev/null +++ b/packages/SystemUI/res/layout/tuner_widget_settings_switch.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 562fb7f62b83d..3f485c3bad8b1 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1667,4 +1667,8 @@ Page %1$d of %2$d + + Plugins + diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml index b46e862471f3a..211f8e8183e85 100644 --- a/packages/SystemUI/res/xml/tuner_prefs.xml +++ b/packages/SystemUI/res/xml/tuner_prefs.xml @@ -133,6 +133,11 @@ android:title="@string/other" android:fragment="com.android.systemui.tuner.OtherPrefs" /> + + pluginActions = mPluginPrefs.getPluginList(); + for (String action : pluginActions) { + String name = action.replace("com.android.systemui.action.PLUGIN_", ""); + PreferenceCategory category = new PreferenceCategory(prefContext); + category.setTitle(name); + + List result = getContext().getPackageManager().queryIntentServices( + new Intent(action), PackageManager.MATCH_DISABLED_COMPONENTS); + if (result.size() > 0) { + screen.addPreference(category); + } + for (ResolveInfo info : result) { + category.addPreference(new PluginPreference(prefContext, info)); + } + } + setPreferenceScreen(screen); + } + + private static class PluginPreference extends SwitchPreference { + private final ComponentName mComponent; + private final boolean mHasSettings; + + public PluginPreference(Context prefContext, ResolveInfo info) { + super(prefContext); + mComponent = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name); + PackageManager pm = prefContext.getPackageManager(); + mHasSettings = pm.resolveActivity(new Intent(ACTION_PLUGIN_SETTINGS) + .setPackage(mComponent.getPackageName()), 0) != null; + setTitle(info.serviceInfo.loadLabel(pm)); + setChecked(pm.getComponentEnabledSetting(mComponent) + != PackageManager.COMPONENT_ENABLED_STATE_DISABLED); + setWidgetLayoutResource(R.layout.tuner_widget_settings_switch); + } + + @Override + protected boolean persistBoolean(boolean value) { + getContext().getPackageManager().setComponentEnabledSetting(mComponent, + value ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED + : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + return true; + } + + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + holder.findViewById(R.id.settings).setVisibility(mHasSettings ? View.VISIBLE + : View.GONE); + holder.findViewById(R.id.divider).setVisibility(mHasSettings ? View.VISIBLE + : View.GONE); + holder.findViewById(R.id.settings).setOnClickListener(v -> { + ResolveInfo result = v.getContext().getPackageManager().resolveActivity( + new Intent(ACTION_PLUGIN_SETTINGS).setPackage( + mComponent.getPackageName()), 0); + if (result != null) { + v.getContext().startActivity(new Intent().setComponent( + new ComponentName(result.activityInfo.packageName, + result.activityInfo.name))); + } + }); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java index 70f2fdcfa8d34..7f63418de3244 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java @@ -19,16 +19,9 @@ import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.content.DialogInterface; -import android.database.ContentObserver; -import android.net.Uri; import android.os.Bundle; -import android.os.Handler; import android.provider.Settings; -import android.provider.Settings.System; import android.support.v14.preference.PreferenceFragment; -import android.support.v14.preference.SwitchPreference; -import android.support.v7.preference.Preference; -import android.support.v7.preference.Preference.OnPreferenceChangeListener; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -36,12 +29,14 @@ import android.view.MenuItem; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.systemui.R; +import com.android.systemui.plugins.PluginPrefs; public class TunerFragment extends PreferenceFragment { private static final String TAG = "TunerFragment"; private static final String KEY_BATTERY_PCT = "battery_pct"; + private static final String KEY_PLUGINS = "plugins"; public static final String SETTING_SEEN_TUNER_WARNING = "seen_tuner_warning"; @@ -65,6 +60,9 @@ public class TunerFragment extends PreferenceFragment { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.tuner_prefs); + if (!PluginPrefs.hasPlugins(getContext())) { + getPreferenceScreen().removePreference(findPreference(KEY_PLUGINS)); + } if (Settings.Secure.getInt(getContext().getContentResolver(), SETTING_SEEN_TUNER_WARNING, 0) == 0) {