Skip to content

Commit

Permalink
Merge tag 'android-13.0.0_r82' into thirteen
Browse files Browse the repository at this point in the history
Android 13.0.0 release 82

# -----BEGIN PGP SIGNATURE-----
#
# iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCZQiT4wAKCRDorT+BmrEO
# eNQXAJ4ofuZvXEZSBqXWIZ8eHHLF25NxNgCfU7HYBj7tW+Z7efP/Nll4NagtNHY=
# =bJqa
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 18 Sep 2023 08:16:03 PM CEST
# gpg:                using DSA key 4340D13570EF945E83810964E8AD3F819AB10E78
# gpg: Can't check signature: No public key

* tag 'android-13.0.0_r82' of https://android.googlesource.com/platform/frameworks/base: (25 commits)
  Keyguard: use transition state for syncing occlude [RESTRICT AUTOMERGE]
  Report folding features to letterboxed apps.
  Send update config change when letterbox is moved
  Cancel current animation instead of candidate
  Improve user handling when querying for resumable media
  Update AccountManagerService checkKeyIntentParceledCorrectly.
  Forbid granting access to NLSes with too-long component names
  Ignore virtual presentation windows - RESTRICT AUTOMERGE
  [DO NOT MERGE] Update quickshare intent rather than recreating
  Keyguard: use transition state for syncing occlude [RESTRICT AUTOMERGE]
  Report folding features to letterboxed apps.
  Send update config change when letterbox is moved
  Cancel current animation instead of candidate
  Keyguard: use transition state for syncing occlude [RESTRICT AUTOMERGE]
  Report folding features to letterboxed apps.
  Send update config change when letterbox is moved
  Cancel current animation instead of candidate
  Keyguard: use transition state for syncing occlude [RESTRICT AUTOMERGE]
  Report folding features to letterboxed apps.
  Send update config change when letterbox is moved
  ...
Change-Id: Iac2736cdb7885e98ce3e2f5766867e304d997096
  • Loading branch information
whyredfire committed Sep 18, 2023
2 parents 5358402 + 2391f08 commit 00843cf
Show file tree
Hide file tree
Showing 17 changed files with 537 additions and 77 deletions.
6 changes: 6 additions & 0 deletions core/java/android/app/NotificationManager.java
Expand Up @@ -571,6 +571,12 @@ public class NotificationManager {
*/
public static final int BUBBLE_PREFERENCE_SELECTED = 2;

/**
* Maximum length of the component name of a registered NotificationListenerService.
* @hide
*/
public static int MAX_SERVICE_COMPONENT_NAME_LENGTH = 500;

@UnsupportedAppUsage
private static INotificationManager sService;

Expand Down
Expand Up @@ -243,7 +243,9 @@ public String getPackageName() {
return mHelper != null ? mHelper.packageName : null;
}

public void updateState(@NonNull String packageName, int uid, boolean isEnabled) {
/** Updates enabled state based on associated package. */
public void updateState(
@NonNull String packageName, int uid, boolean isEnableAllowed, boolean isEnabled) {
mHelper.updatePackageDetails(packageName, uid);
if (mAppOpsManager == null) {
mAppOpsManager = getContext().getSystemService(AppOpsManager.class);
Expand All @@ -254,7 +256,9 @@ public void updateState(@NonNull String packageName, int uid, boolean isEnabled)
final boolean ecmEnabled = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enhancedConfirmationModeEnabled);
final boolean appOpsAllowed = !ecmEnabled || mode == AppOpsManager.MODE_ALLOWED;
if (isEnabled) {
if (!isEnableAllowed && !isEnabled) {
setEnabled(false);
} else if (isEnabled) {
setEnabled(true);
} else if (appOpsAllowed && isDisabledByAppOps()) {
setEnabled(true);
Expand Down
Expand Up @@ -122,9 +122,9 @@ constructor(
Log.e(TAG, "Error getting package information", e)
}

Log.d(TAG, "Adding resume controls $desc")
Log.d(TAG, "Adding resume controls for ${browser.userId}: $desc")
mediaDataManager.addResumptionControls(
currentUserId,
browser.userId,
desc,
resumeAction,
token,
Expand Down Expand Up @@ -196,7 +196,11 @@ constructor(
}
resumeComponents.add(component to lastPlayed)
}
Log.d(TAG, "loaded resume components ${resumeComponents.toArray().contentToString()}")
Log.d(
TAG,
"loaded resume components for $currentUserId: " +
"${resumeComponents.toArray().contentToString()}"
)

if (needsUpdate) {
// Save any missing times that we had to fill in
Expand All @@ -210,11 +214,21 @@ constructor(
return
}

val pm = context.packageManager
val now = systemClock.currentTimeMillis()
resumeComponents.forEach {
if (now.minus(it.second) <= RESUME_MEDIA_TIMEOUT) {
val browser = mediaBrowserFactory.create(mediaBrowserCallback, it.first)
browser.findRecentMedia()
// Verify that the service exists for this user
val intent = Intent(MediaBrowserService.SERVICE_INTERFACE)
intent.component = it.first
val inf = pm.resolveServiceAsUser(intent, 0, currentUserId)
if (inf != null) {
val browser =
mediaBrowserFactory.create(mediaBrowserCallback, it.first, currentUserId)
browser.findRecentMedia()
} else {
Log.d(TAG, "User $currentUserId does not have component ${it.first}")
}
}
}
}
Expand Down Expand Up @@ -244,7 +258,7 @@ constructor(
Log.d(TAG, "Checking for service component for " + data.packageName)
val pm = context.packageManager
val serviceIntent = Intent(MediaBrowserService.SERVICE_INTERFACE)
val resumeInfo = pm.queryIntentServices(serviceIntent, 0)
val resumeInfo = pm.queryIntentServicesAsUser(serviceIntent, 0, currentUserId)

val inf = resumeInfo?.filter { it.serviceInfo.packageName == data.packageName }
if (inf != null && inf.size > 0) {
Expand Down Expand Up @@ -280,13 +294,17 @@ constructor(
browser: ResumeMediaBrowser
) {
// Since this is a test, just save the component for later
Log.d(TAG, "Can get resumable media from $componentName")
Log.d(
TAG,
"Can get resumable media for ${browser.userId} from $componentName"
)
mediaDataManager.setResumeAction(key, getResumeAction(componentName))
updateResumptionList(componentName)
mediaBrowser = null
}
},
componentName
componentName,
currentUserId
)
mediaBrowser?.testConnection()
}
Expand Down Expand Up @@ -326,7 +344,7 @@ constructor(
/** Get a runnable which will resume media playback */
private fun getResumeAction(componentName: ComponentName): Runnable {
return Runnable {
mediaBrowser = mediaBrowserFactory.create(null, componentName)
mediaBrowser = mediaBrowserFactory.create(null, componentName, currentUserId)
mediaBrowser?.restart()
}
}
Expand Down
Expand Up @@ -17,6 +17,7 @@
package com.android.systemui.media.controls.resume;

import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
Expand Down Expand Up @@ -53,6 +54,7 @@ public class ResumeMediaBrowser {
private final ResumeMediaBrowserLogger mLogger;
private final ComponentName mComponentName;
private final MediaController.Callback mMediaControllerCallback = new SessionDestroyCallback();
@UserIdInt private final int mUserId;

private MediaBrowser mMediaBrowser;
@Nullable private MediaController mMediaController;
Expand All @@ -62,18 +64,21 @@ public class ResumeMediaBrowser {
* @param context the context
* @param callback used to report media items found
* @param componentName Component name of the MediaBrowserService this browser will connect to
* @param userId ID of the current user
*/
public ResumeMediaBrowser(
Context context,
@Nullable Callback callback,
ComponentName componentName,
MediaBrowserFactory browserFactory,
ResumeMediaBrowserLogger logger) {
ResumeMediaBrowserLogger logger,
@UserIdInt int userId) {
mContext = context;
mCallback = callback;
mComponentName = componentName;
mBrowserFactory = browserFactory;
mLogger = logger;
mUserId = userId;
}

/**
Expand Down Expand Up @@ -284,6 +289,14 @@ protected MediaController createMediaController(MediaSession.Token token) {
return new MediaController(mContext, token);
}

/**
* Get the ID of the user associated with this broswer
* @return the user ID
*/
public @UserIdInt int getUserId() {
return mUserId;
}

/**
* Get the media session token
* @return the token, or null if the MediaBrowser is null or disconnected
Expand Down
Expand Up @@ -16,6 +16,7 @@

package com.android.systemui.media.controls.resume;

import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;

Expand All @@ -42,10 +43,12 @@ public ResumeMediaBrowserFactory(
*
* @param callback will be called on connection or error, and addTrack when media item found
* @param componentName component to browse
* @param userId ID of the current user
* @return
*/
public ResumeMediaBrowser create(ResumeMediaBrowser.Callback callback,
ComponentName componentName) {
return new ResumeMediaBrowser(mContext, callback, componentName, mBrowserFactory, mLogger);
ComponentName componentName, @UserIdInt int userId) {
return new ResumeMediaBrowser(mContext, callback, componentName, mBrowserFactory, mLogger,
userId);
}
}
Expand Up @@ -141,7 +141,12 @@ protected Void doInBackground(String... params) {
// Since Quick Share target recommendation does not rely on image URL, it is
// queried and surfaced before image compress/export. Action intent would not be
// used, because it does not contain image URL.
queryQuickShareAction(image, user);
Notification.Action quickShare =
queryQuickShareAction(mScreenshotId, image, user, null);
if (quickShare != null) {
mQuickShareData.quickShareAction = quickShare;
mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
}
}

// Call synchronously here since already on a background thread.
Expand Down Expand Up @@ -181,9 +186,10 @@ protected Void doInBackground(String... params) {
smartActionsEnabled);
mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri,
smartActionsEnabled);
mImageData.quickShareAction = createQuickShareAction(mContext,
mQuickShareData.quickShareAction, uri);
mImageData.subject = getSubjectString();
mImageData.quickShareAction = createQuickShareAction(
mQuickShareData.quickShareAction, mScreenshotId, uri, mImageTime, image,
user);
mImageData.subject = getSubjectString(mImageTime);

mParams.mActionsReadyListener.onActionsReady(mImageData);
if (DEBUG_CALLBACK) {
Expand Down Expand Up @@ -258,7 +264,7 @@ Supplier<ActionTransition> createShareAction(Context context, Resources r, Uri u
new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}),
new ClipData.Item(uri));
sharingIntent.setClipData(clipdata);
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, getSubjectString());
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, getSubjectString(mImageTime));
sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

Expand Down Expand Up @@ -424,60 +430,73 @@ private static void addIntentExtras(String screenshotId, Intent intent, String a
}

/**
* Populate image uri into intent of Quick Share action.
* Wrap the quickshare intent and populate the fillin intent with the URI
*/
@VisibleForTesting
private Notification.Action createQuickShareAction(Context context, Notification.Action action,
Uri uri) {
if (action == null) {
Notification.Action createQuickShareAction(
Notification.Action quickShare, String screenshotId, Uri uri, long imageTime,
Bitmap image, UserHandle user) {
if (quickShare == null) {
return null;
} else if (quickShare.actionIntent.isImmutable()) {
Notification.Action quickShareWithUri =
queryQuickShareAction(screenshotId, image, user, uri);
if (quickShareWithUri == null
|| !quickShareWithUri.title.toString().contentEquals(quickShare.title)) {
return null;
}
quickShare = quickShareWithUri;
}
// Populate image URI into Quick Share chip intent
Intent sharingIntent = action.actionIntent.getIntent();
sharingIntent.setType("image/png");
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
// Include URI in ClipData also, so that grantPermission picks it up.
// We don't use setData here because some apps interpret this as "to:".
ClipData clipdata = new ClipData(new ClipDescription("content",
new String[]{"image/png"}),
new ClipData.Item(uri));
sharingIntent.setClipData(clipdata);
sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
PendingIntent updatedPendingIntent = PendingIntent.getActivity(
context, 0, sharingIntent,
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);

// Proxy smart actions through {@link SmartActionsReceiver} for logging smart actions.
Bundle extras = action.getExtras();

Intent wrappedIntent = new Intent(mContext, SmartActionsReceiver.class)
.putExtra(ScreenshotController.EXTRA_ACTION_INTENT, quickShare.actionIntent)
.putExtra(ScreenshotController.EXTRA_ACTION_INTENT_FILLIN,
createFillInIntent(uri, imageTime))
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Bundle extras = quickShare.getExtras();
String actionType = extras.getString(
ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE);
Intent intent = new Intent(context, SmartActionsReceiver.class)
.putExtra(ScreenshotController.EXTRA_ACTION_INTENT, updatedPendingIntent)
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
// We only query for quick share actions when smart actions are enabled, so we can assert
// that it's true here.
addIntentExtras(mScreenshotId, intent, actionType, true /* smartActionsEnabled */);
PendingIntent broadcastIntent = PendingIntent.getBroadcast(context,
mRandom.nextInt(),
intent,
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
return new Notification.Action.Builder(action.getIcon(), action.title,
broadcastIntent).setContextual(true).addExtras(extras).build();
addIntentExtras(screenshotId, wrappedIntent, actionType, true /* smartActionsEnabled */);
PendingIntent broadcastIntent =
PendingIntent.getBroadcast(mContext, mRandom.nextInt(), wrappedIntent,
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
return new Notification.Action.Builder(quickShare.getIcon(), quickShare.title,
broadcastIntent)
.setContextual(true)
.addExtras(extras)
.build();
}

private Intent createFillInIntent(Uri uri, long imageTime) {
Intent fillIn = new Intent();
fillIn.setType("image/png");
fillIn.putExtra(Intent.EXTRA_STREAM, uri);
fillIn.putExtra(Intent.EXTRA_SUBJECT, getSubjectString(imageTime));
// Include URI in ClipData also, so that grantPermission picks it up.
// We don't use setData here because some apps interpret this as "to:".
ClipData clipData = new ClipData(
new ClipDescription("content", new String[]{"image/png"}),
new ClipData.Item(uri));
fillIn.setClipData(clipData);
fillIn.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
return fillIn;
}

/**
* Query and surface Quick Share chip if it is available. Action intent would not be used,
* because it does not contain image URL which would be populated in {@link
* #createQuickShareAction(Context, Notification.Action, Uri)}
* #createQuickShareAction(Notification.Action, String, Uri, long, Bitmap, UserHandle)}
*/
private void queryQuickShareAction(Bitmap image, UserHandle user) {

@VisibleForTesting
Notification.Action queryQuickShareAction(
String screenshotId, Bitmap image, UserHandle user, Uri uri) {
CompletableFuture<List<Notification.Action>> quickShareActionsFuture =
mScreenshotSmartActions.getSmartActionsFuture(
mScreenshotId, null, image, mSmartActionsProvider,
screenshotId, uri, image, mSmartActionsProvider,
ScreenshotSmartActionType.QUICK_SHARE_ACTION,
true /* smartActionsEnabled */, user);
int timeoutMs = DeviceConfig.getInt(
Expand All @@ -486,17 +505,17 @@ private void queryQuickShareAction(Bitmap image, UserHandle user) {
500);
List<Notification.Action> quickShareActions =
mScreenshotSmartActions.getSmartActions(
mScreenshotId, quickShareActionsFuture, timeoutMs,
screenshotId, quickShareActionsFuture, timeoutMs,
mSmartActionsProvider,
ScreenshotSmartActionType.QUICK_SHARE_ACTION);
if (!quickShareActions.isEmpty()) {
mQuickShareData.quickShareAction = quickShareActions.get(0);
mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
return quickShareActions.get(0);
}
return null;
}

private String getSubjectString() {
String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
private static String getSubjectString(long imageTime) {
String subjectDate = DateFormat.getDateTimeInstance().format(new Date(imageTime));
return String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
}
}
Expand Up @@ -254,6 +254,7 @@ interface TransitionDestination {
static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled";
static final String EXTRA_OVERRIDE_TRANSITION = "android:screenshot_override_transition";
static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
static final String EXTRA_ACTION_INTENT_FILLIN = "android:screenshot_action_intent_fillin";

static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
Expand Down

0 comments on commit 00843cf

Please sign in to comment.