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();