Skip to content

Commit 00ae4c3

Browse files
committed
Merge tag 'android-13.0.0_r75' into cr-11.0
Android 13.0.0 release 75 Change-Id: Ib373d3df6c507ab14539025d89ecdd47c555a285
2 parents ff99d66 + 292f896 commit 00ae4c3

17 files changed

Lines changed: 537 additions & 77 deletions

File tree

core/java/android/app/NotificationManager.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,12 @@ public class NotificationManager {
571571
*/
572572
public static final int BUBBLE_PREFERENCE_SELECTED = 2;
573573

574+
/**
575+
* Maximum length of the component name of a registered NotificationListenerService.
576+
* @hide
577+
*/
578+
public static int MAX_SERVICE_COMPONENT_NAME_LENGTH = 500;
579+
574580
@UnsupportedAppUsage
575581
private static INotificationManager sService;
576582

packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,9 @@ public String getPackageName() {
243243
return mHelper != null ? mHelper.packageName : null;
244244
}
245245

246-
public void updateState(@NonNull String packageName, int uid, boolean isEnabled) {
246+
/** Updates enabled state based on associated package. */
247+
public void updateState(
248+
@NonNull String packageName, int uid, boolean isEnableAllowed, boolean isEnabled) {
247249
mHelper.updatePackageDetails(packageName, uid);
248250
if (mAppOpsManager == null) {
249251
mAppOpsManager = getContext().getSystemService(AppOpsManager.class);
@@ -254,7 +256,9 @@ public void updateState(@NonNull String packageName, int uid, boolean isEnabled)
254256
final boolean ecmEnabled = getContext().getResources().getBoolean(
255257
com.android.internal.R.bool.config_enhancedConfirmationModeEnabled);
256258
final boolean appOpsAllowed = !ecmEnabled || mode == AppOpsManager.MODE_ALLOWED;
257-
if (isEnabled) {
259+
if (!isEnableAllowed && !isEnabled) {
260+
setEnabled(false);
261+
} else if (isEnabled) {
258262
setEnabled(true);
259263
} else if (appOpsAllowed && isDisabledByAppOps()) {
260264
setEnabled(true);

packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,9 @@ constructor(
122122
Log.e(TAG, "Error getting package information", e)
123123
}
124124

125-
Log.d(TAG, "Adding resume controls $desc")
125+
Log.d(TAG, "Adding resume controls for ${browser.userId}: $desc")
126126
mediaDataManager.addResumptionControls(
127-
currentUserId,
127+
browser.userId,
128128
desc,
129129
resumeAction,
130130
token,
@@ -196,7 +196,11 @@ constructor(
196196
}
197197
resumeComponents.add(component to lastPlayed)
198198
}
199-
Log.d(TAG, "loaded resume components ${resumeComponents.toArray().contentToString()}")
199+
Log.d(
200+
TAG,
201+
"loaded resume components for $currentUserId: " +
202+
"${resumeComponents.toArray().contentToString()}"
203+
)
200204

201205
if (needsUpdate) {
202206
// Save any missing times that we had to fill in
@@ -210,11 +214,21 @@ constructor(
210214
return
211215
}
212216

217+
val pm = context.packageManager
213218
val now = systemClock.currentTimeMillis()
214219
resumeComponents.forEach {
215220
if (now.minus(it.second) <= RESUME_MEDIA_TIMEOUT) {
216-
val browser = mediaBrowserFactory.create(mediaBrowserCallback, it.first)
217-
browser.findRecentMedia()
221+
// Verify that the service exists for this user
222+
val intent = Intent(MediaBrowserService.SERVICE_INTERFACE)
223+
intent.component = it.first
224+
val inf = pm.resolveServiceAsUser(intent, 0, currentUserId)
225+
if (inf != null) {
226+
val browser =
227+
mediaBrowserFactory.create(mediaBrowserCallback, it.first, currentUserId)
228+
browser.findRecentMedia()
229+
} else {
230+
Log.d(TAG, "User $currentUserId does not have component ${it.first}")
231+
}
218232
}
219233
}
220234
}
@@ -244,7 +258,7 @@ constructor(
244258
Log.d(TAG, "Checking for service component for " + data.packageName)
245259
val pm = context.packageManager
246260
val serviceIntent = Intent(MediaBrowserService.SERVICE_INTERFACE)
247-
val resumeInfo = pm.queryIntentServices(serviceIntent, 0)
261+
val resumeInfo = pm.queryIntentServicesAsUser(serviceIntent, 0, currentUserId)
248262

249263
val inf = resumeInfo?.filter { it.serviceInfo.packageName == data.packageName }
250264
if (inf != null && inf.size > 0) {
@@ -280,13 +294,17 @@ constructor(
280294
browser: ResumeMediaBrowser
281295
) {
282296
// Since this is a test, just save the component for later
283-
Log.d(TAG, "Can get resumable media from $componentName")
297+
Log.d(
298+
TAG,
299+
"Can get resumable media for ${browser.userId} from $componentName"
300+
)
284301
mediaDataManager.setResumeAction(key, getResumeAction(componentName))
285302
updateResumptionList(componentName)
286303
mediaBrowser = null
287304
}
288305
},
289-
componentName
306+
componentName,
307+
currentUserId
290308
)
291309
mediaBrowser?.testConnection()
292310
}
@@ -326,7 +344,7 @@ constructor(
326344
/** Get a runnable which will resume media playback */
327345
private fun getResumeAction(componentName: ComponentName): Runnable {
328346
return Runnable {
329-
mediaBrowser = mediaBrowserFactory.create(null, componentName)
347+
mediaBrowser = mediaBrowserFactory.create(null, componentName, currentUserId)
330348
mediaBrowser?.restart()
331349
}
332350
}

packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.android.systemui.media.controls.resume;
1818

1919
import android.annotation.Nullable;
20+
import android.annotation.UserIdInt;
2021
import android.app.PendingIntent;
2122
import android.content.ComponentName;
2223
import android.content.Context;
@@ -53,6 +54,7 @@ public class ResumeMediaBrowser {
5354
private final ResumeMediaBrowserLogger mLogger;
5455
private final ComponentName mComponentName;
5556
private final MediaController.Callback mMediaControllerCallback = new SessionDestroyCallback();
57+
@UserIdInt private final int mUserId;
5658

5759
private MediaBrowser mMediaBrowser;
5860
@Nullable private MediaController mMediaController;
@@ -62,18 +64,21 @@ public class ResumeMediaBrowser {
6264
* @param context the context
6365
* @param callback used to report media items found
6466
* @param componentName Component name of the MediaBrowserService this browser will connect to
67+
* @param userId ID of the current user
6568
*/
6669
public ResumeMediaBrowser(
6770
Context context,
6871
@Nullable Callback callback,
6972
ComponentName componentName,
7073
MediaBrowserFactory browserFactory,
71-
ResumeMediaBrowserLogger logger) {
74+
ResumeMediaBrowserLogger logger,
75+
@UserIdInt int userId) {
7276
mContext = context;
7377
mCallback = callback;
7478
mComponentName = componentName;
7579
mBrowserFactory = browserFactory;
7680
mLogger = logger;
81+
mUserId = userId;
7782
}
7883

7984
/**
@@ -284,6 +289,14 @@ protected MediaController createMediaController(MediaSession.Token token) {
284289
return new MediaController(mContext, token);
285290
}
286291

292+
/**
293+
* Get the ID of the user associated with this broswer
294+
* @return the user ID
295+
*/
296+
public @UserIdInt int getUserId() {
297+
return mUserId;
298+
}
299+
287300
/**
288301
* Get the media session token
289302
* @return the token, or null if the MediaBrowser is null or disconnected

packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserFactory.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

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

19+
import android.annotation.UserIdInt;
1920
import android.content.ComponentName;
2021
import android.content.Context;
2122

@@ -42,10 +43,12 @@ public ResumeMediaBrowserFactory(
4243
*
4344
* @param callback will be called on connection or error, and addTrack when media item found
4445
* @param componentName component to browse
46+
* @param userId ID of the current user
4547
* @return
4648
*/
4749
public ResumeMediaBrowser create(ResumeMediaBrowser.Callback callback,
48-
ComponentName componentName) {
49-
return new ResumeMediaBrowser(mContext, callback, componentName, mBrowserFactory, mLogger);
50+
ComponentName componentName, @UserIdInt int userId) {
51+
return new ResumeMediaBrowser(mContext, callback, componentName, mBrowserFactory, mLogger,
52+
userId);
5053
}
5154
}

packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java

Lines changed: 66 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,12 @@ protected Void doInBackground(Void... paramsUnused) {
141141
// Since Quick Share target recommendation does not rely on image URL, it is
142142
// queried and surfaced before image compress/export. Action intent would not be
143143
// used, because it does not contain image URL.
144-
queryQuickShareAction(image, user);
144+
Notification.Action quickShare =
145+
queryQuickShareAction(mScreenshotId, image, user, null);
146+
if (quickShare != null) {
147+
mQuickShareData.quickShareAction = quickShare;
148+
mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
149+
}
145150
}
146151

147152
// Call synchronously here since already on a background thread.
@@ -180,9 +185,10 @@ protected Void doInBackground(Void... paramsUnused) {
180185
smartActionsEnabled);
181186
mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri,
182187
smartActionsEnabled);
183-
mImageData.quickShareAction = createQuickShareAction(mContext,
184-
mQuickShareData.quickShareAction, uri);
185-
mImageData.subject = getSubjectString();
188+
mImageData.quickShareAction = createQuickShareAction(
189+
mQuickShareData.quickShareAction, mScreenshotId, uri, mImageTime, image,
190+
user);
191+
mImageData.subject = getSubjectString(mImageTime);
186192

187193
mParams.mActionsReadyListener.onActionsReady(mImageData);
188194
if (DEBUG_CALLBACK) {
@@ -257,7 +263,7 @@ Supplier<ActionTransition> createShareAction(Context context, Resources r, Uri u
257263
new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}),
258264
new ClipData.Item(uri));
259265
sharingIntent.setClipData(clipdata);
260-
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, getSubjectString());
266+
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, getSubjectString(mImageTime));
261267
sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
262268
.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
263269

@@ -423,60 +429,73 @@ private static void addIntentExtras(String screenshotId, Intent intent, String a
423429
}
424430

425431
/**
426-
* Populate image uri into intent of Quick Share action.
432+
* Wrap the quickshare intent and populate the fillin intent with the URI
427433
*/
428434
@VisibleForTesting
429-
private Notification.Action createQuickShareAction(Context context, Notification.Action action,
430-
Uri uri) {
431-
if (action == null) {
435+
Notification.Action createQuickShareAction(
436+
Notification.Action quickShare, String screenshotId, Uri uri, long imageTime,
437+
Bitmap image, UserHandle user) {
438+
if (quickShare == null) {
432439
return null;
440+
} else if (quickShare.actionIntent.isImmutable()) {
441+
Notification.Action quickShareWithUri =
442+
queryQuickShareAction(screenshotId, image, user, uri);
443+
if (quickShareWithUri == null
444+
|| !quickShareWithUri.title.toString().contentEquals(quickShare.title)) {
445+
return null;
446+
}
447+
quickShare = quickShareWithUri;
433448
}
434-
// Populate image URI into Quick Share chip intent
435-
Intent sharingIntent = action.actionIntent.getIntent();
436-
sharingIntent.setType("image/png");
437-
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
438-
String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
439-
String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
440-
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
441-
// Include URI in ClipData also, so that grantPermission picks it up.
442-
// We don't use setData here because some apps interpret this as "to:".
443-
ClipData clipdata = new ClipData(new ClipDescription("content",
444-
new String[]{"image/png"}),
445-
new ClipData.Item(uri));
446-
sharingIntent.setClipData(clipdata);
447-
sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
448-
PendingIntent updatedPendingIntent = PendingIntent.getActivity(
449-
context, 0, sharingIntent,
450-
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
451-
452-
// Proxy smart actions through {@link SmartActionsReceiver} for logging smart actions.
453-
Bundle extras = action.getExtras();
449+
450+
Intent wrappedIntent = new Intent(mContext, SmartActionsReceiver.class)
451+
.putExtra(ScreenshotController.EXTRA_ACTION_INTENT, quickShare.actionIntent)
452+
.putExtra(ScreenshotController.EXTRA_ACTION_INTENT_FILLIN,
453+
createFillInIntent(uri, imageTime))
454+
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
455+
Bundle extras = quickShare.getExtras();
454456
String actionType = extras.getString(
455457
ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
456458
ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE);
457-
Intent intent = new Intent(context, SmartActionsReceiver.class)
458-
.putExtra(ScreenshotController.EXTRA_ACTION_INTENT, updatedPendingIntent)
459-
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
460459
// We only query for quick share actions when smart actions are enabled, so we can assert
461460
// that it's true here.
462-
addIntentExtras(mScreenshotId, intent, actionType, true /* smartActionsEnabled */);
463-
PendingIntent broadcastIntent = PendingIntent.getBroadcast(context,
464-
mRandom.nextInt(),
465-
intent,
466-
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
467-
return new Notification.Action.Builder(action.getIcon(), action.title,
468-
broadcastIntent).setContextual(true).addExtras(extras).build();
461+
addIntentExtras(screenshotId, wrappedIntent, actionType, true /* smartActionsEnabled */);
462+
PendingIntent broadcastIntent =
463+
PendingIntent.getBroadcast(mContext, mRandom.nextInt(), wrappedIntent,
464+
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
465+
return new Notification.Action.Builder(quickShare.getIcon(), quickShare.title,
466+
broadcastIntent)
467+
.setContextual(true)
468+
.addExtras(extras)
469+
.build();
470+
}
471+
472+
private Intent createFillInIntent(Uri uri, long imageTime) {
473+
Intent fillIn = new Intent();
474+
fillIn.setType("image/png");
475+
fillIn.putExtra(Intent.EXTRA_STREAM, uri);
476+
fillIn.putExtra(Intent.EXTRA_SUBJECT, getSubjectString(imageTime));
477+
// Include URI in ClipData also, so that grantPermission picks it up.
478+
// We don't use setData here because some apps interpret this as "to:".
479+
ClipData clipData = new ClipData(
480+
new ClipDescription("content", new String[]{"image/png"}),
481+
new ClipData.Item(uri));
482+
fillIn.setClipData(clipData);
483+
fillIn.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
484+
return fillIn;
469485
}
470486

471487
/**
472488
* Query and surface Quick Share chip if it is available. Action intent would not be used,
473489
* because it does not contain image URL which would be populated in {@link
474-
* #createQuickShareAction(Context, Notification.Action, Uri)}
490+
* #createQuickShareAction(Notification.Action, String, Uri, long, Bitmap, UserHandle)}
475491
*/
476-
private void queryQuickShareAction(Bitmap image, UserHandle user) {
492+
493+
@VisibleForTesting
494+
Notification.Action queryQuickShareAction(
495+
String screenshotId, Bitmap image, UserHandle user, Uri uri) {
477496
CompletableFuture<List<Notification.Action>> quickShareActionsFuture =
478497
mScreenshotSmartActions.getSmartActionsFuture(
479-
mScreenshotId, null, image, mSmartActionsProvider,
498+
screenshotId, uri, image, mSmartActionsProvider,
480499
ScreenshotSmartActionType.QUICK_SHARE_ACTION,
481500
true /* smartActionsEnabled */, user);
482501
int timeoutMs = DeviceConfig.getInt(
@@ -485,17 +504,17 @@ private void queryQuickShareAction(Bitmap image, UserHandle user) {
485504
500);
486505
List<Notification.Action> quickShareActions =
487506
mScreenshotSmartActions.getSmartActions(
488-
mScreenshotId, quickShareActionsFuture, timeoutMs,
507+
screenshotId, quickShareActionsFuture, timeoutMs,
489508
mSmartActionsProvider,
490509
ScreenshotSmartActionType.QUICK_SHARE_ACTION);
491510
if (!quickShareActions.isEmpty()) {
492-
mQuickShareData.quickShareAction = quickShareActions.get(0);
493-
mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
511+
return quickShareActions.get(0);
494512
}
513+
return null;
495514
}
496515

497-
private String getSubjectString() {
498-
String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
516+
private static String getSubjectString(long imageTime) {
517+
String subjectDate = DateFormat.getDateTimeInstance().format(new Date(imageTime));
499518
return String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
500519
}
501520
}

packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ interface TransitionDestination {
246246
static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled";
247247
static final String EXTRA_OVERRIDE_TRANSITION = "android:screenshot_override_transition";
248248
static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
249+
static final String EXTRA_ACTION_INTENT_FILLIN = "android:screenshot_action_intent_fillin";
249250

250251
static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
251252
static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";

0 commit comments

Comments
 (0)