QS: Don't use ComponentName to identify tiles
Evidently some apps redirect/obscure tiles in a way that makes
creating a ComponentName from the TileService useless. Instead
generate a token which will be a much more stable way of identifying
tiles henceforth.
Change-Id: Id68550bcdcdc3e3987f09380f258610e7a5aca85
Fixes: 29121793
diff --git a/core/java/android/service/quicksettings/IQSService.aidl b/core/java/android/service/quicksettings/IQSService.aidl
index bf96357..d03ff93 100644
--- a/core/java/android/service/quicksettings/IQSService.aidl
+++ b/core/java/android/service/quicksettings/IQSService.aidl
@@ -23,16 +23,16 @@
* @hide
*/
interface IQSService {
- Tile getTile(in ComponentName component);
- void updateQsTile(in Tile tile);
- void updateStatusIcon(in Tile tile, in Icon icon,
+ Tile getTile(in IBinder tile);
+ void updateQsTile(in Tile tile, in IBinder service);
+ void updateStatusIcon(in IBinder tile, in Icon icon,
String contentDescription);
- void onShowDialog(in Tile tile);
- void onStartActivity(in Tile tile);
+ void onShowDialog(in IBinder tile);
+ void onStartActivity(in IBinder tile);
boolean isLocked();
boolean isSecure();
- void startUnlockAndRun(in Tile tile);
+ void startUnlockAndRun(in IBinder tile);
- void onDialogHidden(in Tile tile);
- void onStartSuccessful(in Tile tile);
+ void onDialogHidden(in IBinder tile);
+ void onStartSuccessful(in IBinder tile);
}
diff --git a/core/java/android/service/quicksettings/Tile.java b/core/java/android/service/quicksettings/Tile.java
index 3d7d53e..4b81a72 100644
--- a/core/java/android/service/quicksettings/Tile.java
+++ b/core/java/android/service/quicksettings/Tile.java
@@ -15,8 +15,8 @@
*/
package android.service.quicksettings;
-import android.content.ComponentName;
import android.graphics.drawable.Icon;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -59,7 +59,7 @@
*/
public static final int STATE_ACTIVE = 2;
- private ComponentName mComponentName;
+ private IBinder mToken;
private Icon mIcon;
private CharSequence mLabel;
private CharSequence mContentDescription;
@@ -78,29 +78,15 @@
/**
* @hide
*/
- public Tile(ComponentName componentName) {
- mComponentName = componentName;
+ public Tile() {
}
/**
* @hide
*/
- public void setService(IQSService service) {
+ public void setService(IQSService service, IBinder stub) {
mService = service;
- }
-
- /**
- * @hide
- */
- public ComponentName getComponentName() {
- return mComponentName;
- }
-
- /**
- * @hide
- */
- public IQSService getQsService() {
- return mService;
+ mToken = stub;
}
/**
@@ -193,7 +179,7 @@
*/
public void updateTile() {
try {
- mService.updateQsTile(this);
+ mService.updateQsTile(this, mToken);
} catch (RemoteException e) {
Log.e(TAG, "Couldn't update tile");
}
@@ -201,12 +187,6 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- if (mComponentName != null) {
- dest.writeByte((byte) 1);
- mComponentName.writeToParcel(dest, flags);
- } else {
- dest.writeByte((byte) 0);
- }
if (mIcon != null) {
dest.writeByte((byte) 1);
mIcon.writeToParcel(dest, flags);
@@ -220,11 +200,6 @@
private void readFromParcel(Parcel source) {
if (source.readByte() != 0) {
- mComponentName = ComponentName.CREATOR.createFromParcel(source);
- } else {
- mComponentName = null;
- }
- if (source.readByte() != 0) {
mIcon = Icon.CREATOR.createFromParcel(source);
} else {
mIcon = null;
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 50411ab..887f4b6 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -123,6 +123,11 @@
/**
* @hide
*/
+ public static final String EXTRA_TOKEN = "token";
+
+ /**
+ * @hide
+ */
public static final String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
private final H mHandler = new H(Looper.getMainLooper());
@@ -132,6 +137,7 @@
private IBinder mToken;
private IQSService mService;
private Runnable mUnlockRunnable;
+ private IBinder mTileToken;
@Override
public void onDestroy() {
@@ -197,7 +203,7 @@
public final void setStatusIcon(Icon icon, String contentDescription) {
if (mService != null) {
try {
- mService.updateStatusIcon(mTile, icon, contentDescription);
+ mService.updateStatusIcon(mTileToken, icon, contentDescription);
} catch (RemoteException e) {
}
}
@@ -224,14 +230,14 @@
@Override
public void onViewDetachedFromWindow(View v) {
try {
- mService.onDialogHidden(getQsTile());
+ mService.onDialogHidden(mTileToken);
} catch (RemoteException e) {
}
}
});
dialog.show();
try {
- mService.onShowDialog(mTile);
+ mService.onShowDialog(mTileToken);
} catch (RemoteException e) {
}
}
@@ -246,7 +252,7 @@
public final void unlockAndRun(Runnable runnable) {
mUnlockRunnable = runnable;
try {
- mService.startUnlockAndRun(mTile);
+ mService.startUnlockAndRun(mTileToken);
} catch (RemoteException e) {
}
}
@@ -292,7 +298,7 @@
public final void startActivityAndCollapse(Intent intent) {
startActivity(intent);
try {
- mService.onStartActivity(mTile);
+ mService.onStartActivity(mTileToken);
} catch (RemoteException e) {
}
}
@@ -311,14 +317,14 @@
@Override
public IBinder onBind(Intent intent) {
mService = IQSService.Stub.asInterface(intent.getIBinderExtra(EXTRA_SERVICE));
+ mTileToken = intent.getIBinderExtra(EXTRA_TOKEN);
try {
- ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT);
- mTile = mService.getTile(component);
+ mTile = mService.getTile(mTileToken);
} catch (RemoteException e) {
throw new RuntimeException("Unable to reach IQSService", e);
}
if (mTile != null) {
- mTile.setService(mService);
+ mTile.setService(mService, mTileToken);
mHandler.sendEmptyMessage(H.MSG_START_SUCCESS);
}
return new IQSTileService.Stub() {
@@ -403,7 +409,7 @@
break;
case MSG_START_SUCCESS:
try {
- mService.onStartSuccessful(mTile);
+ mService.onStartSuccessful(mTileToken);
} catch (RemoteException e) {
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 569a567..b36221d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -71,7 +71,7 @@
super(host);
mWindowManager = WindowManagerGlobal.getWindowManagerService();
mComponent = ComponentName.unflattenFromString(action);
- mTile = new Tile(mComponent);
+ mTile = new Tile();
setTileIcon();
mServiceManager = host.getTileServices().getTileWrapper(this);
mService = mServiceManager.getTileService();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
index 407453c..451e1f6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
@@ -94,4 +94,8 @@
return false;
}
}
+
+ public IQSTileService getService() {
+ return mService;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 79f9de6..681005c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -26,6 +26,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.net.Uri;
+import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -37,6 +38,7 @@
import android.support.annotation.VisibleForTesting;
import android.util.ArraySet;
import android.util.Log;
+
import libcore.util.Objects;
import java.util.Set;
@@ -67,6 +69,7 @@
private final Handler mHandler;
private final Intent mIntent;
private final UserHandle mUser;
+ private final IBinder mToken = new Binder();
private Set<Integer> mQueuedMessages = new ArraySet<>();
private QSTileServiceWrapper mWrapper;
@@ -88,7 +91,7 @@
mHandler = handler;
mIntent = intent;
mIntent.putExtra(TileService.EXTRA_SERVICE, service.asBinder());
- mIntent.putExtra(TileService.EXTRA_COMPONENT, intent.getComponent());
+ mIntent.putExtra(TileService.EXTRA_TOKEN, mToken);
mUser = user;
if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser);
}
@@ -396,6 +399,10 @@
handleDeath();
}
+ public IBinder getToken() {
+ return mToken;
+ }
+
public interface TileChangeListener {
void onTileChanged(ComponentName tile);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index 3d030f9..f3e4d60 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -25,6 +25,7 @@
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Handler;
+import android.os.IBinder;
import android.os.UserHandle;
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
@@ -32,6 +33,7 @@
import android.support.annotation.VisibleForTesting;
import android.util.Log;
+import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
import java.util.List;
@@ -106,6 +108,10 @@
return mStateManager;
}
+ public IBinder getToken() {
+ return mStateManager.getToken();
+ }
+
public void setBindRequested(boolean bindRequested) {
if (mBindRequested == bindRequested) return;
mBindRequested = bindRequested;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 6f0bed2..575f198 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -25,10 +25,12 @@
import android.graphics.drawable.Icon;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
import android.util.ArrayMap;
@@ -52,6 +54,7 @@
private final ArrayMap<CustomTile, TileServiceManager> mServices = new ArrayMap<>();
private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>();
+ private final ArrayMap<IBinder, CustomTile> mTokenMap = new ArrayMap<>();
private final Context mContext;
private final Handler mHandler;
private final Handler mMainHandler;
@@ -82,6 +85,7 @@
synchronized (mServices) {
mServices.put(tile, service);
mTiles.put(component, tile);
+ mTokenMap.put(service.getToken(), tile);
}
return service;
}
@@ -95,6 +99,7 @@
service.setBindAllowed(false);
service.handleDestroy();
mServices.remove(tile);
+ mTokenMap.remove(service.getToken());
mTiles.remove(tile.getComponent());
final String slot = tile.getComponent().getClassName();
mMainHandler.post(new Runnable() {
@@ -138,8 +143,9 @@
}
}
- private void verifyCaller(String packageName) {
+ private void verifyCaller(CustomTile tile) {
try {
+ String packageName = tile.getComponent().getPackageName();
int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
Binder.getCallingUserHandle().getIdentifier());
if (Binder.getCallingUid() != uid) {
@@ -170,10 +176,9 @@
}
@Override
- public void updateQsTile(Tile tile) {
- ComponentName componentName = tile.getComponentName();
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public void updateQsTile(Tile tile, IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
synchronized (mServices) {
final TileServiceManager tileServiceManager = mServices.get(customTile);
@@ -186,10 +191,9 @@
}
@Override
- public void onStartSuccessful(Tile tile) {
- ComponentName componentName = tile.getComponentName();
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public void onStartSuccessful(IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
synchronized (mServices) {
final TileServiceManager tileServiceManager = mServices.get(customTile);
@@ -200,10 +204,9 @@
}
@Override
- public void onShowDialog(Tile tile) {
- ComponentName componentName = tile.getComponentName();
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public void onShowDialog(IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
customTile.onDialogShown();
mHost.collapsePanels();
@@ -212,10 +215,9 @@
}
@Override
- public void onDialogHidden(Tile tile) {
- ComponentName componentName = tile.getComponentName();
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public void onDialogHidden(IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
mServices.get(customTile).setShowingDialog(false);
customTile.onDialogHidden();
@@ -223,23 +225,22 @@
}
@Override
- public void onStartActivity(Tile tile) {
- ComponentName componentName = tile.getComponentName();
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public void onStartActivity(IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
mHost.collapsePanels();
}
}
@Override
- public void updateStatusIcon(Tile tile, Icon icon, String contentDescription) {
- final ComponentName componentName = tile.getComponentName();
- String packageName = componentName.getPackageName();
- verifyCaller(packageName);
- CustomTile customTile = getTileForComponent(componentName);
+ public void updateStatusIcon(IBinder token, Icon icon, String contentDescription) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
try {
+ ComponentName componentName = customTile.getComponent();
+ String packageName = componentName.getPackageName();
UserHandle userHandle = getCallingUserHandle();
PackageInfo info = mContext.getPackageManager().getPackageInfoAsUser(packageName, 0,
userHandle.getIdentifier());
@@ -263,9 +264,9 @@
}
@Override
- public Tile getTile(ComponentName componentName) {
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public Tile getTile(IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
return customTile.getQsTile();
}
@@ -273,10 +274,9 @@
}
@Override
- public void startUnlockAndRun(Tile tile) {
- ComponentName componentName = tile.getComponentName();
- verifyCaller(componentName.getPackageName());
- CustomTile customTile = getTileForComponent(componentName);
+ public void startUnlockAndRun(IBinder token) {
+ CustomTile customTile = getTileForToken(token);
+ verifyCaller(customTile);
if (customTile != null) {
customTile.startUnlockAndRun();
}
@@ -294,6 +294,12 @@
return keyguardMonitor.isSecure() && keyguardMonitor.isShowing();
}
+ private CustomTile getTileForToken(IBinder token) {
+ synchronized (mServices) {
+ return mTokenMap.get(token);
+ }
+ }
+
private CustomTile getTileForComponent(ComponentName component) {
synchronized (mServices) {
return mTiles.get(component);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 011ec22..1894821 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -407,7 +407,7 @@
ComponentName component = CustomTile.getComponentFromSpec(tileSpec);
Intent intent = new Intent().setComponent(component);
TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
- mContext, mServices, new Tile(component), intent,
+ mContext, mServices, new Tile(), intent,
new UserHandle(ActivityManager.getCurrentUser()));
lifecycleManager.onStopListening();
lifecycleManager.onTileRemoved();
@@ -421,7 +421,7 @@
ComponentName component = CustomTile.getComponentFromSpec(tileSpec);
Intent intent = new Intent().setComponent(component);
TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
- mContext, mServices, new Tile(component), intent,
+ mContext, mServices, new Tile(), intent,
new UserHandle(ActivityManager.getCurrentUser()));
lifecycleManager.onTileAdded();
lifecycleManager.flushMessagesAndUnbind();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
index c93377a..7703c58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
@@ -58,7 +58,7 @@
mHandler = new Handler(mThread.getLooper());
ComponentName component = new ComponentName(mContext, FakeTileService.class);
mStateManager = new TileLifecycleManager(mHandler, getContext(),
- Mockito.mock(IQSService.class), new Tile(component),
+ Mockito.mock(IQSService.class), new Tile(),
new Intent().setComponent(component),
new UserHandle(UserHandle.myUserId()));
mCallbacks.clear();