Merge "CompatChanges for TileService#startActivityAndCollapse"
This commit is contained in:
committed by
Android (Google) Code Review
commit
0103eb1fb5
@@ -40439,7 +40439,7 @@ package android.service.quicksettings {
|
||||
method public void onTileRemoved();
|
||||
method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
|
||||
method public final void showDialog(android.app.Dialog);
|
||||
method public final void startActivityAndCollapse(android.content.Intent);
|
||||
method @Deprecated public final void startActivityAndCollapse(android.content.Intent);
|
||||
method public final void startActivityAndCollapse(@NonNull android.app.PendingIntent);
|
||||
method public final void unlockAndRun(Runnable);
|
||||
field public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
|
||||
|
||||
@@ -24,6 +24,9 @@ import android.app.Dialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.app.StatusBarManager;
|
||||
import android.app.compat.CompatChanges;
|
||||
import android.compat.annotation.ChangeId;
|
||||
import android.compat.annotation.EnabledSince;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -166,6 +169,17 @@ public class TileService extends Service {
|
||||
*/
|
||||
public static final String EXTRA_STATE = "state";
|
||||
|
||||
/**
|
||||
* The method {@link TileService#startActivityAndCollapse(Intent)} will verify that only
|
||||
* apps targeting {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or higher will
|
||||
* not be allowed to use it.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@ChangeId
|
||||
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||
public static final long START_ACTIVITY_NEEDS_PENDING_INTENT = 241766793L;
|
||||
|
||||
private final H mHandler = new H(Looper.getMainLooper());
|
||||
|
||||
private boolean mListening = false;
|
||||
@@ -251,7 +265,6 @@ public class TileService extends Service {
|
||||
* This will collapse the Quick Settings panel and show the dialog.
|
||||
*
|
||||
* @param dialog Dialog to show.
|
||||
*
|
||||
* @see #isLocked()
|
||||
*/
|
||||
public final void showDialog(Dialog dialog) {
|
||||
@@ -330,8 +343,19 @@ public class TileService extends Service {
|
||||
|
||||
/**
|
||||
* Start an activity while collapsing the panel.
|
||||
*
|
||||
* @deprecated for versions {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and up,
|
||||
* use {@link TileService#startActivityAndCollapse(PendingIntent)} instead.
|
||||
* @throws UnsupportedOperationException if called in versions
|
||||
* {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and up
|
||||
*/
|
||||
@Deprecated
|
||||
public final void startActivityAndCollapse(Intent intent) {
|
||||
if (CompatChanges.isChangeEnabled(START_ACTIVITY_NEEDS_PENDING_INTENT)) {
|
||||
throw new UnsupportedOperationException(
|
||||
"startActivityAndCollapse: Starting activity from TileService using an Intent"
|
||||
+ " is not allowed.");
|
||||
}
|
||||
startActivity(intent);
|
||||
try {
|
||||
mService.onStartActivity(mTileToken);
|
||||
@@ -410,7 +434,7 @@ public class TileService extends Service {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnlockComplete() throws RemoteException{
|
||||
public void onUnlockComplete() throws RemoteException {
|
||||
mHandler.sendEmptyMessage(H.MSG_UNLOCK_COMPLETE);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package com.android.systemui.qs.external;
|
||||
|
||||
import static android.service.quicksettings.TileService.START_ACTIVITY_NEEDS_PENDING_INTENT;
|
||||
|
||||
import android.app.compat.CompatChanges;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -41,15 +44,15 @@ import androidx.annotation.WorkerThread;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
|
||||
import dagger.assisted.Assisted;
|
||||
import dagger.assisted.AssistedFactory;
|
||||
import dagger.assisted.AssistedInject;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import dagger.assisted.Assisted;
|
||||
import dagger.assisted.AssistedFactory;
|
||||
import dagger.assisted.AssistedInject;
|
||||
|
||||
/**
|
||||
* Manages the lifecycle of a TileService.
|
||||
* <p>
|
||||
@@ -124,7 +127,9 @@ public class TileLifecycleManager extends BroadcastReceiver implements
|
||||
/** Injectable factory for TileLifecycleManager. */
|
||||
@AssistedFactory
|
||||
public interface Factory {
|
||||
/** */
|
||||
/**
|
||||
*
|
||||
*/
|
||||
TileLifecycleManager create(Intent intent, UserHandle userHandle);
|
||||
}
|
||||
|
||||
@@ -161,7 +166,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
|
||||
* Determines whether the associated TileService is a Boolean Tile.
|
||||
*
|
||||
* @return true if {@link TileService#META_DATA_TOGGLEABLE_TILE} is set to {@code true} for this
|
||||
* tile
|
||||
* tile
|
||||
* @see TileService#META_DATA_TOGGLEABLE_TILE
|
||||
*/
|
||||
public boolean isToggleableTile() {
|
||||
@@ -207,12 +212,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
|
||||
if (DEBUG) Log.d(TAG, "Binding service " + mIntent + " " + mUser);
|
||||
mBindTryCount++;
|
||||
try {
|
||||
mIsBound = mContext.bindServiceAsUser(mIntent, this,
|
||||
Context.BIND_AUTO_CREATE
|
||||
| Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
|
||||
| Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
|
||||
| Context.BIND_WAIVE_PRIORITY,
|
||||
mUser);
|
||||
mIsBound = bindServices();
|
||||
if (!mIsBound) {
|
||||
mContext.unbindService(this);
|
||||
}
|
||||
@@ -237,6 +237,24 @@ public class TileLifecycleManager extends BroadcastReceiver implements
|
||||
}
|
||||
}
|
||||
|
||||
private boolean bindServices() {
|
||||
String packageName = mIntent.getComponent().getPackageName();
|
||||
if (CompatChanges.isChangeEnabled(START_ACTIVITY_NEEDS_PENDING_INTENT, packageName,
|
||||
mUser)) {
|
||||
return mContext.bindServiceAsUser(mIntent, this,
|
||||
Context.BIND_AUTO_CREATE
|
||||
| Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
|
||||
| Context.BIND_WAIVE_PRIORITY,
|
||||
mUser);
|
||||
}
|
||||
return mContext.bindServiceAsUser(mIntent, this,
|
||||
Context.BIND_AUTO_CREATE
|
||||
| Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
|
||||
| Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
|
||||
| Context.BIND_WAIVE_PRIORITY,
|
||||
mUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
if (DEBUG) Log.d(TAG, "onServiceConnected " + name);
|
||||
@@ -418,8 +436,11 @@ public class TileLifecycleManager extends BroadcastReceiver implements
|
||||
mPackageManagerAdapter.getPackageInfoAsUser(packageName, 0, mUser.getIdentifier());
|
||||
return true;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
if (DEBUG) Log.d(TAG, "Package not available: " + packageName, e);
|
||||
else Log.d(TAG, "Package not available: " + packageName);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Package not available: " + packageName, e);
|
||||
} else {
|
||||
Log.d(TAG, "Package not available: " + packageName);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -15,11 +15,17 @@
|
||||
*/
|
||||
package com.android.systemui.qs.external;
|
||||
|
||||
import static android.service.quicksettings.TileService.START_ACTIVITY_NEEDS_PENDING_INTENT;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.anyString;
|
||||
@@ -29,6 +35,7 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.compat.CompatChanges;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -59,6 +66,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@@ -77,11 +85,16 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
|
||||
private Handler mHandler;
|
||||
private TileLifecycleManager mStateManager;
|
||||
private TestContextWrapper mWrappedContext;
|
||||
private MockitoSession mMockitoSession;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
setPackageEnabled(true);
|
||||
mTileServiceComponentName = new ComponentName(mContext, "FakeTileService.class");
|
||||
mMockitoSession = mockitoSession()
|
||||
.initMocks(this)
|
||||
.mockStatic(CompatChanges.class)
|
||||
.startMocking();
|
||||
|
||||
// Stub.asInterface will just return itself.
|
||||
when(mMockTileService.queryLocalInterface(anyString())).thenReturn(mMockTileService);
|
||||
@@ -106,7 +119,13 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
mThread.quit();
|
||||
if (mMockitoSession != null) {
|
||||
mMockitoSession.finishMocking();
|
||||
}
|
||||
if (mThread != null) {
|
||||
mThread.quit();
|
||||
}
|
||||
|
||||
mStateManager.handleDestroy();
|
||||
}
|
||||
|
||||
@@ -290,6 +309,50 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
|
||||
verify(falseContext).unbindService(captor.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersionUDoesNotBindsAllowBackgroundActivity() {
|
||||
mockChangeEnabled(START_ACTIVITY_NEEDS_PENDING_INTENT, true);
|
||||
Context falseContext = mock(Context.class);
|
||||
TileLifecycleManager manager = new TileLifecycleManager(mHandler, falseContext,
|
||||
mock(IQSService.class),
|
||||
mMockPackageManagerAdapter,
|
||||
mMockBroadcastDispatcher,
|
||||
mTileServiceIntent,
|
||||
mUser);
|
||||
|
||||
manager.setBindService(true);
|
||||
int flags = Context.BIND_AUTO_CREATE
|
||||
| Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
|
||||
| Context.BIND_WAIVE_PRIORITY;
|
||||
|
||||
verify(falseContext).bindServiceAsUser(any(), any(), eq(flags), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersionLessThanUBindsAllowBackgroundActivity() {
|
||||
mockChangeEnabled(START_ACTIVITY_NEEDS_PENDING_INTENT, false);
|
||||
Context falseContext = mock(Context.class);
|
||||
TileLifecycleManager manager = new TileLifecycleManager(mHandler, falseContext,
|
||||
mock(IQSService.class),
|
||||
mMockPackageManagerAdapter,
|
||||
mMockBroadcastDispatcher,
|
||||
mTileServiceIntent,
|
||||
mUser);
|
||||
|
||||
manager.setBindService(true);
|
||||
int flags = Context.BIND_AUTO_CREATE
|
||||
| Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
|
||||
| Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
|
||||
| Context.BIND_WAIVE_PRIORITY;
|
||||
|
||||
verify(falseContext).bindServiceAsUser(any(), any(), eq(flags), any());
|
||||
}
|
||||
|
||||
private void mockChangeEnabled(long changeId, boolean enabled) {
|
||||
doReturn(enabled).when(() -> CompatChanges.isChangeEnabled(eq(changeId), anyString(),
|
||||
any(UserHandle.class)));
|
||||
}
|
||||
|
||||
private static class TestContextWrapper extends ContextWrapper {
|
||||
private IntentFilter mLastIntentFilter;
|
||||
private int mLastFlag;
|
||||
|
||||
Reference in New Issue
Block a user