OSDN Git Service

Add API for System QS tiles to set status icons
authorJason Monk <jmonk@google.com>
Wed, 6 Jan 2016 13:51:26 +0000 (08:51 -0500)
committerJason Monk <jmonk@google.com>
Fri, 8 Jan 2016 13:54:13 +0000 (08:54 -0500)
Allow system apps that have a Quick Settings tile to show a
status bar icon.  If the quick settings tile is removed, the
status bar icon will no longer be shown.

Change-Id: I875b962bbdf4ff863012de688a3dd29a8d7e11ab

12 files changed:
api/system-current.txt
core/java/android/service/quicksettings/IQSService.aidl
core/java/android/service/quicksettings/TileService.java
packages/SystemUI/src/com/android/systemui/qs/QSTile.java
packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java

index 2779348..31d9d74 100644 (file)
@@ -35845,6 +35845,7 @@ package android.service.quicksettings {
     method public int onTileAdded();
     method public void onTileRemoved();
     method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
+    method public final void setStatusIcon(android.graphics.drawable.Icon, java.lang.String);
     method public final void showDialog(android.app.Dialog);
     field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
     field public static final int TILE_MODE_ACTIVE = 2; // 0x2
index 75da82f..9991d41 100644 (file)
@@ -16,6 +16,7 @@
 package android.service.quicksettings;
 
 import android.content.ComponentName;
+import android.graphics.drawable.Icon;
 import android.service.quicksettings.Tile;
 
 /**
@@ -23,6 +24,8 @@ import android.service.quicksettings.Tile;
  */
 interface IQSService {
     void updateQsTile(in Tile tile);
+    void updateStatusIcon(in Tile tile, in Icon icon,
+            String contentDescription);
     void onShowDialog(in Tile tile);
     void setTileMode(in ComponentName component, int mode);
 }
index 9b50ef5..6b12193 100644 (file)
 package android.service.quicksettings;
 
 import android.Manifest;
+import android.annotation.SystemApi;
 import android.app.Dialog;
 import android.app.Service;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.drawable.Icon;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -172,6 +174,26 @@ public class TileService extends Service {
     }
 
     /**
+     * Sets an icon to be shown in the status bar.
+     * <p>
+     * The icon will be displayed before all other icons.  Can only be called between
+     * {@link #onStartListening} and {@link #onStopListening}.  Can only be called by system apps.
+     *
+     * @param icon The icon to be displayed, null to hide
+     * @param contentDescription Content description of the icon to be displayed
+     * @hide
+     */
+    @SystemApi
+    public final void setStatusIcon(Icon icon, String contentDescription) {
+        if (mService != null) {
+            try {
+                mService.updateStatusIcon(mTile, icon, contentDescription);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
      * Used to show a dialog.
      *
      * This will collapse the Quick Settings panel and show the dialog.
index 1a36abd..b6776bb 100644 (file)
@@ -28,6 +28,7 @@ import android.util.SparseArray;
 import android.view.View;
 import android.view.ViewGroup;
 import com.android.systemui.qs.QSTile.State;
+import com.android.systemui.qs.external.TileServices;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
@@ -349,8 +350,10 @@ public abstract class QSTile<TState extends State> implements Listenable {
         UserSwitcherController getUserSwitcherController();
         UserInfoController getUserInfoController();
         BatteryController getBatteryController();
+        TileServices getTileServices();
         void removeTile(String tileSpec);
 
+
         public interface Callback {
             void onTilesChanged();
         }
index 2e5a0b2..eefff30 100644 (file)
@@ -132,6 +132,7 @@ public class CustomTile extends QSTile<QSTile.State> {
             } catch (RemoteException e) {
             }
         }
+        mHost.getTileServices().freeService(this, mServiceManager);
     }
 
     @Override
index 7403ae0..a831c87 100644 (file)
@@ -20,17 +20,22 @@ import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.graphics.drawable.Icon;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.service.quicksettings.IQSService;
 import android.service.quicksettings.Tile;
 import android.service.quicksettings.TileService;
 import android.util.ArrayMap;
 import android.util.Log;
+import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -47,6 +52,7 @@ public class TileServices extends IQSService.Stub {
     private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>();
     private final Context mContext;
     private final Handler mHandler;
+    private final Handler mMainHandler;
     private final QSTileHost mHost;
 
     private int mMaxBound = DEFAULT_MAX_BOUND;
@@ -57,6 +63,7 @@ public class TileServices extends IQSService.Stub {
         mContext.registerReceiver(mRequestListeningReceiver,
                 new IntentFilter(TileService.ACTION_REQUEST_LISTENING));
         mHandler = new Handler(looper);
+        mMainHandler = new Handler(Looper.getMainLooper());
     }
 
     public Context getContext() {
@@ -82,6 +89,13 @@ public class TileServices extends IQSService.Stub {
             service.setBindAllowed(false);
             mServices.remove(tile);
             mTiles.remove(tile.getComponent());
+            final String slot = tile.getComponent().getClassName();
+            mMainHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mHost.getIconController().removeIcon(slot);
+                }
+            });
         }
     }
 
@@ -161,8 +175,9 @@ public class TileServices extends IQSService.Stub {
 
     @Override
     public void updateQsTile(Tile tile) {
-        verifyCaller(tile.getComponentName().getPackageName());
-        CustomTile customTile = getTileForComponent(tile.getComponentName());
+        ComponentName componentName = tile.getComponentName();
+        verifyCaller(componentName.getPackageName());
+        CustomTile customTile = getTileForComponent(componentName);
         if (customTile != null) {
             synchronized (mServices) {
                 mServices.get(customTile).setLastUpdate(System.currentTimeMillis());
@@ -174,14 +189,45 @@ public class TileServices extends IQSService.Stub {
 
     @Override
     public void onShowDialog(Tile tile) {
-        verifyCaller(tile.getComponentName().getPackageName());
-        CustomTile customTile = getTileForComponent(tile.getComponentName());
+        ComponentName componentName = tile.getComponentName();
+        verifyCaller(componentName.getPackageName());
+        CustomTile customTile = getTileForComponent(componentName);
         if (customTile != null) {
             customTile.onDialogShown();
             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);
+        if (customTile != null) {
+            try {
+                UserHandle userHandle = getCallingUserHandle();
+                PackageInfo info = mContext.getPackageManager().getPackageInfoAsUser(packageName, 0,
+                        userHandle.getIdentifier());
+                if (info.applicationInfo.isSystemApp()) {
+                    final StatusBarIcon statusIcon = icon != null
+                            ? new StatusBarIcon(userHandle, packageName, icon, 0, 0,
+                                    contentDescription)
+                            : null;
+                    mMainHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            StatusBarIconController iconController = mHost.getIconController();
+                            iconController.setIcon(componentName.getClassName(), statusIcon);
+                            iconController.setExternalIcon(componentName.getClassName());
+                        }
+                    });
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+            }
+        }
+    }
+
     private CustomTile getTileForComponent(ComponentName component) {
         synchronized (mServices) {
             return mTiles.get(component);
index db2415a..de7a8db 100644 (file)
@@ -30,8 +30,6 @@ import android.util.AttributeSet;
 import android.util.Log;
 import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
-import android.widget.ImageView;
-
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.R;
 
@@ -76,7 +74,7 @@ public class StatusBarIconView extends AnimatedImageView {
             setScaleY(scale);
         }
 
-        setScaleType(ImageView.ScaleType.CENTER);
+        setScaleType(ScaleType.CENTER);
     }
 
     public void setNotification(Notification notification) {
index cc380d8..029dc1f 100644 (file)
@@ -891,7 +891,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
                     mNetworkController, mZenModeController, mHotspotController,
                     mCastController, mFlashlightController,
                     mUserSwitcherController, mUserInfoController, mKeyguardMonitor,
-                    mSecurityController, mBatteryController);
+                    mSecurityController, mBatteryController, mIconController);
             mQSPanel.setHost(qsh);
             mQSPanel.setTiles(qsh.getTiles());
             mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
index 5c856e8..336b208 100644 (file)
@@ -95,17 +95,19 @@ public final class QSTileHost implements QSTile.Host, Tunable {
     private final KeyguardMonitor mKeyguard;
     private final SecurityController mSecurity;
     private final BatteryController mBattery;
+    private final StatusBarIconController mIconController;
     private final TileServices mServices;
 
     private final List<Callback> mCallbacks = new ArrayList<>();
 
     public QSTileHost(Context context, PhoneStatusBar statusBar,
-            BluetoothController bluetooth, LocationController location,
-            RotationLockController rotation, NetworkController network,
-            ZenModeController zen, HotspotController hotspot,
-            CastController cast, FlashlightController flashlight,
-            UserSwitcherController userSwitcher, UserInfoController userInfo, KeyguardMonitor keyguard,
-            SecurityController security, BatteryController battery) {
+                      BluetoothController bluetooth, LocationController location,
+                      RotationLockController rotation, NetworkController network,
+                      ZenModeController zen, HotspotController hotspot,
+                      CastController cast, FlashlightController flashlight,
+                      UserSwitcherController userSwitcher, UserInfoController userInfo,
+                      KeyguardMonitor keyguard, SecurityController security,
+                      BatteryController battery, StatusBarIconController iconController) {
         mContext = context;
         mStatusBar = statusBar;
         mBluetooth = bluetooth;
@@ -121,6 +123,7 @@ public final class QSTileHost implements QSTile.Host, Tunable {
         mKeyguard = keyguard;
         mSecurity = security;
         mBattery = battery;
+        mIconController = iconController;
 
         final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
                 Process.THREAD_PRIORITY_BACKGROUND);
@@ -258,6 +261,10 @@ public final class QSTileHost implements QSTile.Host, Tunable {
         return mServices;
     }
 
+    public StatusBarIconController getIconController() {
+        return mIconController;
+    }
+
     @Override
     public void onTuningChanged(String key, String newValue) {
         if (!TILES_SETTING.equals(key)) {
index a91f6a2..3692aee 100644 (file)
@@ -205,7 +205,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
                 host.getCastController(), host.getFlashlightController(),
                 host.getUserSwitcherController(), host.getUserInfoController(),
                 host.getKeyguardMonitor(), host.getSecurityController(),
-                host.getBatteryController());
+                host.getBatteryController(), host.getIconController());
         mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
         mHeaderQsPanel.setHost(myHost);
         mHeaderQsPanel.setMaxTiles(5);
index 6172752..5e98ec1 100644 (file)
@@ -194,19 +194,23 @@ public class StatusBarIconController extends StatusBarIconList implements Tunabl
         }
     }
 
+    public void setExternalIcon(String slot) {
+        int viewIndex = getViewIndex(getSlotIndex(slot));
+        ImageView imageView = (ImageView) mStatusIcons.getChildAt(viewIndex);
+        imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+        imageView.setAdjustViewBounds(true);
+        imageView = (ImageView) mStatusIconsKeyguard.getChildAt(viewIndex);
+        imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+        imageView.setAdjustViewBounds(true);
+    }
+
     public void setIcon(String slot, StatusBarIcon icon) {
         setIcon(getSlotIndex(slot), icon);
     }
 
     public void removeIcon(String slot) {
         int index = getSlotIndex(slot);
-        if (getIcon(index) == null) {
-            return;
-        }
-        super.removeIcon(index);
-        int viewIndex = getViewIndex(index);
-        mStatusIcons.removeViewAt(viewIndex);
-        mStatusIconsKeyguard.removeViewAt(viewIndex);
+        removeIcon(index);
     }
 
     public void setIconVisibility(String slot, boolean visibility) {
@@ -220,12 +224,24 @@ public class StatusBarIconController extends StatusBarIconList implements Tunabl
     }
 
     @Override
+    public void removeIcon(int index) {
+        if (getIcon(index) == null) {
+            return;
+        }
+        super.removeIcon(index);
+        int viewIndex = getViewIndex(index);
+        mStatusIcons.removeViewAt(viewIndex);
+        mStatusIconsKeyguard.removeViewAt(viewIndex);
+    }
+
+    @Override
     public void setIcon(int index, StatusBarIcon icon) {
-        boolean isNew = getIcon(index) == null;
-        super.setIcon(index, icon);
         if (icon == null) {
+            removeIcon(index);
             return;
         }
+        boolean isNew = getIcon(index) == null;
+        super.setIcon(index, icon);
         if (isNew) {
             addSystemIcon(index, icon);
         } else {
index 7a3ce87..c4ca039 100644 (file)
@@ -35,7 +35,7 @@ public class TileServicesTests extends SysuiTestCase {
         super.setUp();
         mManagers = new ArrayList<>();
         QSTileHost host = new QSTileHost(mContext, null, null, null, null, null, null, null, null,
-                null, null, null, null, null, null);
+                null, null, null, null, null, null, null);
         mTileService = new TestTileServices(host, Looper.myLooper());
     }