Merge "Add API for requesting add TileService"
This commit is contained in:
committed by
Android (Google) Code Review
commit
d53d2d0d23
@@ -6694,6 +6694,16 @@ package android.app {
|
||||
}
|
||||
|
||||
public class StatusBarManager {
|
||||
method public int requestAddTileService(@NonNull android.content.ComponentName, @NonNull CharSequence, @NonNull android.graphics.drawable.Icon, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
|
||||
field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_BAD_COMPONENT = 3; // 0x3
|
||||
field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_MISMATCHED_PACKAGE = 1; // 0x1
|
||||
field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_NOT_CURRENT_USER = 4; // 0x4
|
||||
field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_REQUEST_IN_PROGRESS = 2; // 0x2
|
||||
field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON = 5; // 0x5
|
||||
field public static final int TILE_ADD_REQUEST_ANSWER_SUCCESS = 0; // 0x0
|
||||
field public static final int TILE_ADD_REQUEST_RESULT_TILE_ADDED = 2; // 0x2
|
||||
field public static final int TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED = 1; // 0x1
|
||||
field public static final int TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED = 0; // 0x0
|
||||
}
|
||||
|
||||
public final class SyncNotedAppOp implements android.os.Parcelable {
|
||||
@@ -10696,6 +10706,7 @@ package android.content {
|
||||
field public static final String SEARCH_SERVICE = "search";
|
||||
field public static final String SENSOR_SERVICE = "sensor";
|
||||
field public static final String SHORTCUT_SERVICE = "shortcut";
|
||||
field public static final String STATUS_BAR_SERVICE = "statusbar";
|
||||
field public static final String STORAGE_SERVICE = "storage";
|
||||
field public static final String STORAGE_STATS_SERVICE = "storagestats";
|
||||
field public static final String SYSTEM_HEALTH_SERVICE = "systemhealth";
|
||||
|
||||
@@ -2353,7 +2353,6 @@ package android.content {
|
||||
field public static final String SECURE_ELEMENT_SERVICE = "secure_element";
|
||||
field public static final String SMARTSPACE_SERVICE = "smartspace";
|
||||
field public static final String STATS_MANAGER = "stats";
|
||||
field public static final String STATUS_BAR_SERVICE = "statusbar";
|
||||
field public static final String SYSTEM_CONFIG_SERVICE = "system_config";
|
||||
field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
|
||||
field public static final String TETHERING_SERVICE = "tethering";
|
||||
|
||||
@@ -24,7 +24,9 @@ import android.annotation.SystemApi;
|
||||
import android.annotation.SystemService;
|
||||
import android.annotation.TestApi;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@@ -35,11 +37,15 @@ import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.internal.statusbar.IAddTileResultCallback;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.internal.statusbar.NotificationVisibility;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Allows an app to control the status bar.
|
||||
@@ -206,6 +212,71 @@ public class StatusBarManager {
|
||||
/** @hide */
|
||||
public static final int CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER = 2;
|
||||
|
||||
/**
|
||||
* Response indicating that the tile was not added.
|
||||
*/
|
||||
public static final int TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED = 0;
|
||||
/**
|
||||
* Response indicating that the tile was already added and the user was not prompted.
|
||||
*/
|
||||
public static final int TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED = 1;
|
||||
/**
|
||||
* Response indicating that the tile was added.
|
||||
*/
|
||||
public static final int TILE_ADD_REQUEST_RESULT_TILE_ADDED = 2;
|
||||
/** @hide */
|
||||
public static final int TILE_ADD_REQUEST_RESULT_DIALOG_DISMISSED = 3;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = {"TILE_ADD_REQUEST_RESULT_"}, value = {
|
||||
TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED,
|
||||
TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED,
|
||||
TILE_ADD_REQUEST_RESULT_TILE_ADDED,
|
||||
TILE_ADD_REQUEST_RESULT_DIALOG_DISMISSED
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface RequestResult {}
|
||||
|
||||
/**
|
||||
* Indicates that the request was sent successfully. Does not indicate that the user
|
||||
* has accepted the request.
|
||||
*/
|
||||
public static final int TILE_ADD_REQUEST_ANSWER_SUCCESS = 0;
|
||||
/**
|
||||
* Indicates that this package does not match that of the
|
||||
* {@link android.service.quicksettings.TileService}.
|
||||
*/
|
||||
public static final int TILE_ADD_REQUEST_ANSWER_FAILED_MISMATCHED_PACKAGE = 1;
|
||||
/**
|
||||
* Indicates that there's a request in progress for this package.
|
||||
*/
|
||||
public static final int TILE_ADD_REQUEST_ANSWER_FAILED_REQUEST_IN_PROGRESS = 2;
|
||||
/**
|
||||
* Indicates that the component does not match an enabled
|
||||
* {@link android.service.quicksettings.TileService} for the current user.
|
||||
*/
|
||||
public static final int TILE_ADD_REQUEST_ANSWER_FAILED_BAD_COMPONENT = 3;
|
||||
/**
|
||||
* Indicates that the user is not the current user.
|
||||
*/
|
||||
public static final int TILE_ADD_REQUEST_ANSWER_FAILED_NOT_CURRENT_USER = 4;
|
||||
/**
|
||||
* The request could not be processed due to an unkonwn reason.
|
||||
*/
|
||||
public static final int TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON = 5;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = {"TILE_ADD_REQUEST_ANSWER_"}, value = {
|
||||
TILE_ADD_REQUEST_ANSWER_SUCCESS,
|
||||
TILE_ADD_REQUEST_ANSWER_FAILED_MISMATCHED_PACKAGE,
|
||||
TILE_ADD_REQUEST_ANSWER_FAILED_REQUEST_IN_PROGRESS,
|
||||
TILE_ADD_REQUEST_ANSWER_FAILED_BAD_COMPONENT,
|
||||
TILE_ADD_REQUEST_ANSWER_FAILED_NOT_CURRENT_USER,
|
||||
TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface RequestAnswer {}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
private Context mContext;
|
||||
private IStatusBarService mService;
|
||||
@@ -529,6 +600,69 @@ public class StatusBarManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request to the user to add a {@link android.service.quicksettings.TileService}
|
||||
* to the set of current QS tiles.
|
||||
* <p>
|
||||
* Calling this will prompt the user to decide whether they want to add the shown
|
||||
* {@link android.service.quicksettings.TileService} to their current tiles. The user can
|
||||
* deny the request and the system can stop processing requests for a given
|
||||
* {@link ComponentName} after a number of requests.
|
||||
* <p>
|
||||
* The request will show to the user information about the tile:
|
||||
* <ul>
|
||||
* <li>Application name</li>
|
||||
* <li>Label for the tile</li>
|
||||
* <li>Icon for the tile</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The user for which this will be added is determined from the {@link Context} used to retrieve
|
||||
* this service, and must match the current user.
|
||||
*
|
||||
* @param tileServiceComponentName {@link ComponentName} of the
|
||||
* {@link android.service.quicksettings.TileService} for the request.
|
||||
* @param tileLabel label of the tile to show to the user.
|
||||
* @param icon icon to use in the tile shown to the user.
|
||||
* @param resultExecutor an executor to run the callback on
|
||||
* @param resultCallback callback to indicate the {@link RequestResult}.
|
||||
* @return whether the request was successfully sent.
|
||||
*
|
||||
* @see android.service.quicksettings.TileService
|
||||
*/
|
||||
@RequestAnswer
|
||||
public int requestAddTileService(
|
||||
@NonNull ComponentName tileServiceComponentName,
|
||||
@NonNull CharSequence tileLabel,
|
||||
@NonNull Icon icon,
|
||||
@NonNull Executor resultExecutor,
|
||||
@NonNull Consumer<Integer> resultCallback
|
||||
) {
|
||||
Objects.requireNonNull(tileServiceComponentName);
|
||||
Objects.requireNonNull(tileLabel);
|
||||
Objects.requireNonNull(icon);
|
||||
Objects.requireNonNull(resultExecutor);
|
||||
Objects.requireNonNull(resultCallback);
|
||||
if (!tileServiceComponentName.getPackageName().equals(mContext.getPackageName())) {
|
||||
return TILE_ADD_REQUEST_ANSWER_FAILED_MISMATCHED_PACKAGE;
|
||||
}
|
||||
int userId = mContext.getUserId();
|
||||
RequestResultCallback callbackProxy = new RequestResultCallback(resultExecutor,
|
||||
resultCallback);
|
||||
IStatusBarService svc = getService();
|
||||
try {
|
||||
return svc.requestAddTile(
|
||||
tileServiceComponentName,
|
||||
tileLabel,
|
||||
icon,
|
||||
userId,
|
||||
callbackProxy
|
||||
);
|
||||
} catch (RemoteException ex) {
|
||||
ex.rethrowFromSystemServer();
|
||||
}
|
||||
return TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static String windowStateToString(int state) {
|
||||
if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
|
||||
@@ -773,4 +907,25 @@ public class StatusBarManager {
|
||||
return new Pair<Integer, Integer>(disable1, disable2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
static final class RequestResultCallback extends IAddTileResultCallback.Stub {
|
||||
|
||||
@NonNull
|
||||
private final Executor mExecutor;
|
||||
@NonNull
|
||||
private final Consumer<Integer> mCallback;
|
||||
|
||||
RequestResultCallback(@NonNull Executor executor, @NonNull Consumer<Integer> callback) {
|
||||
mExecutor = executor;
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTileRequest(int userResponse) {
|
||||
mExecutor.execute(() -> mCallback.accept(userResponse));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4295,14 +4295,12 @@ public abstract class Context {
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve a {@link
|
||||
* android.app.StatusBarManager} for interacting with the status bar.
|
||||
* android.app.StatusBarManager} for interacting with the status bar and quick settings.
|
||||
*
|
||||
* @see #getSystemService(String)
|
||||
* @see android.app.StatusBarManager
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@SuppressLint("ServiceName")
|
||||
public static final String STATUS_BAR_SERVICE = "statusbar";
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2021, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.statusbar;
|
||||
|
||||
/** {@hide} */
|
||||
oneway interface IAddTileResultCallback {
|
||||
void onTileRequest(int userResponse);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package com.android.internal.statusbar;
|
||||
|
||||
import android.app.ITransientNotificationCallback;
|
||||
import android.content.ComponentName;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.biometrics.IBiometricSysuiReceiver;
|
||||
import android.hardware.biometrics.PromptInfo;
|
||||
@@ -27,6 +28,7 @@ import android.os.ParcelFileDescriptor;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.view.InsetsVisibilities;
|
||||
|
||||
import com.android.internal.statusbar.IAddTileResultCallback;
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.internal.view.AppearanceRegion;
|
||||
|
||||
@@ -286,4 +288,6 @@ oneway interface IStatusBar
|
||||
* Triggers a GC in the system and status bar.
|
||||
*/
|
||||
void runGcForTest();
|
||||
|
||||
void requestAddTile(in ComponentName componentName, in CharSequence appName, in CharSequence label, in Icon icon, in IAddTileResultCallback callback);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.internal.statusbar;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.content.ComponentName;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.biometrics.IBiometricSysuiReceiver;
|
||||
import android.hardware.biometrics.PromptInfo;
|
||||
@@ -27,6 +28,7 @@ import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
|
||||
import com.android.internal.statusbar.IAddTileResultCallback;
|
||||
import com.android.internal.statusbar.IStatusBar;
|
||||
import com.android.internal.statusbar.RegisterStatusBarResult;
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
@@ -157,4 +159,6 @@ interface IStatusBarService
|
||||
* display.
|
||||
*/
|
||||
void suppressAmbientDisplay(boolean suppress);
|
||||
|
||||
int requestAddTile(in ComponentName componentName, in CharSequence label, in Icon icon, int userId, in IAddTileResultCallback callback);
|
||||
}
|
||||
|
||||
@@ -17,17 +17,20 @@
|
||||
package com.android.systemui.qs.external
|
||||
|
||||
import android.app.Dialog
|
||||
import android.app.StatusBarManager
|
||||
import android.content.ComponentName
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.drawable.Icon
|
||||
import android.util.Log
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.internal.statusbar.IAddTileResultCallback
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.qs.QSTileHost
|
||||
import com.android.systemui.statusbar.commandline.Command
|
||||
import com.android.systemui.statusbar.commandline.CommandRegistry
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialog
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.statusbar.CommandQueue
|
||||
import java.io.PrintWriter
|
||||
import java.util.function.Consumer
|
||||
import javax.inject.Inject
|
||||
@@ -39,24 +42,41 @@ private const val TAG = "TileServiceRequestController"
|
||||
*/
|
||||
class TileServiceRequestController constructor(
|
||||
private val qsTileHost: QSTileHost,
|
||||
private val commandQueue: CommandQueue,
|
||||
private val commandRegistry: CommandRegistry,
|
||||
private val dialogCreator: () -> TileRequestDialog = { TileRequestDialog(qsTileHost.context) }
|
||||
) {
|
||||
|
||||
companion object {
|
||||
// Temporary return values while there's no API
|
||||
internal const val ADD_TILE = 0
|
||||
internal const val DONT_ADD_TILE = 1
|
||||
internal const val TILE_ALREADY_ADDED = 2
|
||||
internal const val ADD_TILE = StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_ADDED
|
||||
internal const val DONT_ADD_TILE = StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED
|
||||
internal const val TILE_ALREADY_ADDED =
|
||||
StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED
|
||||
internal const val DISMISSED = 3
|
||||
}
|
||||
|
||||
private val commandQueueCallback = object : CommandQueue.Callbacks {
|
||||
override fun requestAddTile(
|
||||
componentName: ComponentName,
|
||||
appName: CharSequence,
|
||||
label: CharSequence,
|
||||
icon: Icon,
|
||||
callback: IAddTileResultCallback
|
||||
) {
|
||||
requestTileAdd(componentName, appName, label, icon) {
|
||||
callback.onTileRequest(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun init() {
|
||||
commandRegistry.registerCommand("tile-service-add") { TileServiceRequestCommand() }
|
||||
commandQueue.addCallback(commandQueueCallback)
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
commandRegistry.unregisterCommand("tile-service-add")
|
||||
commandQueue.removeCallback(commandQueueCallback)
|
||||
}
|
||||
|
||||
private fun addTile(componentName: ComponentName) {
|
||||
@@ -133,10 +153,11 @@ class TileServiceRequestController constructor(
|
||||
|
||||
@SysUISingleton
|
||||
class Builder @Inject constructor(
|
||||
private val commandQueue: CommandQueue,
|
||||
private val commandRegistry: CommandRegistry
|
||||
) {
|
||||
fun create(qsTileHost: QSTileHost): TileServiceRequestController {
|
||||
return TileServiceRequestController(qsTileHost, commandRegistry)
|
||||
return TileServiceRequestController(qsTileHost, commandQueue, commandRegistry)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import android.app.StatusBarManager.WindowType;
|
||||
import android.app.StatusBarManager.WindowVisibleState;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.hardware.biometrics.BiometricAuthenticator.Modality;
|
||||
import android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
|
||||
import android.hardware.biometrics.IBiometricSysuiReceiver;
|
||||
@@ -58,6 +59,7 @@ import android.view.WindowInsetsController.Behavior;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.os.SomeArgs;
|
||||
import com.android.internal.statusbar.IAddTileResultCallback;
|
||||
import com.android.internal.statusbar.IStatusBar;
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.internal.util.GcUtils;
|
||||
@@ -149,6 +151,7 @@ public class CommandQueue extends IStatusBar.Stub implements
|
||||
private static final int MSG_EMERGENCY_ACTION_LAUNCH_GESTURE = 58 << MSG_SHIFT;
|
||||
private static final int MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED = 59 << MSG_SHIFT;
|
||||
private static final int MSG_SET_UDFPS_HBM_LISTENER = 60 << MSG_SHIFT;
|
||||
private static final int MSG_TILE_SERVICE_REQUEST_ADD = 61 << MSG_SHIFT;
|
||||
|
||||
public static final int FLAG_EXCLUDE_NONE = 0;
|
||||
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
|
||||
@@ -403,6 +406,16 @@ public class CommandQueue extends IStatusBar.Stub implements
|
||||
* @see IStatusBar#setNavigationBarLumaSamplingEnabled(int, boolean)
|
||||
*/
|
||||
default void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {}
|
||||
|
||||
/**
|
||||
* @see IStatusBar#requestAddTile
|
||||
*/
|
||||
default void requestAddTile(
|
||||
@NonNull ComponentName componentName,
|
||||
@NonNull CharSequence appName,
|
||||
@NonNull CharSequence label,
|
||||
@NonNull Icon icon,
|
||||
@NonNull IAddTileResultCallback callback) {}
|
||||
}
|
||||
|
||||
public CommandQueue(Context context) {
|
||||
@@ -1108,6 +1121,23 @@ public class CommandQueue extends IStatusBar.Stub implements
|
||||
GcUtils.runGcAndFinalizersSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestAddTile(
|
||||
@NonNull ComponentName componentName,
|
||||
@NonNull CharSequence appName,
|
||||
@NonNull CharSequence label,
|
||||
@NonNull Icon icon,
|
||||
@NonNull IAddTileResultCallback callback
|
||||
) {
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = componentName;
|
||||
args.arg2 = appName;
|
||||
args.arg3 = label;
|
||||
args.arg4 = icon;
|
||||
args.arg5 = callback;
|
||||
mHandler.obtainMessage(MSG_TILE_SERVICE_REQUEST_ADD, args).sendToTarget();
|
||||
}
|
||||
|
||||
private final class H extends Handler {
|
||||
private H(Looper l) {
|
||||
super(l);
|
||||
@@ -1481,6 +1511,19 @@ public class CommandQueue extends IStatusBar.Stub implements
|
||||
msg.arg2 != 0);
|
||||
}
|
||||
break;
|
||||
case MSG_TILE_SERVICE_REQUEST_ADD:
|
||||
args = (SomeArgs) msg.obj;
|
||||
ComponentName componentName = (ComponentName) args.arg1;
|
||||
CharSequence appName = (CharSequence) args.arg2;
|
||||
CharSequence label = (CharSequence) args.arg3;
|
||||
Icon icon = (Icon) args.arg4;
|
||||
IAddTileResultCallback callback = (IAddTileResultCallback) args.arg5;
|
||||
for (int i = 0; i < mCallbacks.size(); i++) {
|
||||
mCallbacks.get(i).requestAddTile(
|
||||
componentName, appName, label, icon, callback);
|
||||
}
|
||||
args.recycle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,10 @@ import android.content.DialogInterface
|
||||
import android.graphics.drawable.Icon
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.internal.statusbar.IAddTileResultCallback
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.qs.QSTileHost
|
||||
import com.android.systemui.statusbar.CommandQueue
|
||||
import com.android.systemui.statusbar.commandline.CommandRegistry
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.capture
|
||||
@@ -36,6 +38,7 @@ import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.anyBoolean
|
||||
import org.mockito.Mockito.anyInt
|
||||
import org.mockito.Mockito.anyString
|
||||
import org.mockito.Mockito.atLeastOnce
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
@@ -58,6 +61,8 @@ class TileServiceRequestControllerTest : SysuiTestCase() {
|
||||
@Mock
|
||||
private lateinit var commandRegistry: CommandRegistry
|
||||
@Mock
|
||||
private lateinit var commandQueue: CommandQueue
|
||||
@Mock
|
||||
private lateinit var icon: Icon
|
||||
|
||||
private lateinit var controller: TileServiceRequestController
|
||||
@@ -69,7 +74,7 @@ class TileServiceRequestControllerTest : SysuiTestCase() {
|
||||
// Tile not present by default
|
||||
`when`(qsTileHost.indexOf(anyString())).thenReturn(-1)
|
||||
|
||||
controller = TileServiceRequestController(qsTileHost, commandRegistry) {
|
||||
controller = TileServiceRequestController(qsTileHost, commandQueue, commandRegistry) {
|
||||
tileRequestDialog
|
||||
}
|
||||
|
||||
@@ -152,11 +157,44 @@ class TileServiceRequestControllerTest : SysuiTestCase() {
|
||||
verify(qsTileHost, never()).addTile(any(ComponentName::class.java), anyBoolean())
|
||||
}
|
||||
|
||||
private class Callback : Consumer<Int> {
|
||||
@Test
|
||||
fun commandQueueCallback_registered() {
|
||||
verify(commandQueue).addCallback(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun commandQueueCallback_dataPassedToDialog() {
|
||||
val captor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
|
||||
verify(commandQueue, atLeastOnce()).addCallback(capture(captor))
|
||||
|
||||
captor.value.requestAddTile(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, Callback())
|
||||
|
||||
verify(tileRequestDialog).setTileData(
|
||||
TileRequestDialog.TileData(TEST_APP_NAME, TEST_LABEL, icon)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun commandQueueCallback_callbackCalled() {
|
||||
`when`(qsTileHost.indexOf(CustomTile.toSpec(TEST_COMPONENT))).thenReturn(2)
|
||||
val captor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
|
||||
verify(commandQueue, atLeastOnce()).addCallback(capture(captor))
|
||||
val c = Callback()
|
||||
|
||||
captor.value.requestAddTile(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, c)
|
||||
|
||||
assertThat(c.lastAccepted).isEqualTo(TileServiceRequestController.TILE_ALREADY_ADDED)
|
||||
}
|
||||
|
||||
private class Callback : IAddTileResultCallback.Stub(), Consumer<Int> {
|
||||
var lastAccepted: Int? = null
|
||||
private set
|
||||
override fun accept(t: Int) {
|
||||
lastAccepted = t
|
||||
}
|
||||
|
||||
override fun onTileRequest(r: Int) {
|
||||
accept(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,9 @@ import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.ITransientNotificationCallback;
|
||||
import android.app.Notification;
|
||||
@@ -31,7 +33,11 @@ import android.compat.annotation.ChangeId;
|
||||
import android.compat.annotation.EnabledSince;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.hardware.biometrics.BiometricAuthenticator.Modality;
|
||||
import android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
|
||||
import android.hardware.biometrics.IBiometricSysuiReceiver;
|
||||
@@ -53,6 +59,7 @@ import android.os.ResultReceiver;
|
||||
import android.os.ShellCallback;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.NotificationStats;
|
||||
import android.service.quicksettings.TileService;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
@@ -68,6 +75,7 @@ import com.android.internal.R;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.inputmethod.SoftInputShowHideReason;
|
||||
import com.android.internal.os.TransferPipe;
|
||||
import com.android.internal.statusbar.IAddTileResultCallback;
|
||||
import com.android.internal.statusbar.IStatusBar;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.internal.statusbar.NotificationVisibility;
|
||||
@@ -123,7 +131,9 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final DeathRecipient mDeathRecipient = new DeathRecipient();
|
||||
private final ActivityManagerInternal mActivityManagerInternal;
|
||||
private final ActivityTaskManagerInternal mActivityTaskManager;
|
||||
private final PackageManagerInternal mPackageManagerInternal;
|
||||
private int mCurrentUserId;
|
||||
private boolean mTracingEnabled;
|
||||
|
||||
@@ -227,6 +237,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
|
||||
(DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
|
||||
displayManager.registerDisplayListener(this, mHandler);
|
||||
mActivityTaskManager = LocalServices.getService(ActivityTaskManagerInternal.class);
|
||||
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
|
||||
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1640,6 +1652,96 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCallingUidPackage(String packageName, int callingUid, int userId) {
|
||||
int packageUid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
|
||||
if (UserHandle.getAppId(callingUid) != UserHandle.getAppId(packageUid)) {
|
||||
throw new SecurityException("Package " + packageName
|
||||
+ " does not belong to the calling uid " + callingUid);
|
||||
}
|
||||
}
|
||||
|
||||
private ResolveInfo isComponentValidTileService(ComponentName componentName, int userId) {
|
||||
Intent intent = new Intent(TileService.ACTION_QS_TILE);
|
||||
intent.setComponent(componentName);
|
||||
ResolveInfo r = mPackageManagerInternal.resolveService(intent,
|
||||
intent.resolveTypeIfNeeded(mContext.getContentResolver()), 0, userId,
|
||||
Process.myUid());
|
||||
int enabled = mPackageManagerInternal.getComponentEnabledSetting(
|
||||
componentName, Process.myUid(), userId);
|
||||
if (r != null
|
||||
&& r.serviceInfo != null
|
||||
&& resolveEnabledComponent(r.serviceInfo.enabled, enabled)
|
||||
&& Manifest.permission.BIND_QUICK_SETTINGS_TILE.equals(r.serviceInfo.permission)) {
|
||||
return r;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean resolveEnabledComponent(boolean defaultValue, int pmResult) {
|
||||
if (pmResult == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
|
||||
return true;
|
||||
}
|
||||
if (pmResult == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
|
||||
return defaultValue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int requestAddTile(
|
||||
@NonNull ComponentName componentName,
|
||||
@NonNull CharSequence label,
|
||||
@NonNull Icon icon,
|
||||
int userId,
|
||||
@NonNull IAddTileResultCallback callback
|
||||
) {
|
||||
int callingUid = Binder.getCallingUid();
|
||||
String packageName = componentName.getPackageName();
|
||||
|
||||
// Check calling user can act on behalf of current user
|
||||
mActivityManagerInternal.handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
|
||||
false, ActivityManagerInternal.ALLOW_NON_FULL, "requestAddTile", packageName);
|
||||
|
||||
// Check calling uid matches package
|
||||
checkCallingUidPackage(packageName, callingUid, userId);
|
||||
|
||||
int currentUser = mActivityManagerInternal.getCurrentUserId();
|
||||
|
||||
// Check current user
|
||||
if (userId != currentUser) {
|
||||
return StatusBarManager.TILE_ADD_REQUEST_ANSWER_FAILED_NOT_CURRENT_USER;
|
||||
}
|
||||
|
||||
// We've checked that the package, component name and uid all match.
|
||||
ResolveInfo r = isComponentValidTileService(componentName, userId);
|
||||
if (r == null) {
|
||||
return StatusBarManager.TILE_ADD_REQUEST_ANSWER_FAILED_BAD_COMPONENT;
|
||||
}
|
||||
|
||||
IAddTileResultCallback proxyCallback = new IAddTileResultCallback.Stub() {
|
||||
@Override
|
||||
public void onTileRequest(int i) throws RemoteException {
|
||||
if (i == StatusBarManager.TILE_ADD_REQUEST_RESULT_DIALOG_DISMISSED) {
|
||||
i = StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED;
|
||||
}
|
||||
callback.onTileRequest(i);
|
||||
}
|
||||
};
|
||||
|
||||
CharSequence appName = r.serviceInfo.applicationInfo
|
||||
.loadLabel(mContext.getPackageManager());
|
||||
if (mBar != null) {
|
||||
try {
|
||||
mBar.requestAddTile(componentName, appName, label, icon, proxyCallback);
|
||||
return StatusBarManager.TILE_ADD_REQUEST_ANSWER_SUCCESS;
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "requestAddTile", e);
|
||||
}
|
||||
}
|
||||
return StatusBarManager.TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON;
|
||||
}
|
||||
|
||||
public String[] getStatusBarIcons() {
|
||||
return mContext.getResources().getStringArray(R.array.config_statusBarIcons);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user