summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java8
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java3
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java5
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/Plugin.java19
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/Dependencies.java27
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/DependsOn.java32
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/ProvidesInterface.java30
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/Requirements.java27
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/Requires.java33
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java2
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java27
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowProvider.java3
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java3
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeService.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java (renamed from packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java)42
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java (renamed from packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java)45
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginPrefs.java (renamed from packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginPrefs.java)0
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java134
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/plugins/VersionInfoTest.java103
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java10
32 files changed, 562 insertions, 109 deletions
diff --git a/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java
index 13fc76c5da49..79a0c3599078 100644
--- a/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java
+++ b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java
@@ -24,7 +24,9 @@ import android.view.ViewGroup;
import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
import com.android.systemui.plugins.OverlayPlugin;
+import com.android.systemui.plugins.annotations.Requires;
+@Requires(target = OverlayPlugin.class, version = OverlayPlugin.VERSION)
public class SampleOverlayPlugin implements OverlayPlugin {
private static final String TAG = "SampleOverlayPlugin";
private Context mPluginContext;
@@ -36,12 +38,6 @@ public class SampleOverlayPlugin implements OverlayPlugin {
private float mStatusBarHeight;
@Override
- public int getVersion() {
- Log.d(TAG, "getVersion " + VERSION);
- return VERSION;
- }
-
- @Override
public void onCreate(Context sysuiContext, Context pluginContext) {
Log.d(TAG, "onCreate");
mPluginContext = pluginContext;
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java
index 9c173bd16967..97dbafd65d33 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java
@@ -14,6 +14,8 @@
package com.android.systemui.plugins;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
import android.content.Intent;
import android.graphics.drawable.Drawable;
@@ -21,6 +23,7 @@ import android.graphics.drawable.Drawable;
* An Intent Button represents a triggerable element in SysUI that consists of an
* Icon and an intent to trigger when it is activated (clicked, swiped, etc.).
*/
+@ProvidesInterface(version = IntentButtonProvider.VERSION)
public interface IntentButtonProvider extends Plugin {
public static final int VERSION = 1;
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java
index f5074f75b7a4..61aa60bb9675 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java
@@ -13,12 +13,15 @@
*/
package com.android.systemui.plugins;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
import android.view.View;
+@ProvidesInterface(action = OverlayPlugin.ACTION, version = OverlayPlugin.VERSION)
public interface OverlayPlugin extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_OVERLAY";
- int VERSION = 1;
+ int VERSION = 2;
void setup(View statusBar, View navBar);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/Plugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/Plugin.java
index e75ecb7a127b..bb93367c3791 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/Plugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/Plugin.java
@@ -13,6 +13,8 @@
*/
package com.android.systemui.plugins;
+import com.android.systemui.plugins.annotations.Requires;
+
import android.content.Context;
/**
@@ -111,18 +113,13 @@ import android.content.Context;
public interface Plugin {
/**
- * Should be implemented as the following directly referencing the version constant
- * from the plugin interface being implemented, this will allow recompiles to automatically
- * pick up the current version.
- * <pre class="prettyprint">
- * {@literal
- * public int getVersion() {
- * return VERSION;
- * }
- * }
- * @return
+ * @deprecated
+ * @see Requires
*/
- int getVersion();
+ default int getVersion() {
+ // Default of -1 indicates the plugin supports the new Requires model.
+ return -1;
+ }
default void onCreate(Context sysuiContext, Context pluginContext) {
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/Dependencies.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/Dependencies.java
new file mode 100644
index 000000000000..dbbf047519bb
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/Dependencies.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 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.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Used for repeated @DependsOn internally, not for plugin
+ * use.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Dependencies {
+ DependsOn[] value();
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/DependsOn.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/DependsOn.java
new file mode 100644
index 000000000000..b81d67306307
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/DependsOn.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 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.annotations;
+
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Used to indicate that an interface in the plugin library needs another
+ * interface to function properly. When this is added, it will be enforced
+ * that all plugins that @Requires the annotated interface also @Requires
+ * the specified class as well.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Repeatable(value = Dependencies.class)
+public @interface DependsOn {
+ Class<?> target();
+
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/ProvidesInterface.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/ProvidesInterface.java
new file mode 100644
index 000000000000..d0e14b8657ff
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/ProvidesInterface.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Should be added to all interfaces in plugin lib to specify their
+ * current version and optionally their action to implement the plugin.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ProvidesInterface {
+ int version();
+
+ String action() default "";
+
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/Requirements.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/Requirements.java
new file mode 100644
index 000000000000..9cfa279b9c19
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/Requirements.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 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.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Used for repeated @Requires internally, not for plugin
+ * use.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Requirements {
+ Requires[] value();
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/Requires.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/Requires.java
new file mode 100644
index 000000000000..e1b1303b8cb5
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/annotations/Requires.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 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.annotations;
+
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Used to annotate which interfaces a given plugin depends on.
+ *
+ * At minimum all plugins should have at least one @Requires annotation
+ * for the plugin interface that they are implementing. They will also
+ * need an @Requires for each class that the plugin interface @DependsOn.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Repeatable(value = Requirements.class)
+public @interface Requires {
+ Class<?> target();
+ int version();
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java
index 688df466d244..068848120103 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java
@@ -20,10 +20,12 @@ import android.app.PendingIntent;
import android.content.Context;
import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
/**
* Provides a {@link DozeUi}.
*/
+@ProvidesInterface(action = DozeProvider.ACTION, version = DozeProvider.VERSION)
public interface DozeProvider extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_DOZE";
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index e21a282581a4..b7467eba1b9c 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -14,29 +14,32 @@
package com.android.systemui.plugins.qs;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
+import com.android.systemui.plugins.FragmentBase;
+import com.android.systemui.plugins.annotations.DependsOn;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.plugins.qs.QS.Callback;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.HeightListener;
+
import android.content.Context;
import android.content.Intent;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.FrameLayout;
import android.widget.RelativeLayout;
-import com.android.systemui.plugins.FragmentBase;
-
/**
* Fragment that contains QS in the notification shade. Most of the interface is for
* handling the expand/collapsing of the view interaction.
*/
+@ProvidesInterface(action = QS.ACTION, version = QS.VERSION)
+@DependsOn(target = HeightListener.class)
+@DependsOn(target = Callback.class)
+@DependsOn(target = DetailAdapter.class)
public interface QS extends FragmentBase {
public static final String ACTION = "com.android.systemui.action.PLUGIN_QS";
- // This should be incremented any time this class or ActivityStarter or BaseStatusBarHeader
- // change in incompatible ways.
public static final int VERSION = 5;
String TAG = "QS";
@@ -64,17 +67,23 @@ public interface QS extends FragmentBase {
public abstract void setContainer(ViewGroup container);
+ @ProvidesInterface(version = HeightListener.VERSION)
public interface HeightListener {
+ public static final int VERSION = 1;
void onQsHeightChanged();
}
+ @ProvidesInterface(version = Callback.VERSION)
public interface Callback {
+ public static final int VERSION = 1;
void onShowingDetail(DetailAdapter detail, int x, int y);
void onToggleStateChanged(boolean state);
void onScanStateChanged(boolean state);
}
+ @ProvidesInterface(version = DetailAdapter.VERSION)
public interface DetailAdapter {
+ public static final int VERSION = 1;
CharSequence getTitle();
Boolean getToggleState();
default boolean getToggleEnabled() {
@@ -92,7 +101,9 @@ public interface QS extends FragmentBase {
default boolean hasHeader() { return true; }
}
+ @ProvidesInterface(version = BaseStatusBarHeader.VERSION)
public abstract static class BaseStatusBarHeader extends RelativeLayout {
+ public static final int VERSION = 1;
public BaseStatusBarHeader(Context context, AttributeSet attrs) {
super(context, attrs);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowProvider.java
index 41a0907c3228..bc98c8ec388f 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowProvider.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowProvider.java
@@ -10,7 +10,10 @@ import android.view.View;
import java.util.ArrayList;
import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+@ProvidesInterface(action = NotificationMenuRowProvider.ACTION,
+ version = NotificationMenuRowProvider.VERSION)
public interface NotificationMenuRowProvider extends Plugin {
public static final String ACTION = "com.android.systemui.action.PLUGIN_NOTIFICATION_MENU_ROW";
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
index d54e33fc4dff..5243228121c6 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
@@ -14,14 +14,15 @@
package com.android.systemui.plugins.statusbar.phone;
-import android.annotation.DrawableRes;
import android.annotation.Nullable;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewGroup;
import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+@ProvidesInterface(action = NavBarButtonProvider.ACTION, version = NavBarButtonProvider.VERSION)
public interface NavBarButtonProvider extends Plugin {
public static final String ACTION = "com.android.systemui.action.PLUGIN_NAV_BUTTON";
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
index 918d6e96784d..ddee89ed74ec 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
@@ -17,7 +17,9 @@ package com.android.systemui.plugins.statusbar.phone;
import android.view.MotionEvent;
import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+@ProvidesInterface(action = NavGesture.ACTION, version = NavBarButtonProvider.VERSION)
public interface NavGesture extends Plugin {
public static final String ACTION = "com.android.systemui.action.PLUGIN_NAV_GESTURE";
diff --git a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
index 9cc66138cfb4..ddd48330e679 100644
--- a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
@@ -53,8 +53,7 @@ public class PluginInflateContainer extends AutoReinflateContainer
private static final String TAG = "PluginInflateContainer";
- private String mAction;
- private int mVersion;
+ private Class<?> mClass;
private View mPluginView;
public PluginInflateContainer(Context context, @Nullable AttributeSet attrs) {
@@ -62,28 +61,25 @@ public class PluginInflateContainer extends AutoReinflateContainer
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PluginInflateContainer);
String viewType = a.getString(R.styleable.PluginInflateContainer_viewType);
try {
- Class c = Class.forName(viewType);
- mAction = (String) c.getDeclaredField("ACTION").get(null);
- mVersion = (int) c.getDeclaredField("VERSION").get(null);
+ mClass = Class.forName(viewType);
} catch (Exception e) {
Log.d(TAG, "Problem getting class info " + viewType, e);
- mAction = null;
- mVersion = 0;
+ mClass = null;
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- if (mAction != null) {
- Dependency.get(PluginManager.class).addPluginListener(mAction, this, mVersion);
+ if (mClass != null) {
+ Dependency.get(PluginManager.class).addPluginListener(this, mClass);
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- if (mAction != null) {
+ if (mClass != null) {
Dependency.get(PluginManager.class).removePluginListener(this);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 6caee5f2220e..be6986750804 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -36,6 +36,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.media.RingtonePlayer;
import com.android.systemui.pip.PipUI;
import com.android.systemui.plugins.OverlayPlugin;
+import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.power.PowerUI;
@@ -206,7 +207,7 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
mServices[i].onBootCompleted();
}
}
- Dependency.get(PluginManager.class).addPluginListener(OverlayPlugin.ACTION,
+ Dependency.get(PluginManager.class).addPluginListener(
new PluginListener<OverlayPlugin>() {
private ArraySet<OverlayPlugin> mOverlays;
@@ -235,7 +236,7 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
mOverlays.size() != 0);
}
- }, OverlayPlugin.VERSION, true /* Allow multiple plugins */);
+ }, OverlayPlugin.class, true /* Allow multiple plugins */);
mServicesStarted = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 94dc9a344a34..6186df14ef3f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -49,7 +49,7 @@ public class DozeService extends DreamService implements DozeMachine.Service {
}
DozeProvider provider = Dependency.get(PluginManager.class)
- .getOneShotPlugin(DozeProvider.ACTION, DozeProvider.VERSION);
+ .getOneShotPlugin(DozeProvider.class);
mDozeMachine = new DozeFactory(provider).assembleMachine(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
index 1eaca6ffd9db..03bb73da3902 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
@@ -44,8 +44,9 @@ public class PluginFragmentListener implements PluginListener<Plugin> {
mDefaultClass = defaultFragment;
}
- public void startListening(String action, int version) {
- mPluginManager.addPluginListener(action, this, version, false /* Only allow one */);
+ public void startListening() {
+ mPluginManager.addPluginListener(this, mExpectedInterface,
+ false /* Only allow one */);
}
public void stopListening() {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
index dd1614b50ca6..e895fa226cf3 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -18,12 +18,10 @@ import android.app.Notification;
import android.app.Notification.Action;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -40,6 +38,7 @@ import android.view.LayoutInflater;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.systemui.plugins.VersionInfo.InvalidVersionException;
import java.util.ArrayList;
import java.util.List;
@@ -55,7 +54,7 @@ public class PluginInstanceManager<T extends Plugin> {
private final PluginListener<T> mListener;
private final String mAction;
private final boolean mAllowMultiple;
- private final int mVersion;
+ private final VersionInfo mVersion;
@VisibleForTesting
final MainHandler mMainHandler;
@@ -66,14 +65,14 @@ public class PluginInstanceManager<T extends Plugin> {
private final PluginManager mManager;
PluginInstanceManager(Context context, String action, PluginListener<T> listener,
- boolean allowMultiple, Looper looper, int version, PluginManager manager) {
+ boolean allowMultiple, Looper looper, VersionInfo version, PluginManager manager) {
this(context, context.getPackageManager(), action, listener, allowMultiple, looper, version,
manager, Build.IS_DEBUGGABLE);
}
@VisibleForTesting
PluginInstanceManager(Context context, PackageManager pm, String action,
- PluginListener<T> listener, boolean allowMultiple, Looper looper, int version,
+ PluginListener<T> listener, boolean allowMultiple, Looper looper, VersionInfo version,
PluginManager manager, boolean debuggable) {
mMainHandler = new MainHandler(Looper.getMainLooper());
mPluginHandler = new PluginHandler(looper);
@@ -301,8 +300,14 @@ public class PluginInstanceManager<T extends Plugin> {
Context pluginContext = new PluginContextWrapper(
mContext.createApplicationContext(info, 0), classLoader);
Class<?> pluginClass = Class.forName(cls, true, classLoader);
+ // TODO: Only create the plugin before version check if we need it for
+ // legacy version check.
T plugin = (T) pluginClass.newInstance();
- if (plugin.getVersion() != mVersion) {
+ try {
+ checkVersion(pluginClass, plugin, mVersion);
+ if (DEBUG) Log.d(TAG, "createPlugin");
+ return new PluginInfo(pkg, cls, plugin, pluginContext);
+ } catch (InvalidVersionException e) {
final int icon = mContext.getResources().getIdentifier("tuner", "drawable",
mContext.getPackageName());
final int color = Resources.getSystem().getIdentifier(
@@ -318,20 +323,18 @@ public class PluginInstanceManager<T extends Plugin> {
String label = cls;
try {
label = mPm.getServiceInfo(component, 0).loadLabel(mPm).toString();
- } catch (NameNotFoundException e) {
+ } catch (NameNotFoundException e2) {
}
- if (plugin.getVersion() < mVersion) {
+ if (!e.isTooNew()) {
// Localization not required as this will never ever appear in a user build.
nb.setContentTitle("Plugin \"" + label + "\" is too old")
.setContentText("Contact plugin developer to get an updated"
- + " version.\nPlugin version: " + plugin.getVersion()
- + "\nSystem version: " + mVersion);
+ + " version.\n" + e.getMessage());
} else {
// Localization not required as this will never ever appear in a user build.
nb.setContentTitle("Plugin \"" + label + "\" is too new")
.setContentText("Check to see if an OTA is available.\n"
- + "Plugin version: " + plugin.getVersion()
- + "\nSystem version: " + mVersion);
+ + e.getMessage());
}
Intent i = new Intent(PluginManager.DISABLE_PLUGIN).setData(
Uri.parse("package://" + component.flattenToString()));
@@ -345,13 +348,24 @@ public class PluginInstanceManager<T extends Plugin> {
+ ", expected " + mVersion);
return null;
}
- if (DEBUG) Log.d(TAG, "createPlugin");
- return new PluginInfo(pkg, cls, plugin, pluginContext);
} catch (Exception e) {
Log.w(TAG, "Couldn't load plugin: " + pkg, e);
return null;
}
}
+
+ private void checkVersion(Class<?> pluginClass, T plugin, VersionInfo version)
+ throws InvalidVersionException {
+ VersionInfo pv = new VersionInfo().addClass(pluginClass);
+ if (pv.hasVersionInfo()) {
+ version.checkVersion(pv);
+ } else {
+ int fallbackVersion = plugin.getVersion();
+ if (fallbackVersion != version.getDefaultVersion()) {
+ throw new InvalidVersionException("Invalid legacy version", false);
+ }
+ }
+ }
}
public static class PluginContextWrapper extends ContextWrapper {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
index cef485e673ad..8b4bd7bc9f7b 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
@@ -33,6 +33,7 @@ import android.os.HandlerThread;
import android.os.Looper;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -40,6 +41,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
import dalvik.system.PathClassLoader;
@@ -93,7 +95,18 @@ public class PluginManager extends BroadcastReceiver {
Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
}
- public <T extends Plugin> T getOneShotPlugin(String action, int version) {
+ public <T extends Plugin> T getOneShotPlugin(Class<T> cls) {
+ ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
+ if (info == null) {
+ throw new RuntimeException(cls + " doesn't provide an interface");
+ }
+ if (TextUtils.isEmpty(info.action())) {
+ throw new RuntimeException(cls + " doesn't provide an action");
+ }
+ return getOneShotPlugin(info.action(), cls);
+ }
+
+ public <T extends Plugin> T getOneShotPlugin(String action, Class<?> cls) {
if (!isDebuggable) {
// Never ever ever allow these on production builds, they are only for prototyping.
return null;
@@ -102,7 +115,7 @@ public class PluginManager extends BroadcastReceiver {
throw new RuntimeException("Must be called from UI thread");
}
PluginInstanceManager<T> p = mFactory.createPluginInstanceManager(mContext, action, null,
- false, mBackgroundThread.getLooper(), version, this);
+ false, mBackgroundThread.getLooper(), cls, this);
mPluginPrefs.addAction(action);
PluginInfo<T> info = p.getPlugin();
if (info != null) {
@@ -114,20 +127,36 @@ public class PluginManager extends BroadcastReceiver {
return null;
}
+ public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls) {
+ addPluginListener(listener, cls, false);
+ }
+
+ public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls,
+ boolean allowMultiple) {
+ ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
+ if (info == null) {
+ throw new RuntimeException(cls + " doesn't provide an interface");
+ }
+ if (TextUtils.isEmpty(info.action())) {
+ throw new RuntimeException(cls + " doesn't provide an action");
+ }
+ addPluginListener(info.action(), listener, cls, allowMultiple);
+ }
+
public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
- int version) {
- addPluginListener(action, listener, version, false);
+ Class<?> cls) {
+ addPluginListener(action, listener, cls, false);
}
public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
- int version, boolean allowMultiple) {
+ Class cls, boolean allowMultiple) {
if (!isDebuggable) {
// 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, this);
+ allowMultiple, mBackgroundThread.getLooper(), cls, this);
p.loadAll();
mPluginMap.put(listener, p);
startListening();
@@ -282,9 +311,9 @@ public class PluginManager extends BroadcastReceiver {
public static class PluginInstanceManagerFactory {
public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
String action, PluginListener<T> listener, boolean allowMultiple, Looper looper,
- int version, PluginManager manager) {
+ Class<?> cls, PluginManager manager) {
return new PluginInstanceManager(context, action, listener, allowMultiple, looper,
- version, manager);
+ new VersionInfo().addClass(cls), manager);
}
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginPrefs.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginPrefs.java
index 3671b3c1689f..3671b3c1689f 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginPrefs.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginPrefs.java
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java b/packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java
new file mode 100644
index 000000000000..84f7761a8043
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 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 com.android.systemui.plugins.annotations.Dependencies;
+import com.android.systemui.plugins.annotations.DependsOn;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.plugins.annotations.Requirements;
+import com.android.systemui.plugins.annotations.Requires;
+
+import android.util.ArrayMap;
+
+public class VersionInfo {
+
+ private final ArrayMap<Class<?>, Version> mVersions = new ArrayMap<>();
+ private Class<?> mDefault;
+
+ public boolean hasVersionInfo() {
+ return !mVersions.isEmpty();
+ }
+
+ public int getDefaultVersion() {
+ return mVersions.get(mDefault).mVersion;
+ }
+
+ public VersionInfo addClass(Class<?> cls) {
+ if (mDefault == null) {
+ // The legacy default version is from the first class we add.
+ mDefault = cls;
+ }
+ addClass(cls, false);
+ return this;
+ }
+
+ private void addClass(Class<?> cls, boolean required) {
+ ProvidesInterface provider = cls.getDeclaredAnnotation(ProvidesInterface.class);
+ if (provider != null) {
+ mVersions.put(cls, new Version(provider.version(), true));
+ }
+ Requires requires = cls.getDeclaredAnnotation(Requires.class);
+ if (requires != null) {
+ mVersions.put(requires.target(), new Version(requires.version(), required));
+ }
+ Requirements requirements = cls.getDeclaredAnnotation(Requirements.class);
+ if (requirements != null) {
+ for (Requires r : requirements.value()) {
+ mVersions.put(r.target(), new Version(r.version(), required));
+ }
+ }
+ DependsOn depends = cls.getDeclaredAnnotation(DependsOn.class);
+ if (depends != null) {
+ addClass(depends.target(), true);
+ }
+ Dependencies dependencies = cls.getDeclaredAnnotation(Dependencies.class);
+ if (dependencies != null) {
+ for (DependsOn d : dependencies.value()) {
+ addClass(d.target(), true);
+ }
+ }
+ }
+
+ public void checkVersion(VersionInfo plugin) throws InvalidVersionException {
+ ArrayMap<Class<?>, Version> versions = new ArrayMap<>(mVersions);
+ plugin.mVersions.forEach((aClass, version) -> {
+ Version v = versions.remove(aClass);
+ if (v == null) {
+ v = createVersion(aClass);
+ }
+ if (v == null) {
+ throw new InvalidVersionException(aClass.getSimpleName()
+ + " does not provide an interface", false);
+ }
+ if (v.mVersion != version.mVersion) {
+ throw new InvalidVersionException(aClass, v.mVersion < version.mVersion, v.mVersion,
+ version.mVersion);
+ }
+ });
+ versions.forEach((aClass, version) -> {
+ if (version.mRequired) {
+ throw new InvalidVersionException("Missing required dependency "
+ + aClass.getSimpleName(), false);
+ }
+ });
+ }
+
+ private Version createVersion(Class<?> cls) {
+ ProvidesInterface provider = cls.getDeclaredAnnotation(ProvidesInterface.class);
+ if (provider != null) {
+ return new Version(provider.version(), false);
+ }
+ return null;
+ }
+
+ public static class InvalidVersionException extends RuntimeException {
+ private final boolean mTooNew;
+
+ public InvalidVersionException(String str, boolean tooNew) {
+ super(str);
+ mTooNew = tooNew;
+ }
+
+ public InvalidVersionException(Class<?> cls, boolean tooNew, int expected, int actual) {
+ super(cls.getSimpleName() + " expected version " + expected + " but had " + actual);
+ mTooNew = tooNew;
+ }
+
+ public boolean isTooNew() {
+ return mTooNew;
+ }
+ }
+
+ private static class Version {
+
+ private final int mVersion;
+ private final boolean mRequired;
+
+ public Version(int version, boolean required) {
+ mVersion = version;
+ mRequired = required;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 504678c7f1c5..1569b0ca0249 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -86,6 +86,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
setOrientation(VERTICAL);
+ mBrightnessView = LayoutInflater.from(context).inflate(
+ R.layout.quick_settings_brightness_dialog, this, false);
+ addView(mBrightnessView);
+
setupTileLayout();
mFooter = new QSFooter(this, context);
@@ -100,10 +104,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
updateResources();
- mBrightnessView = LayoutInflater.from(context).inflate(
- R.layout.quick_settings_brightness_dialog, this, false);
- addView(mBrightnessView);
-
mBrightnessController = new BrightnessController(getContext(),
(ImageView) findViewById(R.id.brightness_icon),
(ToggleSliderView) findViewById(R.id.brightness_slider));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
index 355022f9794c..534a71936b5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
@@ -90,8 +90,7 @@ public class NotificationMenuRow extends FrameLayout
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Dependency.get(PluginManager.class).addPluginListener(
- NotificationMenuRowProvider.ACTION, this,
- NotificationMenuRowProvider.VERSION, false /* Allow multiple */);
+ this, NotificationMenuRowProvider.class, false /* Allow multiple */);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 2836f41b04f5..2b335f44b485 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -261,9 +261,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
super.onAttachedToWindow();
mAccessibilityController.addStateChangedCallback(this);
Dependency.get(PluginManager.class).addPluginListener(RIGHT_BUTTON_PLUGIN,
- mRightListener, IntentButtonProvider.VERSION, false /* Only allow one */);
+ mRightListener, IntentButtonProvider.class, false /* Only allow one */);
Dependency.get(PluginManager.class).addPluginListener(LEFT_BUTTON_PLUGIN,
- mLeftListener, IntentButtonProvider.VERSION, false /* Only allow one */);
+ mLeftListener, IntentButtonProvider.class, false /* Only allow one */);
Dependency.get(TunerService.class).addTunable(this, LockscreenFragment.LOCKSCREEN_LEFT_BUTTON,
LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 5fb99dabfeab..720ca1499bf1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -138,8 +138,8 @@ public class NavigationBarInflaterView extends FrameLayout
super.onAttachedToWindow();
Dependency.get(TunerService.class).addTunable(this, NAV_BAR_VIEWS, NAV_BAR_LEFT,
NAV_BAR_RIGHT);
- Dependency.get(PluginManager.class).addPluginListener(NavBarButtonProvider.ACTION, this,
- NavBarButtonProvider.VERSION, true /* Allow multiple */);
+ Dependency.get(PluginManager.class).addPluginListener(this,
+ NavBarButtonProvider.class, true /* Allow multiple */);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 5d13289ef9cc..ad875f13d27e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -783,8 +783,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
protected void onAttachedToWindow() {
super.onAttachedToWindow();
onPluginDisconnected(null); // Create default gesture helper
- Dependency.get(PluginManager.class).addPluginListener(NavGesture.ACTION, this,
- NavGesture.VERSION, false /* Only one */);
+ Dependency.get(PluginManager.class).addPluginListener(this,
+ NavGesture.class, false /* Only one */);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ac13cf4eb111..55d66ee03e08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1129,7 +1129,7 @@ public class StatusBar extends SystemUI implements DemoMode,
.replace(R.id.qs_frame, new QSFragment(), QS.TAG)
.commit();
new PluginFragmentListener(container, QS.TAG, QSFragment.class, QS.class)
- .startListening(QS.ACTION, QS.VERSION);
+ .startListening();
final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
mIconController);
mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
index 3715df2a42c0..658966cdde17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
@@ -17,14 +17,27 @@ package com.android.systemui.plugins;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
-
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
+import com.android.systemui.plugins.VersionInfo.InvalidVersionException;
+import com.android.systemui.plugins.annotations.Requires;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
import android.app.Activity;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
@@ -35,7 +48,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.HandlerThread;
@@ -44,17 +56,6 @@ import android.support.test.annotation.UiThreadTest;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
-
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -72,6 +73,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
private PluginListener mMockListener;
private PluginInstanceManager mPluginInstanceManager;
private PluginManager mMockManager;
+ private VersionInfo mMockVersionInfo;
@Before
public void setup() throws Exception {
@@ -83,8 +85,10 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
mMockManager = mock(PluginManager.class);
when(mMockManager.getClassLoader(any(), any()))
.thenReturn(getClass().getClassLoader());
+ mMockVersionInfo = mock(VersionInfo.class);
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
- mMockListener, true, mHandlerThread.getLooper(), 1, mMockManager, true);
+ mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
+ mMockManager, true);
sMockPlugin = mock(Plugin.class);
when(sMockPlugin.getVersion()).thenReturn(1);
}
@@ -145,7 +149,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
NotificationManager nm = mock(NotificationManager.class);
mContext.addMockSystemService(Context.NOTIFICATION_SERVICE, nm);
setupFakePmQuery();
- when(sMockPlugin.getVersion()).thenReturn(2);
+ doThrow(new InvalidVersionException("", false)).when(mMockVersionInfo).checkVersion(any());
mPluginInstanceManager.loadAll();
@@ -181,7 +185,8 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
public void testNonDebuggable() throws Exception {
// Create a version that thinks the build is not debuggable.
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
- mMockListener, true, mHandlerThread.getLooper(), 1, mMockManager, false);
+ mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
+ mMockManager, false);
setupFakePmQuery();
mPluginInstanceManager.loadAll();
@@ -270,6 +275,9 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
}
}
+ // This target class doesn't matter, it just needs to have a Requires to hit the flow where
+ // the mock version info is called.
+ @Requires(target = PluginManagerTest.class, version = 1)
public static class TestPlugin implements Plugin {
@Override
public int getVersion() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index a58407b2ae23..09ac5a633cb0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -32,6 +32,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
import com.android.systemui.plugins.PluginManager.PluginInstanceManagerFactory;
@@ -63,7 +64,7 @@ public class PluginManagerTest extends SysuiTestCase {
mMockFactory = mock(PluginInstanceManagerFactory.class);
mMockPluginInstance = mock(PluginInstanceManager.class);
when(mMockFactory.createPluginInstanceManager(Mockito.any(), Mockito.any(), Mockito.any(),
- Mockito.anyBoolean(), Mockito.any(), Mockito.anyInt(), Mockito.any()))
+ Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.any()))
.thenReturn(mMockPluginInstance);
mPluginManager = new PluginManager(getContext(), mMockFactory, true, mMockExceptionHandler);
resetExceptionHandler();
@@ -76,20 +77,20 @@ public class PluginManagerTest extends SysuiTestCase {
Plugin mockPlugin = mock(Plugin.class);
when(mMockPluginInstance.getPlugin()).thenReturn(new PluginInfo(null, null, mockPlugin,
null));
- Plugin result = mPluginManager.getOneShotPlugin("myAction", 1);
+ Plugin result = mPluginManager.getOneShotPlugin("myAction", TestPlugin.class);
assertTrue(result == mockPlugin);
}
@Test
public void testAddListener() {
- mPluginManager.addPluginListener("myAction", mMockListener, 1);
+ mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
verify(mMockPluginInstance).loadAll();
}
@Test
public void testRemoveListener() {
- mPluginManager.addPluginListener("myAction", mMockListener, 1);
+ mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
mPluginManager.removePluginListener(mMockListener);
verify(mMockPluginInstance).destroy();
@@ -101,16 +102,16 @@ public class PluginManagerTest extends SysuiTestCase {
mMockExceptionHandler);
resetExceptionHandler();
- mPluginManager.addPluginListener("myAction", mMockListener, 1);
+ mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
verify(mMockPluginInstance, Mockito.never()).loadAll();
- assertNull(mPluginManager.getOneShotPlugin("myPlugin", 1));
+ assertNull(mPluginManager.getOneShotPlugin("myPlugin", TestPlugin.class));
verify(mMockPluginInstance, Mockito.never()).getPlugin();
}
@Test
public void testExceptionHandler_foundPlugin() {
- mPluginManager.addPluginListener("myAction", mMockListener, 1);
+ mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
when(mMockPluginInstance.checkAndDisable(Mockito.any())).thenReturn(true);
mPluginExceptionHandler.uncaughtException(Thread.currentThread(), new Throwable());
@@ -125,7 +126,7 @@ public class PluginManagerTest extends SysuiTestCase {
@Test
public void testExceptionHandler_noFoundPlugin() {
- mPluginManager.addPluginListener("myAction", mMockListener, 1);
+ mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
when(mMockPluginInstance.checkAndDisable(Mockito.any())).thenReturn(false);
mPluginExceptionHandler.uncaughtException(Thread.currentThread(), new Throwable());
@@ -161,4 +162,10 @@ public class PluginManagerTest extends SysuiTestCase {
// Set back the real exception handler so the test can crash if it wants to.
Thread.setDefaultUncaughtExceptionHandler(mRealExceptionHandler);
}
+
+ @ProvidesInterface(action = TestPlugin.ACTION, version = TestPlugin.VERSION)
+ public static interface TestPlugin extends Plugin {
+ public static final String ACTION = "testAction";
+ public static final int VERSION = 1;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/VersionInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/VersionInfoTest.java
new file mode 100644
index 000000000000..0d87d6b06c4e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/VersionInfoTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 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 static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.VersionInfo.InvalidVersionException;
+import com.android.systemui.plugins.annotations.Requires;
+import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.plugins.qs.QS.Callback;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.HeightListener;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class VersionInfoTest extends SysuiTestCase {
+
+ @Rule
+ public ExpectedException mThrown = ExpectedException.none();
+
+ @Test
+ public void testHasInfo() {
+ VersionInfo info = new VersionInfo();
+ info.addClass(VersionInfoTest.class); // Has no annotations.
+ assertFalse(info.hasVersionInfo());
+
+ info.addClass(OverlayPlugin.class);
+ assertTrue(info.hasVersionInfo());
+ }
+
+ @Test
+ public void testSingleProvides() {
+ VersionInfo overlay = new VersionInfo().addClass(OverlayPlugin.class);
+ VersionInfo impl = new VersionInfo().addClass(OverlayImpl.class);
+ overlay.checkVersion(impl);
+ }
+
+ @Test
+ public void testIncorrectVersion() {
+ VersionInfo overlay = new VersionInfo().addClass(OverlayPlugin.class);
+ VersionInfo impl = new VersionInfo().addClass(OverlayImplIncorrectVersion.class);
+ mThrown.expect(InvalidVersionException.class);
+ overlay.checkVersion(impl);
+ }
+
+ @Test
+ public void testMissingRequired() {
+ VersionInfo overlay = new VersionInfo().addClass(OverlayPlugin.class);
+ VersionInfo impl = new VersionInfo();
+ mThrown.expect(InvalidVersionException.class);
+ overlay.checkVersion(impl);
+ }
+
+ @Test
+ public void testMissingDependencies() {
+ VersionInfo overlay = new VersionInfo().addClass(QS.class);
+ VersionInfo impl = new VersionInfo().addClass(QSImplNoDeps.class);
+ mThrown.expect(InvalidVersionException.class);
+ overlay.checkVersion(impl);
+ }
+
+ @Test
+ public void testHasDependencies() {
+ VersionInfo overlay = new VersionInfo().addClass(QS.class);
+ VersionInfo impl = new VersionInfo().addClass(QSImpl.class);
+ overlay.checkVersion(impl);
+ }
+
+ @Requires(target = OverlayPlugin.class, version = OverlayPlugin.VERSION)
+ public static class OverlayImpl {
+ }
+
+ @Requires(target = OverlayPlugin.class, version = 0)
+ public static class OverlayImplIncorrectVersion {
+ }
+
+ @Requires(target = QS.class, version = QS.VERSION)
+ public static class QSImplNoDeps {
+ }
+
+ @Requires(target = QS.class, version = QS.VERSION)
+ @Requires(target = Callback.class, version = Callback.VERSION)
+ @Requires(target = HeightListener.class, version = HeightListener.VERSION)
+ @Requires(target = DetailAdapter.class, version = DetailAdapter.VERSION)
+ public static class QSImpl {
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
index d1abccaa6e76..59a93618cdb1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
@@ -31,13 +31,7 @@ public class FakePluginManager extends PluginManager {
@Override
public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
- int version) {
- mLeakChecker.addCallback(listener);
- }
-
- @Override
- public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
- int version, boolean allowMultiple) {
+ Class cls, boolean allowMultiple) {
mLeakChecker.addCallback(listener);
}
@@ -47,7 +41,7 @@ public class FakePluginManager extends PluginManager {
}
@Override
- public <T extends Plugin> T getOneShotPlugin(String action, int version) {
+ public <T extends Plugin> T getOneShotPlugin(String action, Class<?> cls) {
return null;
}
}