diff options
| author | 2016-08-23 14:41:05 -0400 | |
|---|---|---|
| committer | 2016-09-27 12:41:34 -0400 | |
| commit | ef0d34d32e9872e36d321e921d7da91f35be032d (patch) | |
| tree | dad78d7c9cac83f9745f2042c5583baff338a5ba | |
| parent | 46767b77c004a3541c614f8e21d6a871dd148e54 (diff) | |
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
12 files changed, 326 insertions, 9 deletions
diff --git a/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml b/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml index bd2c71c38f5a..ff89bbcb455f 100644 --- a/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml +++ b/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml @@ -21,7 +21,15 @@ <uses-permission android:name="com.android.systemui.permission.PLUGIN" /> <application> - <service android:name=".SampleOverlayPlugin"> + <activity android:name=".PluginSettings" + android:label="@string/plugin_label"> + <intent-filter> + <action android:name="com.android.systemui.action.PLUGIN_SETTINGS" /> + </intent-filter> + </activity> + + <service android:name=".SampleOverlayPlugin" + android:label="@string/plugin_label"> <intent-filter> <action android:name="com.android.systemui.action.PLUGIN_OVERLAY" /> </intent-filter> 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 000000000000..eb90283f08d0 --- /dev/null +++ b/packages/SystemUI/plugin/ExamplePlugin/res/layout/plugin_settings.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** Copyright 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. +--> + +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:textAppearance="?android:attr/textAppearanceLarge" + android:text="@string/plugin_settings_here" + android:gravity="center" /> 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 000000000000..a0bfe849e5c6 --- /dev/null +++ b/packages/SystemUI/plugin/ExamplePlugin/res/values/strings.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * 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. + */ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <string name="plugin_settings_here" translatable="false">Plugin settings go here</string> + <string name="plugin_label" translatable="false">Overlay Plugin</string> + +</resources> 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 000000000000..cf39075d958f --- /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 2a7139c3a74c..495771a3c8ec 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<T extends Plugin> extends BroadcastReceiver { switch (msg.what) { case PLUGIN_CONNECTED: if (DEBUG) Log.d(TAG, "onPluginConnected"); + PluginPrefs.setHasPlugins(mContext); PluginInfo<T> info = (PluginInfo<T>) 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 aa0b3c586747..4bf6494995bc 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 000000000000..3671b3c1689f --- /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<String> mPluginActions; + private final SharedPreferences mSharedPrefs; + + public PluginPrefs(Context context) { + mSharedPrefs = context.getSharedPreferences(PREFS, 0); + mPluginActions = new ArraySet<>(mSharedPrefs.getStringSet(PLUGIN_ACTIONS, null)); + } + + public Set<String> 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 000000000000..c89c02fd9171 --- /dev/null +++ b/packages/SystemUI/res/layout/tuner_widget_settings_switch.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="center_vertical"> + + <ImageView + android:id="@+id/settings" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_settings" + android:tint="@android:color/black" + android:padding="12dp" + android:background="?android:attr/selectableItemBackgroundBorderless" /> + + <View + android:id="@+id/divider" + android:layout_width="1dp" + android:layout_height="30dp" + android:layout_marginEnd="8dp" + android:background="?android:attr/listDivider" /> + + <Switch + android:id="@android:id/switch_widget" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:focusable="false" + android:clickable="false" + android:background="@null" /> +</LinearLayout> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 562fb7f62b83..3f485c3bad8b 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1667,4 +1667,8 @@ <!-- accessibility label for paging indicator in quick settings [CHAR LIMITi=NONE] --> <string name="accessibility_quick_settings_page">Page <xliff:g name="current_page" example="1">%1$d</xliff:g> of <xliff:g name="num_pages" example="2">%2$d</xliff:g></string> + <!-- Plugin control section of the tuner. Non-translatable since it should + not appear on production builds ever. --> + <string name="plugins" translatable="false">Plugins</string> + </resources> diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml index b46e862471f3..211f8e8183e8 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" /> + <Preference + android:key="plugins" + android:title="@string/plugins" + android:fragment="com.android.systemui.tuner.PluginFragment" /> + <!-- Warning, this goes last. --> <Preference android:summary="@string/tuner_persistent_warning" diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java new file mode 100644 index 000000000000..132a6dd6c747 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java @@ -0,0 +1,111 @@ +/* + * 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.tuner; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Bundle; +import android.support.v14.preference.PreferenceFragment; +import android.support.v14.preference.SwitchPreference; +import android.support.v7.preference.PreferenceCategory; +import android.support.v7.preference.PreferenceScreen; +import android.support.v7.preference.PreferenceViewHolder; +import android.view.View; + +import com.android.systemui.plugins.PluginPrefs; +import com.android.systemui.R; + +import java.util.List; +import java.util.Set; + +public class PluginFragment extends PreferenceFragment { + + public static final String ACTION_PLUGIN_SETTINGS + = "com.android.systemui.action.PLUGIN_SETTINGS"; + + private PluginPrefs mPluginPrefs; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getContext()); + screen.setOrderingAsAdded(false); + Context prefContext = getPreferenceManager().getContext(); + mPluginPrefs = new PluginPrefs(getContext()); + Set<String> 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<ResolveInfo> 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 70f2fdcfa8d3..7f63418de324 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) { |