diff options
28 files changed, 495 insertions, 77 deletions
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java index fb78789ba8ad..cfb363a0834c 100644 --- a/core/java/android/bluetooth/BluetoothPan.java +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -118,6 +118,8 @@ public final class BluetoothPan implements BluetoothProfile { */ public static final int PAN_OPERATION_SUCCESS = 1004; + private final Context mContext; + private BluetoothAdapter mAdapter; private final BluetoothProfileConnector<IBluetoothPan> mProfileConnector = new BluetoothProfileConnector(this, BluetoothProfile.PAN, @@ -136,6 +138,7 @@ public final class BluetoothPan implements BluetoothProfile { @UnsupportedAppUsage /*package*/ BluetoothPan(Context context, ServiceListener listener) { mAdapter = BluetoothAdapter.getDefaultAdapter(); + mContext = context; mProfileConnector.connect(context, listener); } @@ -287,11 +290,12 @@ public final class BluetoothPan implements BluetoothProfile { @UnsupportedAppUsage public void setBluetoothTethering(boolean value) { - if (DBG) log("setBluetoothTethering(" + value + ")"); + String pkgName = mContext.getOpPackageName(); + if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName); final IBluetoothPan service = getService(); if (service != null && isEnabled()) { try { - service.setBluetoothTethering(value); + service.setBluetoothTethering(value, pkgName); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); } diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 9d523633feb6..099dea29eaf7 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -60,9 +60,7 @@ import java.util.Set; * multiple possible matching values (via {@link #addAction}, * {@link #addDataType}, {@link #addDataScheme}, {@link #addDataSchemeSpecificPart}, * {@link #addDataAuthority}, {@link #addDataPath}, and {@link #addCategory}, respectively). - * For actions, the field - * will not be tested if no values have been given (treating it as a wildcard); - * if no data characteristics are specified, however, then the filter will + * For actions, if no data characteristics are specified, then the filter will * only match intents that contain no data. * * <p>The data characteristic is diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index c74daa8eadfc..3933e81c732a 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -519,9 +519,9 @@ public class LauncherApps { * <li>The app is a system app.</li> * <li>The app doesn't request any <a href="/guide/topics/permissions/overview">permissions</a>. * </li> - * <li>The <code><application></code> tag in the app's manifest doesn't contain any child - * elements that represent - * <a href="/guide/components/fundamentals#DeclaringComponents">app components</a>.</li> + * <li>The app doesn't have a <em>launcher activity</em> that is enabled by default. A launcher + * activity has an intent containing the <code>ACTION_MAIN</code> action and the + * <code>CATEGORY_LAUNCHER</code> category.</li> * </ul> * * <p>Additionally, the system hides synthesized activities for some or all apps in the diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 06ced7c68467..f42228935579 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -2338,6 +2338,12 @@ public class CameraDeviceImpl extends CameraDevice final CaptureCallbackHolder holder = CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId); + if (holder == null) { + Log.e(TAG, String.format("Receive capture error on unknown request ID %d", + requestId)); + return; + } + final CaptureRequest request = holder.getRequest(subsequenceId); Runnable failureDispatch = null; diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 86651060a394..1c50d73c4953 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -276,6 +276,7 @@ public class TextLine { final int runCount = mDirections.getRunCount(); for (int runIndex = 0; runIndex < runCount; runIndex++) { final int runStart = mDirections.getRunStart(runIndex); + if (runStart > mLen) break; final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen); final boolean runIsRtl = mDirections.isRunRtl(runIndex); @@ -360,6 +361,7 @@ public class TextLine { float h = 0; for (int runIndex = 0; runIndex < mDirections.getRunCount(); runIndex++) { final int runStart = mDirections.getRunStart(runIndex); + if (runStart > mLen) break; final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen); final boolean runIsRtl = mDirections.isRunRtl(runIndex); @@ -417,6 +419,7 @@ public class TextLine { float h = 0; for (int runIndex = 0; runIndex < mDirections.getRunCount(); runIndex++) { final int runStart = mDirections.getRunStart(runIndex); + if (runStart > mLen) break; final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen); final boolean runIsRtl = mDirections.isRunRtl(runIndex); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 84665f78c702..c6536bb71cba 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -14431,8 +14431,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); - if (isVisible != oldVisible) { - updateSystemGestureExclusionRects(); + if (!getSystemGestureExclusionRects().isEmpty() && isVisible != oldVisible) { + postUpdateSystemGestureExclusionRects(); } } diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 436897848f55..cae1f3831b4a 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -24,6 +24,7 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; @@ -729,7 +730,13 @@ public class ChooserActivity extends ResolverActivity { /** * Returns true if app prediction service is defined and the component exists on device. */ - private boolean isAppPredictionServiceAvailable() { + @VisibleForTesting + public boolean isAppPredictionServiceAvailable() { + if (getPackageManager().getAppPredictionServicePackageName() == null) { + // Default AppPredictionService is not defined. + return false; + } + final String appPredictionServiceName = getString(R.string.config_defaultAppPredictionService); if (appPredictionServiceName == null) { @@ -1584,25 +1591,19 @@ public class ChooserActivity extends ResolverActivity { // ShareShortcutInfos directly. boolean resultMessageSent = false; for (int i = 0; i < driList.size(); i++) { - List<ChooserTarget> chooserTargets = new ArrayList<>(); + List<ShortcutManager.ShareShortcutInfo> matchingShortcuts = new ArrayList<>(); for (int j = 0; j < resultList.size(); j++) { if (driList.get(i).getResolvedComponentName().equals( resultList.get(j).getTargetComponent())) { - ShortcutManager.ShareShortcutInfo shareShortcutInfo = resultList.get(j); - // Incoming results are ordered but without a score. Create a score - // based on the index in order to be sorted appropriately when joined - // with legacy direct share api results. - float score = Math.max(1.0f - (0.05f * j), 0.0f); - ChooserTarget chooserTarget = convertToChooserTarget(shareShortcutInfo, score); - chooserTargets.add(chooserTarget); - if (mDirectShareAppTargetCache != null && appTargets != null) { - mDirectShareAppTargetCache.put(chooserTarget, appTargets.get(j)); - } + matchingShortcuts.add(resultList.get(j)); } } - if (chooserTargets.isEmpty()) { + if (matchingShortcuts.isEmpty()) { continue; } + List<ChooserTarget> chooserTargets = convertToChooserTarget( + matchingShortcuts, resultList, appTargets, shortcutType); + final Message msg = Message.obtain(); msg.what = ChooserHandler.SHORTCUT_MANAGER_SHARE_TARGET_RESULT; msg.obj = new ServiceResultInfo(driList.get(i), chooserTargets, null); @@ -1640,23 +1641,69 @@ public class ChooserActivity extends ResolverActivity { return false; } - private ChooserTarget convertToChooserTarget(ShortcutManager.ShareShortcutInfo shareShortcut, - float score) { - ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo(); - Bundle extras = new Bundle(); - extras.putString(Intent.EXTRA_SHORTCUT_ID, shortcutInfo.getId()); - return new ChooserTarget( - // The name of this target. - shortcutInfo.getShortLabel(), - // Don't load the icon until it is selected to be shown - null, - // The ranking score for this target (0.0-1.0); the system will omit items with low - // scores when there are too many Direct Share items. - score, - // The name of the component to be launched if this target is chosen. - shareShortcut.getTargetComponent().clone(), - // The extra values here will be merged into the Intent when this target is chosen. - extras); + /** + * Converts a list of ShareShortcutInfos to ChooserTargets. + * @param matchingShortcuts List of shortcuts, all from the same package, that match the current + * share intent filter. + * @param allShortcuts List of all the shortcuts from all the packages on the device that are + * returned for the current sharing action. + * @param allAppTargets List of AppTargets. Null if the results are not from prediction service. + * @param shortcutType One of the values TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER or + * TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE + * @return A list of ChooserTargets sorted by score in descending order. + */ + @VisibleForTesting + @NonNull + public List<ChooserTarget> convertToChooserTarget( + @NonNull List<ShortcutManager.ShareShortcutInfo> matchingShortcuts, + @NonNull List<ShortcutManager.ShareShortcutInfo> allShortcuts, + @Nullable List<AppTarget> allAppTargets, @ShareTargetType int shortcutType) { + // A set of distinct scores for the matched shortcuts. We use index of a rank in the sorted + // list instead of the actual rank value when converting a rank to a score. + List<Integer> scoreList = new ArrayList<>(); + if (shortcutType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER) { + for (int i = 0; i < matchingShortcuts.size(); i++) { + int shortcutRank = matchingShortcuts.get(i).getShortcutInfo().getRank(); + if (!scoreList.contains(shortcutRank)) { + scoreList.add(shortcutRank); + } + } + Collections.sort(scoreList); + } + + List<ChooserTarget> chooserTargetList = new ArrayList<>(matchingShortcuts.size()); + for (int i = 0; i < matchingShortcuts.size(); i++) { + ShortcutInfo shortcutInfo = matchingShortcuts.get(i).getShortcutInfo(); + int indexInAllShortcuts = allShortcuts.indexOf(matchingShortcuts.get(i)); + + float score; + if (shortcutType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE) { + // Incoming results are ordered. Create a score based on index in the original list. + score = Math.max(1.0f - (0.01f * indexInAllShortcuts), 0.0f); + } else { + // Create a score based on the rank of the shortcut. + int rankIndex = scoreList.indexOf(shortcutInfo.getRank()); + score = Math.max(1.0f - (0.01f * rankIndex), 0.0f); + } + + Bundle extras = new Bundle(); + extras.putString(Intent.EXTRA_SHORTCUT_ID, shortcutInfo.getId()); + ChooserTarget chooserTarget = new ChooserTarget(shortcutInfo.getShortLabel(), + null, // Icon will be loaded later if this target is selected to be shown. + score, matchingShortcuts.get(i).getTargetComponent().clone(), extras); + + chooserTargetList.add(chooserTarget); + if (mDirectShareAppTargetCache != null && allAppTargets != null) { + mDirectShareAppTargetCache.put(chooserTarget, + allAppTargets.get(indexInAllShortcuts)); + } + } + + // Sort ChooserTargets by score in descending order + Comparator<ChooserTarget> byScore = + (ChooserTarget a, ChooserTarget b) -> -Float.compare(a.getScore(), b.getScore()); + Collections.sort(chooserTargetList, byScore); + return chooserTargetList; } private String convertServiceName(String packageName, String serviceName) { @@ -1748,8 +1795,7 @@ public class ChooserActivity extends ResolverActivity { if (!mIsAppPredictorComponentAvailable) { return null; } - if (mAppPredictor == null - && getPackageManager().getAppPredictionServicePackageName() != null) { + if (mAppPredictor == null) { final IntentFilter filter = getTargetIntentFilter(); Bundle extras = new Bundle(); extras.putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, filter); diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 7c52a40d4494..07002d788908 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -796,7 +796,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind updateElevation(); mAllowUpdateElevation = true; - if (changed && mResizeMode == RESIZE_MODE_DOCKED_DIVIDER) { + if (changed + && (mResizeMode == RESIZE_MODE_DOCKED_DIVIDER + || mDrawLegacyNavigationBarBackground)) { getViewRootImpl().requestInvalidateRootRenderNode(); } } diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index 67036fef30ba..c44b7d81868d 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -36,6 +36,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -51,6 +52,8 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager.ShareShortcutInfo; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -807,6 +810,108 @@ public class ChooserActivityTest { is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST)); } + /** + * The case when AppPrediction service is not defined in PackageManager is already covered + * as a test parameter {@link ChooserActivityTest#packageManagers}. This test is checking the + * case when the prediction service is defined but the component is not available on the device. + */ + @Test + public void testIsAppPredictionServiceAvailable() { + Intent sendIntent = createSendTextIntent(); + List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); + when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); + + final ChooserWrapperActivity activity = mActivityRule + .launchActivity(Intent.createChooser(sendIntent, null)); + waitForIdle(); + + if (activity.getPackageManager().getAppPredictionServicePackageName() == null) { + assertThat(activity.isAppPredictionServiceAvailable(), is(false)); + } else { + assertThat(activity.isAppPredictionServiceAvailable(), is(true)); + + sOverrides.resources = Mockito.spy(activity.getResources()); + when(sOverrides.resources.getString(R.string.config_defaultAppPredictionService)) + .thenReturn("ComponentNameThatDoesNotExist"); + + assertThat(activity.isAppPredictionServiceAvailable(), is(false)); + } + } + + @Test + public void testConvertToChooserTarget_predictionService() { + Intent sendIntent = createSendTextIntent(); + List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); + when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); + + final ChooserWrapperActivity activity = mActivityRule + .launchActivity(Intent.createChooser(sendIntent, null)); + waitForIdle(); + + List<ShareShortcutInfo> shortcuts = createShortcuts(activity); + + int[] expectedOrderAllShortcuts = {0, 1, 2, 3}; + float[] expectedScoreAllShortcuts = {1.0f, 0.99f, 0.98f, 0.97f}; + + List<ChooserTarget> chooserTargets = activity.convertToChooserTarget(shortcuts, shortcuts, + null, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE); + assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, + expectedOrderAllShortcuts, expectedScoreAllShortcuts); + + List<ShareShortcutInfo> subset = new ArrayList<>(); + subset.add(shortcuts.get(1)); + subset.add(shortcuts.get(2)); + subset.add(shortcuts.get(3)); + + int[] expectedOrderSubset = {1, 2, 3}; + float[] expectedScoreSubset = {0.99f, 0.98f, 0.97f}; + + chooserTargets = activity.convertToChooserTarget(subset, shortcuts, null, + TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE); + assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, + expectedOrderSubset, expectedScoreSubset); + } + + @Test + public void testConvertToChooserTarget_shortcutManager() { + Intent sendIntent = createSendTextIntent(); + List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); + when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); + + final ChooserWrapperActivity activity = mActivityRule + .launchActivity(Intent.createChooser(sendIntent, null)); + waitForIdle(); + + List<ShareShortcutInfo> shortcuts = createShortcuts(activity); + + int[] expectedOrderAllShortcuts = {2, 0, 3, 1}; + float[] expectedScoreAllShortcuts = {1.0f, 0.99f, 0.99f, 0.98f}; + + List<ChooserTarget> chooserTargets = activity.convertToChooserTarget(shortcuts, shortcuts, + null, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER); + assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, + expectedOrderAllShortcuts, expectedScoreAllShortcuts); + + List<ShareShortcutInfo> subset = new ArrayList<>(); + subset.add(shortcuts.get(1)); + subset.add(shortcuts.get(2)); + subset.add(shortcuts.get(3)); + + int[] expectedOrderSubset = {2, 3, 1}; + float[] expectedScoreSubset = {1.0f, 0.99f, 0.98f}; + + chooserTargets = activity.convertToChooserTarget(subset, shortcuts, null, + TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER); + assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, + expectedOrderSubset, expectedScoreSubset); + } + // This test is too long and too slow and should not be taken as an example for future tests. @Test public void testDirectTargetSelectionLogging() throws InterruptedException { @@ -1103,4 +1208,43 @@ public class ChooserActivityTest { return bitmap; } + + private List<ShareShortcutInfo> createShortcuts(Context context) { + Intent testIntent = new Intent("TestIntent"); + + List<ShareShortcutInfo> shortcuts = new ArrayList<>(); + shortcuts.add(new ShareShortcutInfo( + new ShortcutInfo.Builder(context, "shortcut1") + .setIntent(testIntent).setShortLabel("label1").setRank(3).build(), // 0 2 + new ComponentName("package1", "class1"))); + shortcuts.add(new ShareShortcutInfo( + new ShortcutInfo.Builder(context, "shortcut2") + .setIntent(testIntent).setShortLabel("label2").setRank(7).build(), // 1 3 + new ComponentName("package2", "class2"))); + shortcuts.add(new ShareShortcutInfo( + new ShortcutInfo.Builder(context, "shortcut3") + .setIntent(testIntent).setShortLabel("label3").setRank(1).build(), // 2 0 + new ComponentName("package3", "class3"))); + shortcuts.add(new ShareShortcutInfo( + new ShortcutInfo.Builder(context, "shortcut4") + .setIntent(testIntent).setShortLabel("label4").setRank(3).build(), // 3 2 + new ComponentName("package4", "class4"))); + + return shortcuts; + } + + private void assertCorrectShortcutToChooserTargetConversion(List<ShareShortcutInfo> shortcuts, + List<ChooserTarget> chooserTargets, int[] expectedOrder, float[] expectedScores) { + assertEquals(expectedOrder.length, chooserTargets.size()); + for (int i = 0; i < chooserTargets.size(); i++) { + ChooserTarget ct = chooserTargets.get(i); + ShortcutInfo si = shortcuts.get(expectedOrder[i]).getShortcutInfo(); + ComponentName cn = shortcuts.get(expectedOrder[i]).getTargetComponent(); + + assertEquals(si.getId(), ct.getIntentExtras().getString(Intent.EXTRA_SHORTCUT_ID)); + assertEquals(si.getShortLabel(), ct.getTitle()); + assertThat(Math.abs(expectedScores[i] - ct.getScore()) < 0.000001, is(true)); + assertEquals(cn.flattenToString(), ct.getComponentName().flattenToString()); + } + } } diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java index 44e56eaf0593..1d567c73f376 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java @@ -24,6 +24,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; @@ -85,6 +86,14 @@ public class ChooserWrapperActivity extends ChooserActivity { } @Override + public Resources getResources() { + if (sOverrides.resources != null) { + return sOverrides.resources; + } + return super.getResources(); + } + + @Override protected Bitmap loadThumbnail(Uri uri, Size size) { if (sOverrides.previewThumbnail != null) { return sOverrides.previewThumbnail; @@ -145,6 +154,7 @@ public class ChooserWrapperActivity extends ChooserActivity { public Bitmap previewThumbnail; public MetricsLogger metricsLogger; public int alternateProfileSetting; + public Resources resources; public void reset() { onSafelyStartCallback = null; @@ -157,6 +167,7 @@ public class ChooserWrapperActivity extends ChooserActivity { resolverListController = mock(ResolverListController.class); metricsLogger = mock(MetricsLogger.class); alternateProfileSetting = 0; + resources = null; } } } diff --git a/packages/CarSystemUI/res/layout/super_status_bar.xml b/packages/CarSystemUI/res/layout/super_status_bar.xml index 728a239a4ca9..e1bcc2e5f86c 100644 --- a/packages/CarSystemUI/res/layout/super_status_bar.xml +++ b/packages/CarSystemUI/res/layout/super_status_bar.xml @@ -42,6 +42,14 @@ </com.android.systemui.statusbar.BackDropView> <com.android.systemui.statusbar.ScrimView + android:id="@+id/scrim_for_bubble" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:importantForAccessibility="no" + sysui:ignoreRightInset="true" + /> + + <com.android.systemui.statusbar.ScrimView android:id="@+id/scrim_behind" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt index 276afa7a3a94..a70dc7c0ec5d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt @@ -33,6 +33,7 @@ import com.android.systemui.Gefingerpoken import com.android.systemui.Interpolators import com.android.systemui.R import com.android.systemui.plugins.FalsingManager +import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView @@ -56,7 +57,8 @@ constructor( private val wakeUpCoordinator: NotificationWakeUpCoordinator, private val bypassController: KeyguardBypassController, private val headsUpManager: HeadsUpManagerPhone, - private val roundnessManager: NotificationRoundnessManager + private val roundnessManager: NotificationRoundnessManager, + private val statusBarStateController: StatusBarStateController ) : Gefingerpoken { companion object { private val RUBBERBAND_FACTOR_STATIC = 0.25f @@ -188,7 +190,8 @@ constructor( MotionEvent.ACTION_MOVE -> updateExpansionHeight(moveDistance) MotionEvent.ACTION_UP -> { velocityTracker!!.computeCurrentVelocity(1000 /* units */) - val canExpand = moveDistance > 0 && velocityTracker!!.getYVelocity() > -1000 + val canExpand = moveDistance > 0 && velocityTracker!!.getYVelocity() > -1000 && + statusBarStateController.state != StatusBarState.SHADE if (!mFalsingManager.isUnlockingDisabled && !isFalseTouch && canExpand) { finishExpansion() } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index f0eeb046bc44..abf29c47e803 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -20,6 +20,7 @@ import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.text.format.DateFormat; import android.util.FloatProperty; +import android.util.Log; import android.view.View; import android.view.animation.Interpolator; @@ -136,6 +137,11 @@ public class StatusBarStateControllerImpl implements SysuiStatusBarStateControll // Record the to-be mState and mLastState recordHistoricalState(state, mState); + // b/139259891 + if (mState == StatusBarState.SHADE && state == StatusBarState.SHADE_LOCKED) { + Log.e(TAG, "Invalid state transition: SHADE -> SHADE_LOCKED", new Throwable()); + } + synchronized (mListeners) { for (RankedListener rl : new ArrayList<>(mListeners)) { rl.mListener.onStatePreChange(mState, state); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 83c556630538..6bc0cf6e0a3d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -96,6 +96,7 @@ import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.policy.ZenModeController; @@ -169,12 +170,22 @@ public class NotificationPanelView extends PanelView implements @VisibleForTesting final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback = new KeyguardUpdateMonitorCallback() { + + @Override + public void onBiometricAuthenticated(int userId, + BiometricSourceType biometricSourceType) { + if (mFirstBypassAttempt && mUpdateMonitor.isUnlockingWithBiometricAllowed()) { + mDelayShowingKeyguardStatusBar = true; + } + } + @Override public void onBiometricRunningStateChanged(boolean running, BiometricSourceType biometricSourceType) { boolean keyguardOrShadeLocked = mBarState == StatusBarState.KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED; - if (!running && mFirstBypassAttempt && keyguardOrShadeLocked && !mDozing) { + if (!running && mFirstBypassAttempt && keyguardOrShadeLocked && !mDozing + && !mDelayShowingKeyguardStatusBar) { mFirstBypassAttempt = false; animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD); } @@ -183,6 +194,17 @@ public class NotificationPanelView extends PanelView implements @Override public void onFinishedGoingToSleep(int why) { mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled(); + mDelayShowingKeyguardStatusBar = false; + } + }; + private final KeyguardMonitor.Callback mKeyguardMonitorCallback = + new KeyguardMonitor.Callback() { + @Override + public void onKeyguardFadingAwayChanged() { + if (!mKeyguardMonitor.isKeyguardFadingAway()) { + mFirstBypassAttempt = false; + mDelayShowingKeyguardStatusBar = false; + } } }; @@ -404,7 +426,17 @@ public class NotificationPanelView extends PanelView implements private boolean mShowingKeyguardHeadsUp; private boolean mAllowExpandForSmallExpansion; private Runnable mExpandAfterLayoutRunnable; + + /** + * If face auth with bypass is running for the first time after you turn on the screen. + * (From aod or screen off) + */ private boolean mFirstBypassAttempt; + /** + * If auth happens successfully during {@code mFirstBypassAttempt}, and we should wait until + * the keyguard is dismissed to show the status bar. + */ + private boolean mDelayShowingKeyguardStatusBar; @Inject public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, @@ -436,6 +468,7 @@ public class NotificationPanelView extends PanelView implements mKeyguardBypassController = bypassController; mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled(); + mKeyguardMonitor.addCallback(mKeyguardMonitorCallback); dynamicPrivacyController.addListener(this); mBottomAreaShadeAlphaAnimator = ValueAnimator.ofFloat(1f, 0); @@ -2263,7 +2296,8 @@ public class NotificationPanelView extends PanelView implements * mKeyguardStatusBarAnimateAlpha; newAlpha *= 1.0f - mKeyguardHeadsUpShowingAmount; mKeyguardStatusBar.setAlpha(newAlpha); - boolean hideForBypass = mFirstBypassAttempt && mUpdateMonitor.shouldListenForFace(); + boolean hideForBypass = mFirstBypassAttempt && mUpdateMonitor.shouldListenForFace() + || mDelayShowingKeyguardStatusBar; mKeyguardStatusBar.setVisibility(newAlpha != 0f && !mDozing && !hideForBypass ? VISIBLE : INVISIBLE); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 0334d49ce9df..f94779d6d5ca 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -129,7 +129,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { mKeyguardBypassController); PulseExpansionHandler expansionHandler = new PulseExpansionHandler(mContext, coordinator, mKeyguardBypassController, mHeadsUpManager, - mock(NotificationRoundnessManager.class)); + mock(NotificationRoundnessManager.class), mStatusBarStateController); mNotificationPanelView = new TestableNotificationPanelView(coordinator, expansionHandler, mKeyguardBypassController); mNotificationPanelView.setHeadsUpManager(mHeadsUpManager); diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto index 8ad24894a1b9..353a18756ca2 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -1792,6 +1792,25 @@ message ExperimentValues { // Indicates if we are logging LinkSpeedCount in metrics optional bool link_speed_counts_logging_enabled = 4; + + // Duration for evaluating Wifi condition to trigger a data stall + // measured in milliseconds + optional int32 data_stall_duration_ms = 5; + + // Threshold of Tx throughput below which to trigger a data stall + // measured in Mbps + optional int32 data_stall_tx_tput_thr_mbps = 6; + + // Threshold of Rx throughput below which to trigger a data stall + // measured in Mbps + optional int32 data_stall_rx_tput_thr_mbps = 7; + + // Threshold of Tx packet error rate above which to trigger a data stall + // in percentage + optional int32 data_stall_tx_per_thr = 8; + + // Threshold of CCA level above which to trigger a data stall in percentage + optional int32 data_stall_cca_level_thr = 9; } message WifiIsUnusableEvent { diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 52a4218238e7..2ab46e65e77f 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -2737,7 +2737,9 @@ public class DeviceIdleController extends SystemService resetIdleManagementLocked(); // Wait a small amount of time in case something (eg: background service from // recently closed app) needs to finish running. - scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false); + // Use a non-wakeup alarm for going into quick doze in case an AlarmClock alarm + // is scheduled soon. The non-wakeup alarm will be delayed by at most 2 minutes. + scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false, false); EventLogTags.writeDeviceIdle(mState, "no activity"); } else if (mState == STATE_ACTIVE) { mState = STATE_INACTIVE; @@ -3362,6 +3364,10 @@ public class DeviceIdleController extends SystemService } void scheduleAlarmLocked(long delay, boolean idleUntil) { + scheduleAlarmLocked(delay, idleUntil, true); + } + + private void scheduleAlarmLocked(long delay, boolean idleUntil, boolean useWakeupAlarm) { if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")"); if (mUseMotionSensor && mMotionSensor == null @@ -3377,12 +3383,14 @@ public class DeviceIdleController extends SystemService // can continue until the user interacts with the device. return; } + final int alarmType = useWakeupAlarm + ? AlarmManager.ELAPSED_REALTIME_WAKEUP : AlarmManager.ELAPSED_REALTIME; mNextAlarmTime = SystemClock.elapsedRealtime() + delay; if (idleUntil) { - mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mAlarmManager.setIdleUntil(alarmType, mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler); } else { - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mAlarmManager.set(alarmType, mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler); } } diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java index 1891ba9b1742..6bc1a570b7c0 100644 --- a/services/core/java/com/android/server/MountServiceIdler.java +++ b/services/core/java/com/android/server/MountServiceIdler.java @@ -27,6 +27,7 @@ import android.content.ComponentName; import android.content.Context; import android.os.RemoteException; import android.util.Slog; +import java.util.concurrent.TimeUnit; public class MountServiceIdler extends JobService { private static final String TAG = "MountServiceIdler"; @@ -48,7 +49,7 @@ public class MountServiceIdler extends JobService { mStarted = false; } } - // ... and try again tomorrow + // ... and try again right away or tomorrow scheduleIdlePass(MountServiceIdler.this); } }; @@ -98,24 +99,32 @@ public class MountServiceIdler extends JobService { public static void scheduleIdlePass(Context context) { JobScheduler tm = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); - Calendar calendar = tomorrowMidnight(); - final long timeToMidnight = calendar.getTimeInMillis() - System.currentTimeMillis(); + final long today3AM = offsetFromTodayMidnight(0, 3).getTimeInMillis(); + final long today4AM = offsetFromTodayMidnight(0, 4).getTimeInMillis(); + final long tomorrow3AM = offsetFromTodayMidnight(1, 3).getTimeInMillis(); + + long nextScheduleTime; + if (System.currentTimeMillis() > today3AM && System.currentTimeMillis() < today4AM) { + nextScheduleTime = TimeUnit.SECONDS.toMillis(10); + } else { + nextScheduleTime = tomorrow3AM - System.currentTimeMillis(); // 3AM tomorrow + } JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService); builder.setRequiresDeviceIdle(true); - builder.setRequiresCharging(true); - builder.setMinimumLatency(timeToMidnight); + builder.setRequiresBatteryNotLow(true); + builder.setMinimumLatency(nextScheduleTime); tm.schedule(builder.build()); } - private static Calendar tomorrowMidnight() { + private static Calendar offsetFromTodayMidnight(int nDays, int nHours) { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); - calendar.set(Calendar.HOUR_OF_DAY, 3); + calendar.set(Calendar.HOUR_OF_DAY, nHours); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); - calendar.add(Calendar.DAY_OF_MONTH, 1); + calendar.add(Calendar.DAY_OF_MONTH, nDays); return calendar; } } diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 73d160d8c444..24581a247216 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -455,7 +455,20 @@ public class Tethering extends BaseNetworkObserver { @Override public void onServiceConnected(int profile, BluetoothProfile proxy) { - ((BluetoothPan) proxy).setBluetoothTethering(enable); + // Clear identify is fine because caller already pass tethering permission at + // ConnectivityService#startTethering()(or stopTethering) before the control comes + // here. Bluetooth will check tethering permission again that there is + // Context#getOpPackageName() under BluetoothPan#setBluetoothTethering() to get + // caller's package name for permission check. + // Calling BluetoothPan#setBluetoothTethering() here means the package name always + // be system server. If calling identity is not cleared, that package's uid might + // not match calling uid and end up in permission denied. + final long identityToken = Binder.clearCallingIdentity(); + try { + ((BluetoothPan) proxy).setBluetoothTethering(enable); + } finally { + Binder.restoreCallingIdentity(identityToken); + } // TODO: Enabling bluetooth tethering can fail asynchronously here. // We should figure out a way to bubble up that failure instead of sending success. final int result = (((BluetoothPan) proxy).isTetheringOn() == enable) diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 5a1eed8897b6..5b697ee89602 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2700,7 +2700,8 @@ class ActivityStarter { || mPreferredDisplayId != DEFAULT_DISPLAY) { final boolean onTop = aOptions == null || !aOptions.getAvoidMoveToFront(); final ActivityStack stack = - mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams); + mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams, + mRequest.realCallingPid, mRequest.realCallingUid); return stack; } // Otherwise handle adjacent launch. @@ -2818,11 +2819,24 @@ class ActivityStarter { return this; } + /** + * Sets the pid of the caller who originally started the activity. + * + * Normally, the pid/uid would be the calling pid from the binder call. + * However, in case of a {@link PendingIntent}, the pid/uid pair of the caller is considered + * the original entity that created the pending intent, in contrast to setRealCallingPid/Uid, + * which represents the entity who invoked pending intent via {@link PendingIntent#send}. + */ ActivityStarter setCallingPid(int pid) { mRequest.callingPid = pid; return this; } + /** + * Sets the uid of the caller who originally started the activity. + * + * @see #setCallingPid + */ ActivityStarter setCallingUid(int uid) { mRequest.callingUid = uid; return this; @@ -2833,11 +2847,25 @@ class ActivityStarter { return this; } + /** + * Sets the pid of the caller who requested to launch the activity. + * + * The pid/uid represents the caller who launches the activity in this request. + * It will almost same as setCallingPid/Uid except when processing {@link PendingIntent}: + * the pid/uid will be the caller who called {@link PendingIntent#send()}. + * + * @see #setCallingPid + */ ActivityStarter setRealCallingPid(int pid) { mRequest.realCallingPid = pid; return this; } + /** + * Sets the uid of the caller who requested to launch the activity. + * + * @see #setRealCallingPid + */ ActivityStarter setRealCallingUid(int uid) { mRequest.realCallingUid = uid; return this; diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index a339ef03c22c..ffbf68813d35 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -1667,7 +1667,8 @@ class RootActivityContainer extends ConfigurationContainer <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop) { - return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */); + return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */, + -1 /* no realCallingPid */, -1 /* no realCallingUid */); } /** @@ -1676,13 +1677,16 @@ class RootActivityContainer extends ConfigurationContainer * @param r The activity we are trying to launch. Can be null. * @param options The activity options used to the launch. Can be null. * @param candidateTask The possible task the activity might be launched in. Can be null. - * @params launchParams The resolved launch params to use. + * @param launchParams The resolved launch params to use. + * @param realCallingPid The pid from {@link ActivityStarter#setRealCallingPid} + * @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid} * * @return The stack to use for the launch or INVALID_STACK_ID. */ <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop, - @Nullable LaunchParamsController.LaunchParams launchParams) { + @Nullable LaunchParamsController.LaunchParams launchParams, int realCallingPid, + int realCallingUid) { int taskId = INVALID_TASK_ID; int displayId = INVALID_DISPLAY; //Rect bounds = null; @@ -1713,7 +1717,14 @@ class RootActivityContainer extends ConfigurationContainer if (launchParams != null && launchParams.mPreferredDisplayId != INVALID_DISPLAY) { displayId = launchParams.mPreferredDisplayId; } - if (displayId != INVALID_DISPLAY && canLaunchOnDisplay(r, displayId)) { + final boolean canLaunchOnDisplayFromStartRequest = + realCallingPid != 0 && realCallingUid > 0 && r != null + && mStackSupervisor.canPlaceEntityOnDisplay(displayId, realCallingPid, + realCallingUid, r.info); + // Checking if the activity's launch caller, or the realCallerId of the activity from + // start request (i.e. PendingIntent caller) is allowed to launch on the display. + if (displayId != INVALID_DISPLAY && (canLaunchOnDisplay(r, displayId) + || canLaunchOnDisplayFromStartRequest)) { if (r != null) { stack = (T) getValidLaunchStackOnDisplay(displayId, r, candidateTask, options, launchParams); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index c108752c951a..f67b4fe78f58 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1167,7 +1167,8 @@ public class WindowManagerService extends IWindowManager.Stub new HandlerExecutor(mH), properties -> { synchronized (mGlobalLock) { final int exclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP, - properties.getInt(KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0)); + DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0)); final boolean excludedByPreQSticky = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 3d944671ef25..07d9f803d9fa 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -341,7 +341,7 @@ public class ActivityStarterTests extends ActivityTestsBase { doReturn(stack).when(mRootActivityContainer) .getLaunchStack(any(), any(), any(), anyBoolean()); doReturn(stack).when(mRootActivityContainer) - .getLaunchStack(any(), any(), any(), anyBoolean(), any()); + .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt()); } // Set up mock package manager internal and make sure no unmocked methods are called diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 3c0da265f97a..84bdecb86826 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -208,6 +208,8 @@ class ActivityTestsBase { private ActivityStack mStack; private int mActivityFlags; private int mLaunchMode; + private int mLaunchedFromPid; + private int mLaunchedFromUid; ActivityBuilder(ActivityTaskManagerService service) { mService = service; @@ -258,6 +260,16 @@ class ActivityTestsBase { return this; } + ActivityBuilder setLaunchedFromPid(int pid) { + mLaunchedFromPid = pid; + return this; + } + + ActivityBuilder setLaunchedFromUid(int uid) { + mLaunchedFromUid = uid; + return this; + } + ActivityRecord build() { if (mComponent == null) { final int id = sCurrentActivityId++; @@ -285,10 +297,11 @@ class ActivityTestsBase { aInfo.launchMode = mLaunchMode; final ActivityRecord activity = new ActivityRecord(mService, null /* caller */, - 0 /* launchedFromPid */, 0, null, intent, null, - aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */, - 0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */, - mService.mStackSupervisor, null /* options */, null /* sourceRecord */); + mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */, + null, intent, null, aInfo /*aInfo*/, new Configuration(), null /* resultTo */, + null /* resultWho */, 0 /* reqCode */, false /*componentSpecified*/, + false /* rootVoiceInteraction */, mService.mStackSupervisor, + null /* options */, null /* sourceRecord */); spyOn(activity); activity.mAppWindowToken = mock(AppWindowToken.class); doCallRealMethod().when(activity.mAppWindowToken).getOrientationIgnoreVisibility(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index 8d2c3dd80538..baf1b0821982 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.TYPE_VIRTUAL; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; @@ -61,6 +62,7 @@ import android.content.res.Resources; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.util.Pair; +import android.view.DisplayInfo; import androidx.test.filters.MediumTest; @@ -817,6 +819,41 @@ public class RootActivityContainerTests extends ActivityTestsBase { } /** + * Test that {@link RootActivityContainer#getLaunchStack} with the real caller id will get the + * expected stack when requesting the activity launch on the secondary display. + */ + @Test + public void testGetLaunchStackWithRealCallerId() { + // Create a non-system owned virtual display. + final DisplayInfo info = new DisplayInfo(); + mSupervisor.mService.mContext.getDisplay().getDisplayInfo(info); + info.type = TYPE_VIRTUAL; + info.ownerUid = 100; + final TestActivityDisplay secondaryDisplay = createNewActivityDisplay(info); + mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP); + + // Create an activity with specify the original launch pid / uid. + final ActivityRecord r = new ActivityBuilder(mService).setLaunchedFromPid(200) + .setLaunchedFromUid(200).build(); + + // Simulate ActivityStarter to find a launch stack for requesting the activity to launch + // on the secondary display with realCallerId. + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(secondaryDisplay.mDisplayId); + options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); + doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId, + 300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info); + final ActivityStack result = mRootActivityContainer.getLaunchStack(r, options, + null /* task */, true /* onTop */, null, 300 /* test realCallerPid */, + 300 /* test realCallerUid */); + + // Assert that the stack is returned as expected. + assertNotNull(result); + assertEquals("The display ID of the stack should same as secondary display ", + secondaryDisplay.mDisplayId, result.mDisplayId); + } + + /** * Mock {@link RootActivityContainerTests#resolveHomeActivity} for returning consistent activity * info for test cases (the original implementation will resolve from the real package manager). */ diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index c6c198668d95..163be515f131 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -578,7 +578,8 @@ public class SubscriptionInfo implements Parcelable { PackageManager packageManager = context.getPackageManager(); PackageInfo packageInfo; try { - packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + packageInfo = packageManager.getPackageInfo(packageName, + PackageManager.GET_SIGNING_CERTIFICATES); } catch (PackageManager.NameNotFoundException e) { Log.d("SubscriptionInfo", "canManageSubscription: Unknown package: " + packageName, e); return false; diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 776b168e6766..126644dd0e93 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2612,7 +2612,8 @@ public class SubscriptionManager { PackageManager packageManager = mContext.getPackageManager(); PackageInfo packageInfo; try { - packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + packageInfo = packageManager.getPackageInfo(packageName, + PackageManager.GET_SIGNING_CERTIFICATES); } catch (PackageManager.NameNotFoundException e) { logd("Unknown package: " + packageName); return false; diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java index 37a4491141a0..cb3c3847f08d 100644 --- a/telephony/java/android/telephony/UiccAccessRule.java +++ b/telephony/java/android/telephony/UiccAccessRule.java @@ -19,6 +19,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.pm.PackageInfo; import android.content.pm.Signature; +import android.content.pm.SigningInfo; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -168,17 +169,28 @@ public final class UiccAccessRule implements Parcelable { * * @param packageInfo package info fetched from * {@link android.content.pm.PackageManager#getPackageInfo}. - * {@link android.content.pm.PackageManager#GET_SIGNATURES} must have been passed in. + * {@link android.content.pm.PackageManager#GET_SIGNING_CERTIFICATES} must have been + * passed in. * @return either {@link TelephonyManager#CARRIER_PRIVILEGE_STATUS_HAS_ACCESS} or * {@link TelephonyManager#CARRIER_PRIVILEGE_STATUS_NO_ACCESS}. */ public int getCarrierPrivilegeStatus(PackageInfo packageInfo) { - if (packageInfo.signatures == null || packageInfo.signatures.length == 0) { + Signature[] signatures = packageInfo.signatures; + SigningInfo sInfo = packageInfo.signingInfo; + + if (sInfo != null) { + signatures = sInfo.getSigningCertificateHistory(); + if (sInfo.hasMultipleSigners()) { + signatures = sInfo.getApkContentsSigners(); + } + } + + if (signatures == null || signatures.length == 0) { throw new IllegalArgumentException( - "Must use GET_SIGNATURES when looking up package info"); + "Must use GET_SIGNING_CERTIFICATES when looking up package info"); } - for (Signature sig : packageInfo.signatures) { + for (Signature sig : signatures) { int accessStatus = getCarrierPrivilegeStatus(sig, packageInfo.packageName); if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { return accessStatus; |