Loading core/java/android/service/quicksettings/IQSService.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package android.service.quicksettings; import android.app.PendingIntent; import android.content.ComponentName; import android.graphics.drawable.Icon; import android.service.quicksettings.Tile; Loading @@ -29,10 +30,10 @@ interface IQSService { String contentDescription); void onShowDialog(in IBinder tile); void onStartActivity(in IBinder tile); void startActivity(in IBinder tile, in PendingIntent pendingIntent); boolean isLocked(); boolean isSecure(); void startUnlockAndRun(in IBinder tile); void onDialogHidden(in IBinder tile); void onStartSuccessful(in IBinder tile); } core/java/android/service/quicksettings/Tile.java +41 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.service.quicksettings; import android.annotation.Nullable; import android.app.PendingIntent; import android.graphics.drawable.Icon; import android.os.IBinder; import android.os.Parcel; Loading Loading @@ -66,6 +67,7 @@ public final class Tile implements Parcelable { private CharSequence mSubtitle; private CharSequence mContentDescription; private CharSequence mStateDescription; private PendingIntent mPendingIntent; // Default to inactive until clients of the new API can update. private int mState = STATE_INACTIVE; Loading Loading @@ -223,6 +225,34 @@ public final class Tile implements Parcelable { } } /** * Gets the Activity {@link PendingIntent} to be launched when the tile is clicked. * @hide */ @Nullable public PendingIntent getActivityLaunchForClick() { return mPendingIntent; } /** * Sets an Activity {@link PendingIntent} to be launched when the tile is clicked. * * The last value set here will be launched when the user clicks in the tile, instead of * forwarding the `onClick` message to the {@link TileService}. Set to {@code null} to handle * the `onClick` in the `TileService` * (This is the default behavior if this method is never called.) * @param pendingIntent a PendingIntent for an activity to be launched onclick, or {@code null} * to handle the clicks in the `TileService`. * @hide */ public void setActivityLaunchForClick(@Nullable PendingIntent pendingIntent) { if (pendingIntent != null && !pendingIntent.isActivity()) { throw new IllegalArgumentException(); } else { mPendingIntent = pendingIntent; } } @Override public void writeToParcel(Parcel dest, int flags) { if (mIcon != null) { Loading @@ -231,6 +261,12 @@ public final class Tile implements Parcelable { } else { dest.writeByte((byte) 0); } if (mPendingIntent != null) { dest.writeByte((byte) 1); mPendingIntent.writeToParcel(dest, flags); } else { dest.writeByte((byte) 0); } dest.writeInt(mState); TextUtils.writeToParcel(mLabel, dest, flags); TextUtils.writeToParcel(mSubtitle, dest, flags); Loading @@ -244,6 +280,11 @@ public final class Tile implements Parcelable { } else { mIcon = null; } if (source.readByte() != 0) { mPendingIntent = PendingIntent.CREATOR.createFromParcel(source); } else { mPendingIntent = null; } mState = source.readInt(); mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); Loading core/java/android/service/quicksettings/TileService.java +15 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.Dialog; import android.app.PendingIntent; import android.app.Service; import android.app.StatusBarManager; import android.content.ComponentName; Loading Loading @@ -335,6 +336,20 @@ public class TileService extends Service { } } /** * Starts an {@link android.app.Activity}. * Will collapse Quick Settings after launching. * * @param pendingIntent A PendingIntent for an Activity to be launched immediately. * @hide */ public void startActivityAndCollapse(PendingIntent pendingIntent) { try { mService.startActivity(mTileToken, pendingIntent); } catch (RemoteException e) { } } /** * Gets the {@link Tile} for this service. * <p/> Loading packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +39 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.qs.external; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -51,6 +52,7 @@ import androidx.annotation.WorkerThread; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; Loading Loading @@ -92,6 +94,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener private android.graphics.drawable.Icon mDefaultIcon; @Nullable private CharSequence mDefaultLabel; @Nullable private View mViewClicked; private final Context mUserContext; Loading Loading @@ -229,7 +233,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener /** * Custom tile is considered available if there is a default icon (obtained from PM). * * <p> * It will return {@code true} before initialization, so tiles are not destroyed prematurely. */ @Override Loading Loading @@ -262,6 +266,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener /** * Update state of {@link this#mTile} from a remote {@link TileService}. * * @param tile tile populated with state to apply */ public void updateTileState(Tile tile) { Loading Loading @@ -293,6 +298,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener if (tile.getStateDescription() != null || overwriteNulls) { mTile.setStateDescription(tile.getStateDescription()); } mTile.setActivityLaunchForClick(tile.getActivityLaunchForClick()); mTile.setState(tile.getState()); } Loading Loading @@ -324,6 +330,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener mService.onStartListening(); } } else { mViewClicked = null; mService.onStopListening(); if (mIsTokenGranted && !mIsShowingDialog) { try { Loading Loading @@ -388,6 +395,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener if (mTile.getState() == Tile.STATE_UNAVAILABLE) { return; } mViewClicked = view; try { if (DEBUG) Log.d(TAG, "Adding token"); mWindowManager.addWindowToken(mToken, TYPE_QS_DIALOG, DEFAULT_DISPLAY, Loading @@ -400,7 +408,12 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener mServiceManager.setBindRequested(true); mService.onStartListening(); } if (mTile.getActivityLaunchForClick() != null) { startActivityAndCollapse(mTile.getActivityLaunchForClick()); } else { mService.onClick(mToken); } } catch (RemoteException e) { // Called through wrapper, won't happen here. } Loading Loading @@ -483,6 +496,27 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener }); } /** * Starts an {@link android.app.Activity} * @param pendingIntent A PendingIntent for an Activity to be launched immediately. */ public void startActivityAndCollapse(PendingIntent pendingIntent) { if (!pendingIntent.isActivity()) { Log.i(TAG, "Intent not for activity."); } else if (!mIsTokenGranted) { Log.i(TAG, "Launching activity before click"); } else { Log.i(TAG, "The activity is starting"); ActivityLaunchAnimator.Controller controller = mViewClicked == null ? null : ActivityLaunchAnimator.Controller.fromView(mViewClicked, 0); mUiHandler.post(() -> mActivityStarter.startPendingIntentDismissingKeyguard( pendingIntent, null, controller) ); } } public static String toSpec(ComponentName name) { return PREFIX + name.flattenToShortString() + ")"; } Loading packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +16 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.systemui.qs.external; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageInfo; Loading @@ -32,6 +33,7 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.broadcast.BroadcastDispatcher; Loading Loading @@ -275,6 +277,19 @@ public class TileServices extends IQSService.Stub { } } @Override public void startActivity(IBinder token, PendingIntent pendingIntent) { startActivity(getTileForToken(token), pendingIntent); } @VisibleForTesting protected void startActivity(CustomTile customTile, PendingIntent pendingIntent) { if (customTile != null) { verifyCaller(customTile); customTile.startActivityAndCollapse(pendingIntent); } } @Override public void updateStatusIcon(IBinder token, Icon icon, String contentDescription) { CustomTile customTile = getTileForToken(token); Loading Loading @@ -336,7 +351,7 @@ public class TileServices extends IQSService.Stub { } @Nullable private CustomTile getTileForToken(IBinder token) { public CustomTile getTileForToken(IBinder token) { synchronized (mServices) { return mTokenMap.get(token); } Loading Loading
core/java/android/service/quicksettings/IQSService.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package android.service.quicksettings; import android.app.PendingIntent; import android.content.ComponentName; import android.graphics.drawable.Icon; import android.service.quicksettings.Tile; Loading @@ -29,10 +30,10 @@ interface IQSService { String contentDescription); void onShowDialog(in IBinder tile); void onStartActivity(in IBinder tile); void startActivity(in IBinder tile, in PendingIntent pendingIntent); boolean isLocked(); boolean isSecure(); void startUnlockAndRun(in IBinder tile); void onDialogHidden(in IBinder tile); void onStartSuccessful(in IBinder tile); }
core/java/android/service/quicksettings/Tile.java +41 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.service.quicksettings; import android.annotation.Nullable; import android.app.PendingIntent; import android.graphics.drawable.Icon; import android.os.IBinder; import android.os.Parcel; Loading Loading @@ -66,6 +67,7 @@ public final class Tile implements Parcelable { private CharSequence mSubtitle; private CharSequence mContentDescription; private CharSequence mStateDescription; private PendingIntent mPendingIntent; // Default to inactive until clients of the new API can update. private int mState = STATE_INACTIVE; Loading Loading @@ -223,6 +225,34 @@ public final class Tile implements Parcelable { } } /** * Gets the Activity {@link PendingIntent} to be launched when the tile is clicked. * @hide */ @Nullable public PendingIntent getActivityLaunchForClick() { return mPendingIntent; } /** * Sets an Activity {@link PendingIntent} to be launched when the tile is clicked. * * The last value set here will be launched when the user clicks in the tile, instead of * forwarding the `onClick` message to the {@link TileService}. Set to {@code null} to handle * the `onClick` in the `TileService` * (This is the default behavior if this method is never called.) * @param pendingIntent a PendingIntent for an activity to be launched onclick, or {@code null} * to handle the clicks in the `TileService`. * @hide */ public void setActivityLaunchForClick(@Nullable PendingIntent pendingIntent) { if (pendingIntent != null && !pendingIntent.isActivity()) { throw new IllegalArgumentException(); } else { mPendingIntent = pendingIntent; } } @Override public void writeToParcel(Parcel dest, int flags) { if (mIcon != null) { Loading @@ -231,6 +261,12 @@ public final class Tile implements Parcelable { } else { dest.writeByte((byte) 0); } if (mPendingIntent != null) { dest.writeByte((byte) 1); mPendingIntent.writeToParcel(dest, flags); } else { dest.writeByte((byte) 0); } dest.writeInt(mState); TextUtils.writeToParcel(mLabel, dest, flags); TextUtils.writeToParcel(mSubtitle, dest, flags); Loading @@ -244,6 +280,11 @@ public final class Tile implements Parcelable { } else { mIcon = null; } if (source.readByte() != 0) { mPendingIntent = PendingIntent.CREATOR.createFromParcel(source); } else { mPendingIntent = null; } mState = source.readInt(); mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); Loading
core/java/android/service/quicksettings/TileService.java +15 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.Dialog; import android.app.PendingIntent; import android.app.Service; import android.app.StatusBarManager; import android.content.ComponentName; Loading Loading @@ -335,6 +336,20 @@ public class TileService extends Service { } } /** * Starts an {@link android.app.Activity}. * Will collapse Quick Settings after launching. * * @param pendingIntent A PendingIntent for an Activity to be launched immediately. * @hide */ public void startActivityAndCollapse(PendingIntent pendingIntent) { try { mService.startActivity(mTileToken, pendingIntent); } catch (RemoteException e) { } } /** * Gets the {@link Tile} for this service. * <p/> Loading
packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +39 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.qs.external; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -51,6 +52,7 @@ import androidx.annotation.WorkerThread; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; Loading Loading @@ -92,6 +94,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener private android.graphics.drawable.Icon mDefaultIcon; @Nullable private CharSequence mDefaultLabel; @Nullable private View mViewClicked; private final Context mUserContext; Loading Loading @@ -229,7 +233,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener /** * Custom tile is considered available if there is a default icon (obtained from PM). * * <p> * It will return {@code true} before initialization, so tiles are not destroyed prematurely. */ @Override Loading Loading @@ -262,6 +266,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener /** * Update state of {@link this#mTile} from a remote {@link TileService}. * * @param tile tile populated with state to apply */ public void updateTileState(Tile tile) { Loading Loading @@ -293,6 +298,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener if (tile.getStateDescription() != null || overwriteNulls) { mTile.setStateDescription(tile.getStateDescription()); } mTile.setActivityLaunchForClick(tile.getActivityLaunchForClick()); mTile.setState(tile.getState()); } Loading Loading @@ -324,6 +330,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener mService.onStartListening(); } } else { mViewClicked = null; mService.onStopListening(); if (mIsTokenGranted && !mIsShowingDialog) { try { Loading Loading @@ -388,6 +395,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener if (mTile.getState() == Tile.STATE_UNAVAILABLE) { return; } mViewClicked = view; try { if (DEBUG) Log.d(TAG, "Adding token"); mWindowManager.addWindowToken(mToken, TYPE_QS_DIALOG, DEFAULT_DISPLAY, Loading @@ -400,7 +408,12 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener mServiceManager.setBindRequested(true); mService.onStartListening(); } if (mTile.getActivityLaunchForClick() != null) { startActivityAndCollapse(mTile.getActivityLaunchForClick()); } else { mService.onClick(mToken); } } catch (RemoteException e) { // Called through wrapper, won't happen here. } Loading Loading @@ -483,6 +496,27 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener }); } /** * Starts an {@link android.app.Activity} * @param pendingIntent A PendingIntent for an Activity to be launched immediately. */ public void startActivityAndCollapse(PendingIntent pendingIntent) { if (!pendingIntent.isActivity()) { Log.i(TAG, "Intent not for activity."); } else if (!mIsTokenGranted) { Log.i(TAG, "Launching activity before click"); } else { Log.i(TAG, "The activity is starting"); ActivityLaunchAnimator.Controller controller = mViewClicked == null ? null : ActivityLaunchAnimator.Controller.fromView(mViewClicked, 0); mUiHandler.post(() -> mActivityStarter.startPendingIntentDismissingKeyguard( pendingIntent, null, controller) ); } } public static String toSpec(ComponentName name) { return PREFIX + name.flattenToShortString() + ")"; } Loading
packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +16 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.systemui.qs.external; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageInfo; Loading @@ -32,6 +33,7 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.broadcast.BroadcastDispatcher; Loading Loading @@ -275,6 +277,19 @@ public class TileServices extends IQSService.Stub { } } @Override public void startActivity(IBinder token, PendingIntent pendingIntent) { startActivity(getTileForToken(token), pendingIntent); } @VisibleForTesting protected void startActivity(CustomTile customTile, PendingIntent pendingIntent) { if (customTile != null) { verifyCaller(customTile); customTile.startActivityAndCollapse(pendingIntent); } } @Override public void updateStatusIcon(IBinder token, Icon icon, String contentDescription) { CustomTile customTile = getTileForToken(token); Loading Loading @@ -336,7 +351,7 @@ public class TileServices extends IQSService.Stub { } @Nullable private CustomTile getTileForToken(IBinder token) { public CustomTile getTileForToken(IBinder token) { synchronized (mServices) { return mTokenMap.get(token); } Loading