Merge "Add Start Activity API for TileServices" into tm-qpr-dev am: b9b844866b
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20581227 Change-Id: I14f482ade1b0b71c9da8ca657ca02db88ccc8815 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package android.service.quicksettings;
|
package android.service.quicksettings;
|
||||||
|
|
||||||
|
import android.app.PendingIntent;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.service.quicksettings.Tile;
|
import android.service.quicksettings.Tile;
|
||||||
@@ -29,10 +30,10 @@ interface IQSService {
|
|||||||
String contentDescription);
|
String contentDescription);
|
||||||
void onShowDialog(in IBinder tile);
|
void onShowDialog(in IBinder tile);
|
||||||
void onStartActivity(in IBinder tile);
|
void onStartActivity(in IBinder tile);
|
||||||
|
void startActivity(in IBinder tile, in PendingIntent pendingIntent);
|
||||||
boolean isLocked();
|
boolean isLocked();
|
||||||
boolean isSecure();
|
boolean isSecure();
|
||||||
void startUnlockAndRun(in IBinder tile);
|
void startUnlockAndRun(in IBinder tile);
|
||||||
|
|
||||||
void onDialogHidden(in IBinder tile);
|
void onDialogHidden(in IBinder tile);
|
||||||
void onStartSuccessful(in IBinder tile);
|
void onStartSuccessful(in IBinder tile);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package android.service.quicksettings;
|
package android.service.quicksettings;
|
||||||
|
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.app.PendingIntent;
|
||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
@@ -66,6 +67,7 @@ public final class Tile implements Parcelable {
|
|||||||
private CharSequence mSubtitle;
|
private CharSequence mSubtitle;
|
||||||
private CharSequence mContentDescription;
|
private CharSequence mContentDescription;
|
||||||
private CharSequence mStateDescription;
|
private CharSequence mStateDescription;
|
||||||
|
private PendingIntent mPendingIntent;
|
||||||
// Default to inactive until clients of the new API can update.
|
// Default to inactive until clients of the new API can update.
|
||||||
private int mState = STATE_INACTIVE;
|
private int mState = STATE_INACTIVE;
|
||||||
|
|
||||||
@@ -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
|
@Override
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
if (mIcon != null) {
|
if (mIcon != null) {
|
||||||
@@ -231,6 +261,12 @@ public final class Tile implements Parcelable {
|
|||||||
} else {
|
} else {
|
||||||
dest.writeByte((byte) 0);
|
dest.writeByte((byte) 0);
|
||||||
}
|
}
|
||||||
|
if (mPendingIntent != null) {
|
||||||
|
dest.writeByte((byte) 1);
|
||||||
|
mPendingIntent.writeToParcel(dest, flags);
|
||||||
|
} else {
|
||||||
|
dest.writeByte((byte) 0);
|
||||||
|
}
|
||||||
dest.writeInt(mState);
|
dest.writeInt(mState);
|
||||||
TextUtils.writeToParcel(mLabel, dest, flags);
|
TextUtils.writeToParcel(mLabel, dest, flags);
|
||||||
TextUtils.writeToParcel(mSubtitle, dest, flags);
|
TextUtils.writeToParcel(mSubtitle, dest, flags);
|
||||||
@@ -244,6 +280,11 @@ public final class Tile implements Parcelable {
|
|||||||
} else {
|
} else {
|
||||||
mIcon = null;
|
mIcon = null;
|
||||||
}
|
}
|
||||||
|
if (source.readByte() != 0) {
|
||||||
|
mPendingIntent = PendingIntent.CREATOR.createFromParcel(source);
|
||||||
|
} else {
|
||||||
|
mPendingIntent = null;
|
||||||
|
}
|
||||||
mState = source.readInt();
|
mState = source.readInt();
|
||||||
mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
|
mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
|
||||||
mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
|
mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import android.annotation.SdkConstant.SdkConstantType;
|
|||||||
import android.annotation.SystemApi;
|
import android.annotation.SystemApi;
|
||||||
import android.annotation.TestApi;
|
import android.annotation.TestApi;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.app.StatusBarManager;
|
import android.app.StatusBarManager;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
@@ -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.
|
* Gets the {@link Tile} for this service.
|
||||||
* <p/>
|
* <p/>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.systemui.qs.external;
|
|||||||
import static android.view.Display.DEFAULT_DISPLAY;
|
import static android.view.Display.DEFAULT_DISPLAY;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
|
import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
|
||||||
|
|
||||||
|
import android.app.PendingIntent;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -51,6 +52,7 @@ import androidx.annotation.WorkerThread;
|
|||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.logging.MetricsLogger;
|
import com.android.internal.logging.MetricsLogger;
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
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.Background;
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
import com.android.systemui.plugins.ActivityStarter;
|
import com.android.systemui.plugins.ActivityStarter;
|
||||||
@@ -92,6 +94,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
private android.graphics.drawable.Icon mDefaultIcon;
|
private android.graphics.drawable.Icon mDefaultIcon;
|
||||||
@Nullable
|
@Nullable
|
||||||
private CharSequence mDefaultLabel;
|
private CharSequence mDefaultLabel;
|
||||||
|
@Nullable
|
||||||
|
private View mViewClicked;
|
||||||
|
|
||||||
private final Context mUserContext;
|
private final Context mUserContext;
|
||||||
|
|
||||||
@@ -202,7 +206,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
* Compare two icons, only works for resources.
|
* Compare two icons, only works for resources.
|
||||||
*/
|
*/
|
||||||
private boolean iconEquals(@Nullable android.graphics.drawable.Icon icon1,
|
private boolean iconEquals(@Nullable android.graphics.drawable.Icon icon1,
|
||||||
@Nullable android.graphics.drawable.Icon icon2) {
|
@Nullable android.graphics.drawable.Icon icon2) {
|
||||||
if (icon1 == icon2) {
|
if (icon1 == icon2) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -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).
|
* 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.
|
* It will return {@code true} before initialization, so tiles are not destroyed prematurely.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -262,6 +266,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update state of {@link this#mTile} from a remote {@link TileService}.
|
* Update state of {@link this#mTile} from a remote {@link TileService}.
|
||||||
|
*
|
||||||
* @param tile tile populated with state to apply
|
* @param tile tile populated with state to apply
|
||||||
*/
|
*/
|
||||||
public void updateTileState(Tile tile) {
|
public void updateTileState(Tile tile) {
|
||||||
@@ -293,6 +298,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
if (tile.getStateDescription() != null || overwriteNulls) {
|
if (tile.getStateDescription() != null || overwriteNulls) {
|
||||||
mTile.setStateDescription(tile.getStateDescription());
|
mTile.setStateDescription(tile.getStateDescription());
|
||||||
}
|
}
|
||||||
|
mTile.setActivityLaunchForClick(tile.getActivityLaunchForClick());
|
||||||
mTile.setState(tile.getState());
|
mTile.setState(tile.getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,6 +330,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
mService.onStartListening();
|
mService.onStartListening();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
mViewClicked = null;
|
||||||
mService.onStopListening();
|
mService.onStopListening();
|
||||||
if (mIsTokenGranted && !mIsShowingDialog) {
|
if (mIsTokenGranted && !mIsShowingDialog) {
|
||||||
try {
|
try {
|
||||||
@@ -388,6 +395,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
if (mTile.getState() == Tile.STATE_UNAVAILABLE) {
|
if (mTile.getState() == Tile.STATE_UNAVAILABLE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
mViewClicked = view;
|
||||||
try {
|
try {
|
||||||
if (DEBUG) Log.d(TAG, "Adding token");
|
if (DEBUG) Log.d(TAG, "Adding token");
|
||||||
mWindowManager.addWindowToken(mToken, TYPE_QS_DIALOG, DEFAULT_DISPLAY,
|
mWindowManager.addWindowToken(mToken, TYPE_QS_DIALOG, DEFAULT_DISPLAY,
|
||||||
@@ -400,7 +408,12 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
mServiceManager.setBindRequested(true);
|
mServiceManager.setBindRequested(true);
|
||||||
mService.onStartListening();
|
mService.onStartListening();
|
||||||
}
|
}
|
||||||
mService.onClick(mToken);
|
|
||||||
|
if (mTile.getActivityLaunchForClick() != null) {
|
||||||
|
startActivityAndCollapse(mTile.getActivityLaunchForClick());
|
||||||
|
} else {
|
||||||
|
mService.onClick(mToken);
|
||||||
|
}
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// Called through wrapper, won't happen here.
|
// Called through wrapper, won't happen here.
|
||||||
}
|
}
|
||||||
@@ -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) {
|
public static String toSpec(ComponentName name) {
|
||||||
return PREFIX + name.flattenToShortString() + ")";
|
return PREFIX + name.flattenToShortString() + ")";
|
||||||
}
|
}
|
||||||
@@ -509,8 +543,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
/**
|
/**
|
||||||
* Create a {@link CustomTile} for a given spec and user.
|
* Create a {@link CustomTile} for a given spec and user.
|
||||||
*
|
*
|
||||||
* @param builder including injected common dependencies.
|
* @param builder including injected common dependencies.
|
||||||
* @param spec as provided by {@link CustomTile#toSpec}
|
* @param spec as provided by {@link CustomTile#toSpec}
|
||||||
* @param userContext context for the user that is creating this tile.
|
* @param userContext context for the user that is creating this tile.
|
||||||
* @return a new {@link CustomTile}
|
* @return a new {@link CustomTile}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.systemui.qs.external;
|
package com.android.systemui.qs.external;
|
||||||
|
|
||||||
|
import android.app.PendingIntent;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
@@ -32,6 +33,7 @@ import android.util.Log;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.android.internal.statusbar.StatusBarIcon;
|
import com.android.internal.statusbar.StatusBarIcon;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
@@ -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
|
@Override
|
||||||
public void updateStatusIcon(IBinder token, Icon icon, String contentDescription) {
|
public void updateStatusIcon(IBinder token, Icon icon, String contentDescription) {
|
||||||
CustomTile customTile = getTileForToken(token);
|
CustomTile customTile = getTileForToken(token);
|
||||||
@@ -336,7 +351,7 @@ public class TileServices extends IQSService.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private CustomTile getTileForToken(IBinder token) {
|
public CustomTile getTileForToken(IBinder token) {
|
||||||
synchronized (mServices) {
|
synchronized (mServices) {
|
||||||
return mTokenMap.get(token);
|
return mTokenMap.get(token);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.systemui.qs.external
|
package com.android.systemui.qs.external
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
@@ -30,8 +31,10 @@ import android.test.suitebuilder.annotation.SmallTest
|
|||||||
import android.testing.AndroidTestingRunner
|
import android.testing.AndroidTestingRunner
|
||||||
import android.testing.TestableLooper
|
import android.testing.TestableLooper
|
||||||
import android.view.IWindowManager
|
import android.view.IWindowManager
|
||||||
|
import android.view.View
|
||||||
import com.android.internal.logging.MetricsLogger
|
import com.android.internal.logging.MetricsLogger
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.animation.ActivityLaunchAnimator
|
||||||
import com.android.systemui.classifier.FalsingManagerFake
|
import com.android.systemui.classifier.FalsingManagerFake
|
||||||
import com.android.systemui.plugins.ActivityStarter
|
import com.android.systemui.plugins.ActivityStarter
|
||||||
import com.android.systemui.plugins.qs.QSTile
|
import com.android.systemui.plugins.qs.QSTile
|
||||||
@@ -39,8 +42,11 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController
|
|||||||
import com.android.systemui.qs.QSHost
|
import com.android.systemui.qs.QSHost
|
||||||
import com.android.systemui.qs.logging.QSLogger
|
import com.android.systemui.qs.logging.QSLogger
|
||||||
import com.android.systemui.util.mockito.any
|
import com.android.systemui.util.mockito.any
|
||||||
|
import com.android.systemui.util.mockito.eq
|
||||||
|
import com.android.systemui.util.mockito.nullable
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertThrows
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -236,6 +242,10 @@ class CustomTileTest : SysuiTestCase() {
|
|||||||
`when`(tile.qsTile.icon.loadDrawable(any(Context::class.java)))
|
`when`(tile.qsTile.icon.loadDrawable(any(Context::class.java)))
|
||||||
.thenReturn(mock(Drawable::class.java))
|
.thenReturn(mock(Drawable::class.java))
|
||||||
|
|
||||||
|
val pi = mock(PendingIntent::class.java)
|
||||||
|
`when`(pi.isActivity).thenReturn(true)
|
||||||
|
tile.qsTile.activityLaunchForClick = pi
|
||||||
|
|
||||||
tile.refreshState()
|
tile.refreshState()
|
||||||
|
|
||||||
testableLooper.processAllMessages()
|
testableLooper.processAllMessages()
|
||||||
@@ -289,4 +299,52 @@ class CustomTileTest : SysuiTestCase() {
|
|||||||
assertFalse(tile.isAvailable)
|
assertFalse(tile.isAvailable)
|
||||||
verify(tileHost).removeTile(tile.tileSpec)
|
verify(tileHost).removeTile(tile.tileSpec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testInvalidPendingIntentDoesNotStartActivity() {
|
||||||
|
val pi = mock(PendingIntent::class.java)
|
||||||
|
`when`(pi.isActivity).thenReturn(false)
|
||||||
|
val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
|
||||||
|
|
||||||
|
assertThrows(IllegalArgumentException::class.java) {
|
||||||
|
tile.qsTile.activityLaunchForClick = pi
|
||||||
|
}
|
||||||
|
|
||||||
|
tile.handleClick(mock(View::class.java))
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
|
verify(activityStarter, never())
|
||||||
|
.startPendingIntentDismissingKeyguard(
|
||||||
|
any(), any(), any(ActivityLaunchAnimator.Controller::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testValidPendingIntentWithNoClickDoesNotStartActivity() {
|
||||||
|
val pi = mock(PendingIntent::class.java)
|
||||||
|
`when`(pi.isActivity).thenReturn(true)
|
||||||
|
val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
|
||||||
|
tile.qsTile.activityLaunchForClick = pi
|
||||||
|
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
|
verify(activityStarter, never())
|
||||||
|
.startPendingIntentDismissingKeyguard(
|
||||||
|
any(), any(), any(ActivityLaunchAnimator.Controller::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testValidPendingIntentStartsActivity() {
|
||||||
|
val pi = mock(PendingIntent::class.java)
|
||||||
|
`when`(pi.isActivity).thenReturn(true)
|
||||||
|
val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
|
||||||
|
tile.qsTile.activityLaunchForClick = pi
|
||||||
|
|
||||||
|
tile.handleClick(mock(View::class.java))
|
||||||
|
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
|
verify(activityStarter)
|
||||||
|
.startPendingIntentDismissingKeyguard(
|
||||||
|
eq(pi), nullable(), nullable<ActivityLaunchAnimator.Controller>())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.times;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.PendingIntent;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -58,6 +59,7 @@ import com.android.systemui.tuner.TunerService;
|
|||||||
import com.android.systemui.util.settings.SecureSettings;
|
import com.android.systemui.util.settings.SecureSettings;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -245,6 +247,32 @@ public class TileServicesTest extends SysuiTestCase {
|
|||||||
verify(manager.getTileService()).onStartListening();
|
verify(manager.getTileService()).onStartListening();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidCustomTileStartsActivity() {
|
||||||
|
CustomTile tile = mock(CustomTile.class);
|
||||||
|
PendingIntent pi = mock(PendingIntent.class);
|
||||||
|
ComponentName componentName = mock(ComponentName.class);
|
||||||
|
when(tile.getComponent()).thenReturn(componentName);
|
||||||
|
when(componentName.getPackageName()).thenReturn(this.getContext().getPackageName());
|
||||||
|
|
||||||
|
mTileService.startActivity(tile, pi);
|
||||||
|
|
||||||
|
verify(tile).startActivityAndCollapse(pi);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidCustomTileDoesNotStartActivity() {
|
||||||
|
CustomTile tile = mock(CustomTile.class);
|
||||||
|
PendingIntent pi = mock(PendingIntent.class);
|
||||||
|
ComponentName componentName = mock(ComponentName.class);
|
||||||
|
when(tile.getComponent()).thenReturn(componentName);
|
||||||
|
when(componentName.getPackageName()).thenReturn("invalid.package.name");
|
||||||
|
|
||||||
|
Assert.assertThrows(SecurityException.class, () -> mTileService.startActivity(tile, pi));
|
||||||
|
|
||||||
|
verify(tile, never()).startActivityAndCollapse(pi);
|
||||||
|
}
|
||||||
|
|
||||||
private class TestTileServices extends TileServices {
|
private class TestTileServices extends TileServices {
|
||||||
TestTileServices(QSTileHost host, Provider<Handler> handlerProvider,
|
TestTileServices(QSTileHost host, Provider<Handler> handlerProvider,
|
||||||
BroadcastDispatcher broadcastDispatcher, UserTracker userTracker,
|
BroadcastDispatcher broadcastDispatcher, UserTracker userTracker,
|
||||||
|
|||||||
Reference in New Issue
Block a user