diff options
45 files changed, 504 insertions, 351 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java index 231263579088..42725c51fd87 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java @@ -59,9 +59,9 @@ import java.util.List; * * <p class="caution"><strong>Note:</strong> Beginning with API 30 * ({@link android.os.Build.VERSION_CODES#R}), JobScheduler will throttle runaway applications. - * Calling {@link #schedule(JobInfo)} and other such methods with very high frequency is indicative - * of an app bug and so, to make sure the system doesn't get overwhelmed, JobScheduler will begin - * to throttle apps that show buggy behavior, regardless of target SDK version. + * Calling {@link #schedule(JobInfo)} and other such methods with very high frequency can have a + * high cost and so, to make sure the system doesn't get overwhelmed, JobScheduler will begin + * to throttle apps, regardless of target SDK version. */ @SystemService(Context.JOB_SCHEDULER_SERVICE) public abstract class JobScheduler { @@ -74,9 +74,16 @@ public abstract class JobScheduler { public @interface Result {} /** - * Returned from {@link #schedule(JobInfo)} when an invalid parameter was supplied. This can occur - * if the run-time for your job is too short, or perhaps the system can't resolve the - * requisite {@link JobService} in your package. + * Returned from {@link #schedule(JobInfo)} if a job wasn't scheduled successfully. Scheduling + * can fail for a variety of reasons, including, but not limited to: + * <ul> + * <li>an invalid parameter was supplied (eg. the run-time for your job is too short, or the + * system can't resolve the requisite {@link JobService} in your package)</li> + * <li>the app has too many jobs scheduled</li> + * <li>the app has tried to schedule too many jobs in a short amount of time</li> + * </ul> + * Attempting to schedule the job again immediately after receiving this result will not + * guarantee a successful schedule. */ public static final int RESULT_FAILURE = 0; /** @@ -89,6 +96,11 @@ public abstract class JobScheduler { * ID with the new information in the {@link JobInfo}. If a job with the given ID is currently * running, it will be stopped. * + * <p class="caution"><strong>Note:</strong> Scheduling a job can have a high cost, even if it's + * rescheduling the same job and the job didn't execute, especially on platform versions before + * version {@link android.os.Build.VERSION_CODES#Q}. As such, the system may throttle calls to + * this API if calls are made too frequently in a short amount of time. + * * @param job The job you wish scheduled. See * {@link android.app.job.JobInfo.Builder JobInfo.Builder} for more detail on the sorts of jobs * you can schedule. diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index e88865161dfa..871e40fc9dfe 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -255,6 +255,18 @@ public class JobSchedulerService extends com.android.server.SystemService private final CountQuotaTracker mQuotaTracker; private static final String QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG = ".schedulePersisted()"; + private static final String QUOTA_TRACKER_SCHEDULE_LOGGED = + ".schedulePersisted out-of-quota logged"; + private static final Category QUOTA_TRACKER_CATEGORY_SCHEDULE_PERSISTED = new Category( + ".schedulePersisted()"); + private static final Category QUOTA_TRACKER_CATEGORY_SCHEDULE_LOGGED = new Category( + ".schedulePersisted out-of-quota logged"); + private static final Categorizer QUOTA_CATEGORIZER = (userId, packageName, tag) -> { + if (QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG.equals(tag)) { + return QUOTA_TRACKER_CATEGORY_SCHEDULE_PERSISTED; + } + return QUOTA_TRACKER_CATEGORY_SCHEDULE_LOGGED; + }; /** * Queue of pending jobs. The JobServiceContext class will receive jobs from this list @@ -271,6 +283,7 @@ public class JobSchedulerService extends com.android.server.SystemService ActivityManagerInternal mActivityManagerInternal; IBatteryStats mBatteryStats; DeviceIdleInternal mLocalDeviceIdleController; + @VisibleForTesting AppStateTracker mAppStateTracker; final UsageStatsManagerInternal mUsageStats; private final AppStandbyInternal mAppStandbyInternal; @@ -343,10 +356,7 @@ public class JobSchedulerService extends com.android.server.SystemService final StateController sc = mControllers.get(controller); sc.onConstantsUpdatedLocked(); } - mQuotaTracker.setEnabled(mConstants.ENABLE_API_QUOTAS); - mQuotaTracker.setCountLimit(Category.SINGLE_CATEGORY, - mConstants.API_QUOTA_SCHEDULE_COUNT, - mConstants.API_QUOTA_SCHEDULE_WINDOW_MS); + updateQuotaTracker(); } catch (IllegalArgumentException e) { // Failed to parse the settings string, log this and move on // with defaults. @@ -356,6 +366,14 @@ public class JobSchedulerService extends com.android.server.SystemService } } + @VisibleForTesting + void updateQuotaTracker() { + mQuotaTracker.setEnabled(mConstants.ENABLE_API_QUOTAS); + mQuotaTracker.setCountLimit(QUOTA_TRACKER_CATEGORY_SCHEDULE_PERSISTED, + mConstants.API_QUOTA_SCHEDULE_COUNT, + mConstants.API_QUOTA_SCHEDULE_WINDOW_MS); + } + static class MaxJobCounts { private final KeyValueListParser.IntValue mTotal; private final KeyValueListParser.IntValue mMaxBg; @@ -508,6 +526,8 @@ public class JobSchedulerService extends com.android.server.SystemService private static final String KEY_API_QUOTA_SCHEDULE_WINDOW_MS = "aq_schedule_window_ms"; private static final String KEY_API_QUOTA_SCHEDULE_THROW_EXCEPTION = "aq_schedule_throw_exception"; + private static final String KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = + "aq_schedule_return_failure"; private static final int DEFAULT_MIN_READY_NON_ACTIVE_JOBS_COUNT = 5; private static final long DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = 31 * MINUTE_IN_MILLIS; @@ -521,6 +541,7 @@ public class JobSchedulerService extends com.android.server.SystemService private static final int DEFAULT_API_QUOTA_SCHEDULE_COUNT = 250; private static final long DEFAULT_API_QUOTA_SCHEDULE_WINDOW_MS = MINUTE_IN_MILLIS; private static final boolean DEFAULT_API_QUOTA_SCHEDULE_THROW_EXCEPTION = true; + private static final boolean DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = false; /** * Minimum # of non-ACTIVE jobs for which the JMS will be happy running some work early. @@ -624,6 +645,11 @@ public class JobSchedulerService extends com.android.server.SystemService */ public boolean API_QUOTA_SCHEDULE_THROW_EXCEPTION = DEFAULT_API_QUOTA_SCHEDULE_THROW_EXCEPTION; + /** + * Whether or not to return a failure result when an app hits its schedule quota limit. + */ + public boolean API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = + DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -679,6 +705,9 @@ public class JobSchedulerService extends com.android.server.SystemService API_QUOTA_SCHEDULE_THROW_EXCEPTION = mParser.getBoolean( KEY_API_QUOTA_SCHEDULE_THROW_EXCEPTION, DEFAULT_API_QUOTA_SCHEDULE_THROW_EXCEPTION); + API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = mParser.getBoolean( + KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT, + DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT); } void dump(IndentingPrintWriter pw) { @@ -713,6 +742,8 @@ public class JobSchedulerService extends com.android.server.SystemService pw.printPair(KEY_API_QUOTA_SCHEDULE_WINDOW_MS, API_QUOTA_SCHEDULE_WINDOW_MS).println(); pw.printPair(KEY_API_QUOTA_SCHEDULE_THROW_EXCEPTION, API_QUOTA_SCHEDULE_THROW_EXCEPTION).println(); + pw.printPair(KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT, + API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT).println(); pw.decreaseIndent(); } @@ -741,6 +772,8 @@ public class JobSchedulerService extends com.android.server.SystemService proto.write(ConstantsProto.API_QUOTA_SCHEDULE_WINDOW_MS, API_QUOTA_SCHEDULE_WINDOW_MS); proto.write(ConstantsProto.API_QUOTA_SCHEDULE_THROW_EXCEPTION, API_QUOTA_SCHEDULE_THROW_EXCEPTION); + proto.write(ConstantsProto.API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT, + API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT); } } @@ -974,12 +1007,17 @@ public class JobSchedulerService extends com.android.server.SystemService public int scheduleAsPackage(JobInfo job, JobWorkItem work, int uId, String packageName, int userId, String tag) { - if (job.isPersisted()) { - // Only limit schedule calls for persisted jobs. + final String servicePkg = job.getService().getPackageName(); + if (job.isPersisted() && (packageName == null || packageName.equals(servicePkg))) { + // Only limit schedule calls for persisted jobs scheduled by the app itself. final String pkg = packageName == null ? job.getService().getPackageName() : packageName; if (!mQuotaTracker.isWithinQuota(userId, pkg, QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG)) { - Slog.e(TAG, userId + "-" + pkg + " has called schedule() too many times"); + if (mQuotaTracker.isWithinQuota(userId, pkg, QUOTA_TRACKER_SCHEDULE_LOGGED)) { + // Don't log too frequently + Slog.wtf(TAG, userId + "-" + pkg + " has called schedule() too many times"); + mQuotaTracker.noteEvent(userId, pkg, QUOTA_TRACKER_SCHEDULE_LOGGED); + } mAppStandbyInternal.restrictApp( pkg, userId, UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY); if (mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION) { @@ -1005,13 +1043,17 @@ public class JobSchedulerService extends com.android.server.SystemService // Only throw the exception for debuggable apps. throw new LimitExceededException( "schedule()/enqueue() called more than " - + mQuotaTracker.getLimit(Category.SINGLE_CATEGORY) + + mQuotaTracker.getLimit( + QUOTA_TRACKER_CATEGORY_SCHEDULE_PERSISTED) + " times in the past " - + mQuotaTracker.getWindowSizeMs(Category.SINGLE_CATEGORY) - + "ms"); + + mQuotaTracker.getWindowSizeMs( + QUOTA_TRACKER_CATEGORY_SCHEDULE_PERSISTED) + + "ms. See the documentation for more information."); } } - return JobScheduler.RESULT_FAILURE; + if (mConstants.API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT) { + return JobScheduler.RESULT_FAILURE; + } } mQuotaTracker.noteEvent(userId, pkg, QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG); } @@ -1372,10 +1414,12 @@ public class JobSchedulerService extends com.android.server.SystemService // Set up the app standby bucketing tracker mStandbyTracker = new StandbyTracker(); mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); - mQuotaTracker = new CountQuotaTracker(context, Categorizer.SINGLE_CATEGORIZER); - mQuotaTracker.setCountLimit(Category.SINGLE_CATEGORY, + mQuotaTracker = new CountQuotaTracker(context, QUOTA_CATEGORIZER); + mQuotaTracker.setCountLimit(QUOTA_TRACKER_CATEGORY_SCHEDULE_PERSISTED, mConstants.API_QUOTA_SCHEDULE_COUNT, mConstants.API_QUOTA_SCHEDULE_WINDOW_MS); + // Log at most once per minute. + mQuotaTracker.setCountLimit(QUOTA_TRACKER_CATEGORY_SCHEDULE_LOGGED, 1, 60_000); mAppStandbyInternal = LocalServices.getService(AppStandbyInternal.class); mAppStandbyInternal.addListener(mStandbyTracker); diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 79da1f6ab282..ee9bd3d259fb 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -1168,7 +1168,12 @@ public class IntentFilter implements Parcelable { public int match(Uri data, boolean wildcardSupported) { String host = data.getHost(); if (host == null) { - return NO_MATCH_DATA; + if (wildcardSupported && mWild) { + // special case, if no host is provided, but the Authority is wildcard, match + return MATCH_CATEGORY_HOST; + } else { + return NO_MATCH_DATA; + } } if (false) Log.v("IntentFilter", "Match host " + host + ": " + mHost); diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index bc9c71e7a68e..ab0ed51fb909 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -1510,7 +1510,7 @@ public class ParsingPackageUtils { Uri data = null; String dataType = null; - String host = IntentFilter.WILDCARD; + String host = null; final int numActions = intentInfo.countActions(); final int numSchemes = intentInfo.countDataSchemes(); final int numTypes = intentInfo.countDataTypes(); diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java index 0e10c42e61db..0eb3c1e8ad01 100644 --- a/core/java/android/net/MacAddress.java +++ b/core/java/android/net/MacAddress.java @@ -38,7 +38,9 @@ import java.util.Arrays; * Representation of a MAC address. * * This class only supports 48 bits long addresses and does not support 64 bits long addresses. - * Instances of this class are immutable. + * Instances of this class are immutable. This class provides implementations of hashCode() + * and equals() that make it suitable for use as keys in standard implementations of + * {@link java.util.Map}. */ public final class MacAddress implements Parcelable { @@ -122,12 +124,22 @@ public final class MacAddress implements Parcelable { } /** + * Convert this MacAddress to a byte array. + * + * The returned array is in network order. For example, if this MacAddress is 1:2:3:4:5:6, + * the returned array is [1, 2, 3, 4, 5, 6]. + * * @return a byte array representation of this MacAddress. */ public @NonNull byte[] toByteArray() { return byteAddrFromLongAddr(mAddr); } + /** + * Returns a human-readable representation of this MacAddress. + * The exact format is implementation-dependent and should not be assumed to have any + * particular format. + */ @Override public @NonNull String toString() { return stringAddrFromLongAddr(mAddr); diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java index 825077ffd57a..ad43f9556d8d 100644 --- a/core/java/android/view/ImeFocusController.java +++ b/core/java/android/view/ImeFocusController.java @@ -125,11 +125,11 @@ public final class ImeFocusController { final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView; onViewFocusChanged(viewForWindowFocus, true); - // Skip starting input when the next focused view is same as served view and the served - // input connection still exists. + // Starting new input when the next focused view is same as served view but the + // editor is not aligned with the same editor or editor is inactive. final boolean nextFocusIsServedView = mServedView != null && mServedView == focusedView; - if (nextFocusIsServedView && immDelegate.isAcceptingText()) { - forceFocus = false; + if (nextFocusIsServedView && !immDelegate.isSameEditorAndAcceptingText(focusedView)) { + forceFocus = true; } immDelegate.startInputAsyncOnWindowFocusGain(viewForWindowFocus, @@ -254,7 +254,7 @@ public final class ImeFocusController { void setCurrentRootView(ViewRootImpl rootView); boolean isCurrentRootView(ViewRootImpl rootView); boolean isRestartOnNextWindowFocus(boolean reset); - boolean isAcceptingText(); + boolean isSameEditorAndAcceptingText(View view); } public View getServedView() { diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index c6be91fa1bf5..a679b3740fd9 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -737,7 +737,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } } - final boolean hasControl = mTmpControlArray.size() > 0; + boolean requestedStateStale = false; final int[] showTypes = new int[1]; final int[] hideTypes = new int[1]; @@ -754,9 +754,26 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation // Ensure to create source consumers if not available yet. for (int i = mTmpControlArray.size() - 1; i >= 0; i--) { final InsetsSourceControl control = mTmpControlArray.valueAt(i); - InsetsSourceConsumer consumer = getSourceConsumer(control.getType()); + final @InternalInsetsType int type = control.getType(); + final InsetsSourceConsumer consumer = getSourceConsumer(type); consumer.setControl(control, showTypes, hideTypes); + if (!requestedStateStale) { + final boolean requestedVisible = consumer.isRequestedVisible(); + + // We might have changed our requested visibilities while we don't have the control, + // so we need to update our requested state once we have control. Otherwise, our + // requested state at the server side might be incorrect. + final boolean requestedVisibilityChanged = + requestedVisible != mRequestedState.getSourceOrDefaultVisibility(type); + + // The IME client visibility will be reset by insets source provider while updating + // control, so if IME is requested visible, we need to send the request to server. + final boolean imeRequestedVisible = type == ITYPE_IME && requestedVisible; + + requestedStateStale = requestedVisibilityChanged || imeRequestedVisible; + } + } mTmpControlArray.clear(); @@ -772,10 +789,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (hideTypes[0] != 0) { applyAnimation(hideTypes[0], false /* show */, false /* fromIme */); } - if (hasControl && mRequestedState.hasSources()) { - // We might have changed our requested visibilities while we don't have the control, - // so we need to update our requested state once we have control. Otherwise, our - // requested state at the server side might be incorrect. + if (requestedStateStale) { updateRequestedState(); } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 2b7044d0c67e..fefe564787ca 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1824,13 +1824,19 @@ public final class ViewRootImpl implements ViewParent, /** * Called after window layout to update the bounds surface. If the surface insets have changed * or the surface has resized, update the bounds surface. + * + * @param shouldReparent Whether it should reparent the bounds layer to the main SurfaceControl. */ - private void updateBoundsLayer() { + private void updateBoundsLayer(boolean shouldReparent) { if (mBoundsLayer != null) { setBoundsLayerCrop(); - mTransaction.deferTransactionUntil(mBoundsLayer, - getRenderSurfaceControl(), mSurface.getNextFrameNumber()) - .apply(); + mTransaction.deferTransactionUntil(mBoundsLayer, getRenderSurfaceControl(), + mSurface.getNextFrameNumber()); + + if (shouldReparent) { + mTransaction.reparent(mBoundsLayer, getRenderSurfaceControl()); + } + mTransaction.apply(); } } @@ -2912,7 +2918,16 @@ public final class ViewRootImpl implements ViewParent, } if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) { - updateBoundsLayer(); + // If the surface has been replaced, there's a chance the bounds layer is not parented + // to the new layer. When updating bounds layer, also reparent to the main VRI + // SurfaceControl to ensure it's correctly placed in the hierarchy. + // + // This needs to be done on the client side since WMS won't reparent the children to the + // new surface if it thinks the app is closing. WMS gets the signal that the app is + // stopping, but on the client side it doesn't get stopped since it's restarted quick + // enough. WMS doesn't want to keep around old children since they will leak when the + // client creates new children. + updateBoundsLayer(surfaceReplaced); } final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 3be0a4d39a56..37b352940ee4 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -633,20 +633,21 @@ public final class InputMethodManager { // we'll just do a window focus gain and call it a day. try { View servedView = controller.getServedView(); - boolean nextFocusIsServedView = servedView != null && servedView == focusedView; + boolean nextFocusSameEditor = servedView != null && servedView == focusedView + && isSameEditorAndAcceptingText(focusedView); if (DEBUG) { Log.v(TAG, "Reporting focus gain, without startInput" - + ", nextFocusIsServedView=" + nextFocusIsServedView); + + ", nextFocusIsServedView=" + nextFocusSameEditor); } final int startInputReason = - nextFocusIsServedView ? WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR + nextFocusSameEditor ? WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR; mService.startInputOrWindowGainedFocus( startInputReason, mClient, focusedView.getWindowToken(), startInputFlags, softInputMode, windowFlags, - nextFocusIsServedView ? mCurrentTextBoxAttribute : null, - nextFocusIsServedView ? mServedInputConnectionWrapper : null, + null, + null, 0 /* missingMethodFlags */, mCurRootView.mContext.getApplicationInfo().targetSdkVersion); } catch (RemoteException e) { @@ -671,10 +672,6 @@ public final class InputMethodManager { @Override public void setCurrentRootView(ViewRootImpl rootView) { synchronized (mH) { - if (mCurRootView != null) { - // Restart the input when the next window focus state of the root view changed. - mRestartOnNextWindowFocus = true; - } mCurRootView = rootView; } } @@ -704,14 +701,33 @@ public final class InputMethodManager { } /** - * For {@link ImeFocusController} to check if the currently served view is accepting full - * text edits. + * For {@link ImeFocusController} to check if the given focused view aligns with the same + * editor and the editor is active to accept the text input. + * + * TODO(b/160968797): Remove this method and move mCurrentTextBoxAttritube to + * ImeFocusController. + * In the long-term, we should make mCurrentTextBoxAtrtribue as per-window base instance, + * so that we we can directly check if the current focused view aligned with the same editor + * in the window without using this checking. + * + * Note that this method is only use for fixing start new input may ignored issue + * (e.g. b/160391516), DO NOT leverage this method to do another check. */ - @Override - public boolean isAcceptingText() { + public boolean isSameEditorAndAcceptingText(View view) { synchronized (mH) { - return mServedInputConnectionWrapper != null - && mServedInputConnectionWrapper.getInputConnection() != null; + if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null) { + return false; + } + + final EditorInfo ic = mCurrentTextBoxAttribute; + // This sameEditor checking is based on using object hash comparison to check if + // some fields of the current EditorInfo (e.g. autoFillId, OpPackageName) the + // hash code is same as the given focused view. + final boolean sameEditor = view.onCheckIsTextEditor() && view.getId() == ic.fieldId + && view.getAutofillId() == ic.autofillId + && view.getContext().getOpPackageName() == ic.packageName; + return sameEditor && mServedInputConnectionWrapper != null + && mServedInputConnectionWrapper.isActive(); } } } diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index c5729b05c587..046981cf2e8f 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -21,8 +21,6 @@ import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COM import static android.view.View.SYSTEM_UI_LAYOUT_FLAGS; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; -import static android.view.WindowInsets.Type.ime; -import static android.view.WindowInsets.Type.systemBars; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; @@ -34,8 +32,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS; -import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; -import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import android.annotation.NonNull; import android.annotation.Nullable; @@ -146,17 +142,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if ((view.getWindowSystemUiVisibility() & SYSTEM_UI_LAYOUT_FLAGS) != 0) { return new Pair<>(Insets.NONE, insets); } - - boolean includeIme = (view.getViewRootImpl().mWindowAttributes.softInputMode - & SOFT_INPUT_MASK_ADJUST) - == SOFT_INPUT_ADJUST_RESIZE; - Insets insetsToApply; - if (ViewRootImpl.sNewInsetsMode == 0) { - insetsToApply = insets.getSystemWindowInsets(); - } else { - insetsToApply = insets.getInsets(systemBars() | (includeIme ? ime() : 0)); - } - insets = insets.inset(insetsToApply); + Insets insetsToApply = insets.getSystemWindowInsets(); return new Pair<>(insetsToApply, insets.inset(insetsToApply).consumeSystemWindowInsets()); }; diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index ec99684bf636..f2f20e3ac12e 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -236,6 +236,8 @@ message ConstantsProto { optional int64 api_quota_schedule_window_ms = 33; // Whether or not to throw an exception when an app hits its schedule quota limit. optional bool api_quota_schedule_throw_exception = 34; + // Whether or not to return a failure result when an app hits its schedule quota limit. + optional bool api_quota_schedule_return_failure_result = 35; message QuotaController { option (.android.msg_privacy).dest = DEST_AUTOMATIC; @@ -335,7 +337,7 @@ message ConstantsProto { // In this time after screen turns on, we increase job concurrency. optional int32 screen_off_job_concurrency_increase_delay_ms = 28; - // Next tag: 35 + // Next tag: 36 } // Next tag: 4 diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index cf08d242e635..71958e88e99c 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -422,9 +422,9 @@ <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"atzitu kokapen-hornitzaileen komando gehigarriak"</string> <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Kokapen-hornitzailearen agindu gehigarriak atzitzeko baimena ematen die aplikazioei. Horrela, agian aplikazioek GPSaren edo bestelako kokapenaren iturburuen funtzionamenduan eragina izan dezakete."</string> <string name="permlab_accessFineLocation" msgid="6426318438195622966">"lortu kokapen zehatza aurreko planoan bakarrik"</string> - <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Erabiltzen ari zarenean, aplikazioak kokapen zehatza lor dezake kokapen-zerbitzuen bidez. Aplikazioak kokapena lortu ahal izateko, kokapen-zerbitzuek aktibatuta egon behar dute gailuan. Bateria-erabilera areagotzen du horrek."</string> + <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Abian denean, aplikazioak kokapen zehatza lor dezake kokapen-zerbitzuen bidez. Aplikazioak kokapena lortu ahal izateko, kokapen-zerbitzuek aktibatuta egon behar dute gailuan. Bateria-erabilera areagotzen du horrek."</string> <string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"atzitu gutxi gorabeherako kokapena aurreko planoan bakarrik"</string> - <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"Erabiltzen ari zarenean, aplikazioak gutxi gorabeherako kokapena lor dezake kokapen-zerbitzuen bidez. Aplikazioak kokapena lortu ahal izateko, kokapen-zerbitzuek aktibatuta egon behar dute gailuan."</string> + <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"Abian denean, aplikazioak gutxi gorabeherako kokapena lor dezake kokapen-zerbitzuen bidez. Aplikazioak kokapena lortu ahal izateko, kokapen-zerbitzuek aktibatuta egon behar dute gailuan."</string> <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"atzitu kokapena atzeko planoan"</string> <string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"Aplikazioak kokapena atzi dezake, baita aplikazioa erabiltzen ari ez zarenean ere."</string> <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"aldatu audio-ezarpenak"</string> diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index 702f2fa65487..c36f1067149e 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -691,18 +691,57 @@ public class InsetsControllerTest { @Test public void testRequestedState() { InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + + // The modified state can be controlled when we have control. mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR)); mController.hide(statusBars()); assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible()); - mController.onControlsChanged(new InsetsSourceControl[0]); + + // The modified state won't be changed while losing control. + mController.onControlsChanged(null /* activeControls */); assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible()); + + // The modified state won't be changed while state changed while we don't have control. InsetsState newState = new InsetsState(mController.getState(), true /* copySource */); mController.onStateChanged(newState); assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible()); + + // The modified state won't be changed while controlling an insets without having the + // control. mController.show(statusBars()); assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible()); + + // The modified state can be updated while gaining control. mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR)); assertTrue(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible()); + + // The modified state can still be updated if the local state and the requested state + // are the same. + mController.onControlsChanged(null /* activeControls */); + mController.hide(statusBars()); + newState = new InsetsState(mController.getState(), true /* copySource */); + newState.getSource(ITYPE_STATUS_BAR).setVisible(false); + mController.onStateChanged(newState); + mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR)); + assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible()); + + // The modified state will always be updated while receiving IME control if IME is + // requested visible. + mController.getSourceConsumer(ITYPE_IME).show(false /* fromIme */); + newState = new InsetsState(mController.getState(), true /* copySource */); + newState.getSource(ITYPE_IME).setVisible(true); + newState.getSource(ITYPE_IME).setFrame(1, 2, 3, 4); + mController.onStateChanged(newState); + mController.onControlsChanged(createSingletonControl(ITYPE_IME)); + assertEquals(newState.getSource(ITYPE_IME), + mTestHost.getModifiedState().peekSource(ITYPE_IME)); + newState = new InsetsState(mController.getState(), true /* copySource */); + newState.getSource(ITYPE_IME).setVisible(true); + newState.getSource(ITYPE_IME).setFrame(5, 6, 7, 8); + mController.onStateChanged(newState); + mController.onControlsChanged(createSingletonControl(ITYPE_IME)); + assertEquals(newState.getSource(ITYPE_IME), + mTestHost.getModifiedState().peekSource(ITYPE_IME)); }); } diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java index 838f60069f27..df2946c97d20 100644 --- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java +++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java @@ -37,7 +37,6 @@ import static org.junit.Assert.assertTrue; import android.app.Activity; import android.app.Instrumentation; import android.graphics.Rect; -import android.platform.test.annotations.Presubmit; import android.text.Layout; import android.text.Spannable; import android.text.SpannableString; @@ -96,7 +95,6 @@ public class EditorCursorDragTest { mMotionEvents.clear(); } - @Presubmit @Test public void testCursorDrag_horizontal_whenTextViewContentsFitOnScreen() throws Throwable { String text = "Hello world!"; diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp index aa8849b642b1..8f67f97fb4bc 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp @@ -48,29 +48,20 @@ static void setScissor(int viewportHeight, const SkIRect& clip) { glScissor(clip.fLeft, y, clip.width(), height); } -static bool GetFboDetails(SkCanvas* canvas, GLuint* outFboID, SkISize* outFboSize) { +static void GetFboDetails(SkCanvas* canvas, GLuint* outFboID, SkISize* outFboSize) { GrRenderTargetContext* renderTargetContext = canvas->internal_private_accessTopLayerRenderTargetContext(); - if (!renderTargetContext) { - ALOGW("Unable to extract renderTarget info from canvas; aborting GLFunctor draw"); - return false; - } + LOG_ALWAYS_FATAL_IF(!renderTargetContext, "Failed to retrieve GrRenderTargetContext"); GrRenderTarget* renderTarget = renderTargetContext->accessRenderTarget(); - if (!renderTarget) { - ALOGW("Unable to extract renderTarget info from canvas; aborting GLFunctor draw"); - return false; - } + LOG_ALWAYS_FATAL_IF(!renderTarget, "accessRenderTarget failed"); GrGLFramebufferInfo fboInfo; - if (!renderTarget->getBackendRenderTarget().getGLFramebufferInfo(&fboInfo)) { - ALOGW("Unable to extract renderTarget info from canvas; aborting GLFunctor draw"); - return false; - } + LOG_ALWAYS_FATAL_IF(!renderTarget->getBackendRenderTarget().getGLFramebufferInfo(&fboInfo), + "getGLFrameBufferInfo failed"); *outFboID = fboInfo.fFBOID; *outFboSize = SkISize::Make(renderTargetContext->width(), renderTargetContext->height()); - return true; } void GLFunctorDrawable::onDraw(SkCanvas* canvas) { @@ -85,11 +76,12 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { return; } + // flush will create a GrRenderTarget if not already present. + canvas->flush(); + GLuint fboID = 0; SkISize fboSize; - if (!GetFboDetails(canvas, &fboID, &fboSize)) { - return; - } + GetFboDetails(canvas, &fboID, &fboSize); SkIRect surfaceBounds = canvas->internal_private_getTopLayerBounds(); SkIRect clipBounds = canvas->getDeviceClipBounds(); @@ -143,7 +135,6 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { // ensure that the framebuffer that the webview will render into is bound before we clear // the stencil and/or draw the functor. - canvas->flush(); glViewport(0, 0, info.width, info.height); glBindFramebuffer(GL_FRAMEBUFFER, fboID); diff --git a/location/java/android/location/package.html b/location/java/android/location/package.html index 2355e725b6c5..20c5c54d6921 100644 --- a/location/java/android/location/package.html +++ b/location/java/android/location/package.html @@ -6,7 +6,7 @@ <p class="warning"> <strong>This API is not the recommended method for accessing Android location.</strong><br> The -<a href="{@docRoot}reference/com/google/android/gms/location/package-summary.html">Google Location Services API</a>, +<a href="https://developers.google.com/android/reference/com/google/android/gms/location/package-summary">Google Location Services API</a>, part of Google Play services, is the preferred way to add location-awareness to your app. It offers a simpler API, higher accuracy, low-power geofencing, and more. If you are currently using the android.location API, you are strongly diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index baa570e4a547..79300ee29a67 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -28,15 +28,15 @@ <string name="battery_low_percent_format" msgid="4276661262843170964">"僅剩 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"電力剩餘 <xliff:g id="PERCENTAGE">%1$s</xliff:g>,根據你的使用情形,剩餘時間大約還有 <xliff:g id="TIME">%2$s</xliff:g>"</string> <string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"電力剩餘 <xliff:g id="PERCENTAGE">%1$s</xliff:g>,剩餘時間大約還有 <xliff:g id="TIME">%2$s</xliff:g>"</string> - <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"僅剩 <xliff:g id="PERCENTAGE">%s</xliff:g>。節約耗電量模式已開啟。"</string> + <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"僅剩 <xliff:g id="PERCENTAGE">%s</xliff:g>。省電模式已開啟。"</string> <string name="invalid_charger" msgid="4370074072117767416">"無法透過 USB 充電,請使用裝置隨附的充電器。"</string> <string name="invalid_charger_title" msgid="938685362320735167">"無法透過 USB 充電"</string> <string name="invalid_charger_text" msgid="2339310107232691577">"使用裝置隨附的充電器"</string> <string name="battery_low_why" msgid="2056750982959359863">"設定"</string> - <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"要開啟節約耗電量模式嗎?"</string> - <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"關於節約耗電量功能"</string> + <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"要開啟省電模式嗎?"</string> + <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"關於省電模式"</string> <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"開啟"</string> - <string name="battery_saver_start_action" msgid="4553256017945469937">"開啟節約耗電量模式"</string> + <string name="battery_saver_start_action" msgid="4553256017945469937">"開啟省電模式"</string> <string name="status_bar_settings_settings_button" msgid="534331565185171556">"設定"</string> <string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string> <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"自動旋轉螢幕"</string> @@ -421,7 +421,7 @@ <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g> 開啟"</string> <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> 關閉"</string> <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"深色主題"</string> - <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"節約耗電量"</string> + <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"省電模式"</string> <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"於日落時開啟"</string> <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"於日出時關閉"</string> <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"開啟時間:<xliff:g id="TIME">%s</xliff:g>"</string> @@ -499,9 +499,9 @@ <string name="user_remove_user_title" msgid="9124124694835811874">"要移除使用者嗎?"</string> <string name="user_remove_user_message" msgid="6702834122128031833">"系統將刪除這個使用者的所有應用程式和資料。"</string> <string name="user_remove_user_remove" msgid="8387386066949061256">"移除"</string> - <string name="battery_saver_notification_title" msgid="8419266546034372562">"節約耗電量模式已開啟"</string> + <string name="battery_saver_notification_title" msgid="8419266546034372562">"省電模式已開啟"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"降低效能並限制背景數據傳輸"</string> - <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"關閉節約耗電量模式"</string> + <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"關閉省電模式"</string> <string name="media_projection_dialog_text" msgid="1755705274910034772">"在錄製或投放內容時,「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」可存取畫面上顯示的任何資訊或裝置播放的任何內容,包括密碼、付款詳情、相片、訊息和你播放的音訊。"</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"在錄製或投放內容時,提供這項功能的服務可存取畫面上顯示的任何資訊或裝置播放的任何內容,包括密碼、付款詳情、相片、訊息和你播放的音訊。"</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"要開始錄製或投放內容嗎?"</string> @@ -767,8 +767,8 @@ <item quantity="one">%d 分鐘</item> </plurals> <string name="battery_panel_title" msgid="5931157246673665963">"電池用量"</string> - <string name="battery_detail_charging_summary" msgid="8821202155297559706">"充電時無法使用節約耗電量模式"</string> - <string name="battery_detail_switch_title" msgid="6940976502957380405">"節約耗電量"</string> + <string name="battery_detail_charging_summary" msgid="8821202155297559706">"充電時無法使用省電模式"</string> + <string name="battery_detail_switch_title" msgid="6940976502957380405">"省電模式"</string> <string name="battery_detail_switch_summary" msgid="3668748557848025990">"降低效能並限制背景資料傳輸"</string> <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> 按鈕"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Home 鍵"</string> @@ -980,11 +980,11 @@ <string name="slice_permission_checkbox" msgid="4242888137592298523">"允許「<xliff:g id="APP">%1$s</xliff:g>」顯示任何應用程式的區塊"</string> <string name="slice_permission_allow" msgid="6340449521277951123">"允許"</string> <string name="slice_permission_deny" msgid="6870256451658176895">"拒絕"</string> - <string name="auto_saver_title" msgid="6873691178754086596">"輕觸即可排定節約耗電量模式自動開啟的情況"</string> + <string name="auto_saver_title" msgid="6873691178754086596">"輕觸即可排定省電模式自動開啟的情況"</string> <string name="auto_saver_text" msgid="3214960308353838764">"在電池電量即將耗盡時開啟"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"不用了,謝謝"</string> - <string name="auto_saver_enabled_title" msgid="4294726198280286333">"已按照排定開啟節約耗電量模式"</string> - <string name="auto_saver_enabled_text" msgid="7889491183116752719">"節約耗電量模式會在電量低於 <xliff:g id="PERCENTAGE">%d</xliff:g>%% 時自動開啟。"</string> + <string name="auto_saver_enabled_title" msgid="4294726198280286333">"已按照排定開啟省電模式"</string> + <string name="auto_saver_enabled_text" msgid="7889491183116752719">"省電模式會在電量低於 <xliff:g id="PERCENTAGE">%d</xliff:g>%% 時自動開啟。"</string> <string name="open_saver_setting_action" msgid="2111461909782935190">"設定"</string> <string name="auto_saver_okay_action" msgid="7815925750741935386">"我知道了"</string> <string name="heap_dump_tile_name" msgid="2464189856478823046">"傾印 SysUI 記憶體快照"</string> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index b39eaf3f3324..3acbfb87c3f4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -228,6 +228,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private final Context mContext; private final boolean mIsPrimaryUser; + private final boolean mIsAutomotive; private final StatusBarStateController mStatusBarStateController; HashMap<Integer, SimData> mSimDatas = new HashMap<>(); HashMap<Integer, ServiceState> mServiceStates = new HashMap<Integer, ServiceState>(); @@ -1770,6 +1771,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mFaceManager.addLockoutResetCallback(mFaceLockoutResetCallback); } + mIsAutomotive = isAutomotive(); + ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); mUserManager = context.getSystemService(UserManager.class); mIsPrimaryUser = mUserManager.isPrimaryUser(); @@ -2484,6 +2487,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab .addCategory(Intent.CATEGORY_HOME); ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(homeIntent, 0 /* flags */); + + // TODO(b/160971249): Replace in the future by resolving activity as user. + if (resolveInfo == null && mIsAutomotive) { + Log.w(TAG, "resolveNeedsSlowUnlockTransition: returning false since activity " + + "could not be resolved."); + return false; + } + return FALLBACK_HOME_COMPONENT.equals(resolveInfo.getComponentInfo().getComponentName()); } @@ -2554,6 +2565,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab return false; } + private boolean isAutomotive() { + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); + } + /** * Remove the given observer's callback. * @@ -2990,5 +3005,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab pw.println(" " + time + " " + model.toString()); } } + if (mIsAutomotive) { + pw.println(" Running on Automotive build"); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java index 204354645e10..2a83aa06a237 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -104,6 +104,8 @@ public class PipMenuActivity extends Activity { private static final int INITIAL_DISMISS_DELAY = 3500; private static final int POST_INTERACTION_DISMISS_DELAY = 2000; private static final long MENU_FADE_DURATION = 125; + private static final long MENU_SLOW_FADE_DURATION = 175; + private static final long MENU_SHOW_ON_EXPAND_START_DELAY = 30; private static final float MENU_BACKGROUND_ALPHA = 0.3f; private static final float DISMISS_BACKGROUND_ALPHA = 0.6f; @@ -182,6 +184,7 @@ public class PipMenuActivity extends Activity { break; } case MESSAGE_MENU_EXPANDED : { + mMenuContainerAnimator.setStartDelay(MENU_SHOW_ON_EXPAND_START_DELAY); mMenuContainerAnimator.start(); break; } @@ -400,7 +403,9 @@ public class PipMenuActivity extends Activity { mMenuContainerAnimator.playTogether(dismissAnim, resizeAnim); } mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN); - mMenuContainerAnimator.setDuration(MENU_FADE_DURATION); + mMenuContainerAnimator.setDuration(menuState == MENU_STATE_CLOSE + ? MENU_FADE_DURATION + : MENU_SLOW_FADE_DURATION); if (allowMenuTimeout) { mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java index 2ef693467d27..201ed9c9ebec 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java @@ -100,7 +100,8 @@ public class UserDetailView extends PseudoGridView { if (item.picture == null) { v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId()); } else { - int avatarSize = (int) v.getResources().getDimension(R.dimen.qs_framed_avatar_size); + int avatarSize = + (int) mContext.getResources().getDimension(R.dimen.qs_framed_avatar_size); Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize); drawable.setColorFilter( item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter()); diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index 8a3819925f30..370f9a762402 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -193,10 +193,11 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, @Override public void onKeyguardShowingChanged() { - if (!isDividerVisible() || mView == null) { + if (!isSplitActive() || mView == null) { return; } mView.setHidden(mKeyguardStateController.isShowing()); + mImePositionProcessor.updateAdjustForIme(); } @Override @@ -285,8 +286,9 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, * while this only cares if some things are (eg. while entering/exiting as well). */ private boolean isSplitActive() { - return mSplits.mPrimary.topActivityType != ACTIVITY_TYPE_UNDEFINED - || mSplits.mSecondary.topActivityType != ACTIVITY_TYPE_UNDEFINED; + return mSplits.mPrimary != null && mSplits.mSecondary != null + && (mSplits.mPrimary.topActivityType != ACTIVITY_TYPE_UNDEFINED + || mSplits.mSecondary.topActivityType != ACTIVITY_TYPE_UNDEFINED); } private void addDivider(Configuration configuration) { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java index 47c8c0ad8a4e..9db389eba3d8 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java @@ -91,6 +91,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor private boolean mPaused = true; private boolean mPausedTargetAdjusted = false; + private boolean mAdjustedWhileHidden = false; DividerImeController(SplitScreenTaskOrganizer splits, TransactionPool pool, Handler handler) { mSplits = splits; @@ -170,11 +171,17 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor // If split is hidden, we don't want to trigger any relayouts that would cause the // divider to show again. updateImeAdjustState(); + } else { + mAdjustedWhileHidden = true; } } private void updateImeAdjustState() { - if (mAdjusted != mTargetAdjusted) { + updateImeAdjustState(false /* force */); + } + + private void updateImeAdjustState(boolean force) { + if (mAdjusted != mTargetAdjusted || force) { // Reposition the server's secondary split position so that it evaluates // insets properly. WindowContainerTransaction wct = new WindowContainerTransaction(); @@ -231,6 +238,11 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor mSplits.mDivider.setAdjustedForIme(mTargetShown && !mPaused); } + public void updateAdjustForIme() { + updateImeAdjustState(mAdjustedWhileHidden); + mAdjustedWhileHidden = false; + } + @Override public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java index 5ec5ec662164..f52a6e0191a1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java @@ -288,7 +288,8 @@ public class KeyguardUserSwitcher { if (item.picture == null) { v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId()); } else { - int avatarSize = (int) v.getResources().getDimension(R.dimen.kg_framed_avatar_size); + int avatarSize = + (int) mContext.getResources().getDimension(R.dimen.kg_framed_avatar_size); Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize); drawable.setColorFilter( item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter()); diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java index e5f30cf63ac3..9e3fcc401ffa 100644 --- a/packages/SystemUI/src/com/android/systemui/util/Utils.java +++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java @@ -129,9 +129,7 @@ public class Utils { * Off by default, but can be disabled by setting to 0 */ public static boolean useQsMediaPlayer(Context context) { - int flag = Settings.Global.getInt(context.getContentResolver(), - Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1); - return flag > 0; + return true; } /** diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java index c0089e53f8b6..1ce98eb152c8 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java +++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java @@ -273,10 +273,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged if (imeSource == null || mImeSourceControl == null) { return; } - // Set frame, but only if the new frame isn't empty -- this maintains continuity final Rect newFrame = imeSource.getFrame(); - mImeFrame.set(newFrame); - final boolean isFloating = newFrame.height() == 0; + final boolean isFloating = newFrame.height() == 0 && show; if (isFloating) { // This is likely a "floating" or "expanded" IME, so to get animations, just // pretend the ime has some size just below the screen. @@ -285,6 +283,9 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged mSystemWindows.mDisplayController.getDisplayLayout(mDisplayId).density() * FLOATING_IME_BOTTOM_INSET); mImeFrame.bottom -= floatingInset; + } else if (newFrame.height() != 0) { + // Don't set a new frame if it's empty and hiding -- this maintains continuity + mImeFrame.set(newFrame); } if (DEBUG) { Slog.d(TAG, "Run startAnim show:" + show + " was:" diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt index 6d6a4d8f6b7d..f48b3fc51e82 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt @@ -25,6 +25,8 @@ import android.view.View import android.view.ViewGroup import androidx.test.filters.SmallTest import com.android.internal.logging.testing.UiEventLoggerFake +import com.android.internal.util.UserIcons +import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.qs.QSUserSwitcherEvent import com.android.systemui.statusbar.policy.UserSwitcherController @@ -50,10 +52,10 @@ class UserDetailViewAdapterTest : SysuiTestCase() { @Mock private lateinit var mOtherView: View @Mock private lateinit var mInflatedUserDetailItemView: UserDetailItemView @Mock private lateinit var mUserInfo: UserInfo - @Mock private lateinit var mPicture: Bitmap @Mock private lateinit var mLayoutInflater: LayoutInflater private lateinit var adapter: UserDetailView.Adapter private lateinit var uiEventLogger: UiEventLoggerFake + private lateinit var mPicture: Bitmap @Before fun setUp() { @@ -64,6 +66,7 @@ class UserDetailViewAdapterTest : SysuiTestCase() { `when`(mLayoutInflater.inflate(anyInt(), any(ViewGroup::class.java), anyBoolean())) .thenReturn(mInflatedUserDetailItemView) adapter = UserDetailView.Adapter(mContext, mUserSwitcherController, uiEventLogger) + mPicture = UserIcons.convertToBitmap(mContext.getDrawable(R.drawable.ic_avatar_user)) } private fun clickableTest( @@ -141,4 +144,4 @@ class UserDetailViewAdapterTest : SysuiTestCase() { false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */) -}
\ No newline at end of file +} diff --git a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index e10bab4b36b5..9bb01ae5df1d 100644 --- a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java +++ b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -102,17 +102,21 @@ public class EthernetTetheringTest { private UiAutomation mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + private boolean mRunTests; @Before public void setUp() throws Exception { - mHandlerThread = new HandlerThread(getClass().getSimpleName()); - mHandlerThread.start(); - mHandler = new Handler(mHandlerThread.getLooper()); - mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm); // Needed to create a TestNetworkInterface, to call requestTetheredInterface, and to receive // tethered client callbacks. mUiAutomation.adoptShellPermissionIdentity( MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, TETHER_PRIVILEGED); + mRunTests = mTm.isTetheringSupported() && mEm != null; + assumeTrue(mRunTests); + + mHandlerThread = new HandlerThread(getClass().getSimpleName()); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm); } private void cleanUp() throws Exception { @@ -136,7 +140,7 @@ public class EthernetTetheringTest { @After public void tearDown() throws Exception { try { - cleanUp(); + if (mRunTests) cleanUp(); } finally { mUiAutomation.dropShellPermissionIdentity(); } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 5124c4a4797e..a2eea1348d5c 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -470,22 +470,23 @@ public final class BroadcastQueue { // if this receiver was slow, impose deferral policy on the app. This will kick in // when processNextBroadcastLocked() next finds this uid as a receiver identity. if (!r.timeoutExempt) { - if (mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) { + // r.curApp can be null if finish has raced with process death - benign + // edge case, and we just ignore it because we're already cleaning up + // as expected. + if (r.curApp != null + && mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) { // Core system packages are exempt from deferral policy if (!UserHandle.isCore(r.curApp.uid)) { if (DEBUG_BROADCAST_DEFERRAL) { Slog.i(TAG_BROADCAST, "Broadcast receiver " + (r.nextReceiver - 1) + " was slow: " + receiver + " br=" + r); } - if (r.curApp != null) { - mDispatcher.startDeferring(r.curApp.uid); - } else { - Slog.d(TAG_BROADCAST, "finish receiver curApp is null? " + r); - } + mDispatcher.startDeferring(r.curApp.uid); } else { if (DEBUG_BROADCAST_DEFERRAL) { Slog.i(TAG_BROADCAST, "Core uid " + r.curApp.uid - + " receiver was slow but not deferring: " + receiver + " br=" + r); + + " receiver was slow but not deferring: " + + receiver + " br=" + r); } } } diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index b279b370c611..ed3a223b5dd7 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -400,7 +400,7 @@ public class ClipboardService extends SystemService { final int intendingUid = getIntendingUid(callingPackage, userId); final int intendingUserId = UserHandle.getUserId(intendingUid); if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, - intendingUid, intendingUserId) + intendingUid, intendingUserId, false) || isDeviceLocked(intendingUserId)) { return null; } @@ -416,7 +416,7 @@ public class ClipboardService extends SystemService { final int intendingUid = getIntendingUid(callingPackage, userId); final int intendingUserId = UserHandle.getUserId(intendingUid); if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, - intendingUid, intendingUserId) + intendingUid, intendingUserId, false) || isDeviceLocked(intendingUserId)) { return false; } @@ -450,7 +450,7 @@ public class ClipboardService extends SystemService { final int intendingUid = getIntendingUid(callingPackage, userId); final int intendingUserId = UserHandle.getUserId(intendingUid); if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, - intendingUid, intendingUserId) + intendingUid, intendingUserId, false) || isDeviceLocked(intendingUserId)) { return false; } @@ -740,14 +740,21 @@ public class ClipboardService extends SystemService { private boolean clipboardAccessAllowed(int op, String callingPackage, int uid, @UserIdInt int userId) { - // Check the AppOp. - if (mAppOps.noteOp(op, uid, callingPackage) != AppOpsManager.MODE_ALLOWED) { - return false; - } + return clipboardAccessAllowed(op, callingPackage, uid, userId, true); + } + + private boolean clipboardAccessAllowed(int op, String callingPackage, int uid, + @UserIdInt int userId, boolean shouldNoteOp) { + + boolean allowed = false; + + // First, verify package ownership to ensure use below is safe. + mAppOps.checkPackage(uid, callingPackage); + // Shell can access the clipboard for testing purposes. if (mPm.checkPermission(android.Manifest.permission.READ_CLIPBOARD_IN_BACKGROUND, callingPackage) == PackageManager.PERMISSION_GRANTED) { - return true; + allowed = true; } // The default IME is always allowed to access the clipboard. String defaultIme = Settings.Secure.getStringForUser(getContext().getContentResolver(), @@ -755,7 +762,7 @@ public class ClipboardService extends SystemService { if (!TextUtils.isEmpty(defaultIme)) { final String imePkg = ComponentName.unflattenFromString(defaultIme).getPackageName(); if (imePkg.equals(callingPackage)) { - return true; + allowed = true; } } @@ -766,8 +773,10 @@ public class ClipboardService extends SystemService { // at the same time. e.x. SystemUI. It needs to check the window focus of // Binder.getCallingUid(). Without checking, the user X can't copy any thing from // INTERNAL_SYSTEM_WINDOW to the other applications. - boolean allowed = mWm.isUidFocused(uid) - || isInternalSysWindowAppWithWindowFocus(callingPackage); + if (!allowed) { + allowed = mWm.isUidFocused(uid) + || isInternalSysWindowAppWithWindowFocus(callingPackage); + } if (!allowed && mContentCaptureInternal != null) { // ...or the Content Capture Service // The uid parameter of mContentCaptureInternal.isContentCaptureServiceForUser @@ -786,17 +795,28 @@ public class ClipboardService extends SystemService { // userId must pass intending userId. i.e. user#10. allowed = mAutofillInternal.isAugmentedAutofillServiceForUser(uid, userId); } - if (!allowed) { - Slog.e(TAG, "Denying clipboard access to " + callingPackage - + ", application is not in focus neither is a system service for " - + "user " + userId); - } - return allowed; + break; case AppOpsManager.OP_WRITE_CLIPBOARD: // Writing is allowed without focus. - return true; + allowed = true; + break; default: throw new IllegalArgumentException("Unknown clipboard appop " + op); } + if (!allowed) { + Slog.e(TAG, "Denying clipboard access to " + callingPackage + + ", application is not in focus nor is it a system service for " + + "user " + userId); + return false; + } + // Finally, check the app op. + int appOpsResult; + if (shouldNoteOp) { + appOpsResult = mAppOps.noteOp(op, uid, callingPackage); + } else { + appOpsResult = mAppOps.checkOp(op, uid, callingPackage); + } + + return appOpsResult == AppOpsManager.MODE_ALLOWED; } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index d8ee32e7bd74..0154fe07a418 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -18,8 +18,6 @@ package com.android.server.inputmethod; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; -import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR; - import static java.lang.annotation.RetentionPolicy.SOURCE; import android.Manifest; @@ -719,11 +717,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ int mImeWindowVis; - /** - * Checks if the client needs to start input. - */ - private boolean mCurClientNeedStartInput = false; - private AlertDialog.Builder mDialogBuilder; private AlertDialog mSwitchingDialog; private IBinder mSwitchingDialogToken = new Binder(); @@ -3467,20 +3460,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (mCurFocusedWindow == windowToken) { if (DEBUG) { Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client - + " attribute=" + attribute + ", token = " + windowToken); - } - // Needs to start input when the same window focus gain but not with the same editor, - // or when the current client needs to start input (e.g. when focusing the same - // window after device turned screen on). - if (attribute != null && (startInputReason != WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR - || mCurClientNeedStartInput)) { - if (mIsInteractive) { - mCurClientNeedStartInput = false; - } + + " attribute=" + attribute + ", token = " + windowToken + + ", startInputReason=" + + InputMethodDebug.startInputReasonToString(startInputReason)); + } + if (attribute != null) { return startInputUncheckedLocked(cs, inputContext, missingMethods, attribute, startInputFlags, startInputReason); } - return new InputBindResult( InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY, null, null, null, -1, null); @@ -4459,9 +4446,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private void handleSetInteractive(final boolean interactive) { synchronized (mMethodMap) { mIsInteractive = interactive; - if (!interactive) { - mCurClientNeedStartInput = true; - } updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition); // Inform the current client of the change in active status diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 18635e8c07e3..2fe783387e23 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1621,8 +1621,6 @@ public class NotificationManagerService extends SystemService { = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE); private final Uri NOTIFICATION_HISTORY_ENABLED = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_HISTORY_ENABLED); - private final Uri NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI - = Settings.Global.getUriFor(Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS); SettingsObserver(Handler handler) { super(handler); @@ -1640,8 +1638,6 @@ public class NotificationManagerService extends SystemService { false, this, UserHandle.USER_ALL); resolver.registerContentObserver(NOTIFICATION_HISTORY_ENABLED, false, this, UserHandle.USER_ALL); - resolver.registerContentObserver(NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI, - false, this, UserHandle.USER_ALL); update(null); } @@ -1678,9 +1674,6 @@ public class NotificationManagerService extends SystemService { Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0) == 1); } } - if (uri == null || NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI.equals(uri)) { - mPreferencesHelper.updateMediaNotificationFilteringEnabled(); - } } } diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index dd6a83bc3f60..bc78d66037fe 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -166,7 +166,8 @@ public class PreferencesHelper implements RankingConfig { private SparseBooleanArray mBadgingEnabled; private boolean mBubblesEnabledGlobally = DEFAULT_GLOBAL_ALLOW_BUBBLE; - private boolean mIsMediaNotificationFilteringEnabled = DEFAULT_MEDIA_NOTIFICATION_FILTERING; + private final boolean mIsMediaNotificationFilteringEnabled = + DEFAULT_MEDIA_NOTIFICATION_FILTERING; private boolean mAreChannelsBypassingDnd; private boolean mHideSilentStatusBarIcons = DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS; @@ -186,7 +187,6 @@ public class PreferencesHelper implements RankingConfig { updateBadgingEnabled(); updateBubblesEnabled(); - updateMediaNotificationFilteringEnabled(); syncChannelsBypassingDnd(mContext.getUserId()); } @@ -2292,16 +2292,6 @@ public class PreferencesHelper implements RankingConfig { return mBubblesEnabledGlobally; } - /** Requests check of the feature setting for showing media notifications in quick settings. */ - public void updateMediaNotificationFilteringEnabled() { - final boolean newValue = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1) > 0; - if (newValue != mIsMediaNotificationFilteringEnabled) { - mIsMediaNotificationFilteringEnabled = newValue; - updateConfig(); - } - } - /** Returns true if the setting is enabled for showing media notifications in quick settings. */ public boolean isMediaNotificationFilteringEnabled() { return mIsMediaNotificationFilteringEnabled; diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 08cdd8f05292..330f99523507 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -865,7 +865,16 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements @Override public ParceledListSlice<SessionInfo> getStagedSessions() { - return mStagingManager.getSessions(Binder.getCallingUid()); + final List<SessionInfo> result = new ArrayList<>(); + synchronized (mSessions) { + for (int i = 0; i < mSessions.size(); i++) { + final PackageInstallerSession session = mSessions.valueAt(i); + if (session.isStaged() && !session.isDestroyed()) { + result.add(session.generateInfoForCaller(false, Binder.getCallingUid())); + } + } + } + return new ParceledListSlice<>(result); } @Override diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 6cd66c642a06..5b1c0fdb8249 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -38,7 +38,6 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser.SigningDetails; import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; -import android.content.pm.ParceledListSlice; import android.content.pm.parsing.PackageInfoWithoutStateUtils; import android.content.rollback.IRollbackManager; import android.content.rollback.RollbackInfo; @@ -180,20 +179,6 @@ public class StagingManager { } } - ParceledListSlice<PackageInstaller.SessionInfo> getSessions(int callingUid) { - final List<PackageInstaller.SessionInfo> result = new ArrayList<>(); - synchronized (mStagedSessions) { - for (int i = 0; i < mStagedSessions.size(); i++) { - final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i); - if (stagedSession.isDestroyed()) { - continue; - } - result.add(stagedSession.generateInfoForCaller(false /*icon*/, callingUid)); - } - } - return new ParceledListSlice<>(result); - } - /** * Validates the signature used to sign the container of the new apex package * diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index b3e162d473db..8868a6c2e6d8 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -396,6 +396,14 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { return false; } + /** + * Returns true if the window has a letterbox and any part of that letterbox overlaps with + * the given {@code rect}. + */ + default boolean isLetterboxedOverlappingWith(Rect rect) { + return false; + } + /** @return the current windowing mode of this window. */ int getWindowingMode(); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 360e40bdf4ff..40e558c09965 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1395,10 +1395,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** - * @see Letterbox#notIntersectsOrFullyContains(Rect) + * @return {@code true} if there is a letterbox and any part of that letterbox overlaps with + * the given {@code rect}. */ - boolean letterboxNotIntersectsOrFullyContains(Rect rect) { - return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect); + boolean isLetterboxOverlappingWith(Rect rect) { + return mLetterbox != null && mLetterbox.isOverlappingWith(rect); } static class Token extends IApplicationToken.Stub { diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java index 26e0790a7604..123fb6c9d8e3 100644 --- a/services/core/java/com/android/server/wm/BarController.java +++ b/services/core/java/com/android/server/wm/BarController.java @@ -175,7 +175,7 @@ public class BarController { } final Rect rotatedContentFrame = win.mToken.getFixedRotationBarContentFrame(mWindowType); final Rect contentFrame = rotatedContentFrame != null ? rotatedContentFrame : mContentFrame; - return win.letterboxNotIntersectsOrFullyContains(contentFrame); + return !win.isLetterboxedOverlappingWith(contentFrame); } boolean setBarShowingLw(final boolean show) { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 33c4e676a03f..5d3f3c0401ef 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3506,12 +3506,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } private boolean isImeControlledByApp() { - return mInputMethodTarget != null && !WindowConfiguration.isSplitScreenWindowingMode( - mInputMethodTarget.getWindowingMode()); + return mInputMethodInputTarget != null && !WindowConfiguration.isSplitScreenWindowingMode( + mInputMethodInputTarget.getWindowingMode()); } boolean isImeAttachedToApp() { return isImeControlledByApp() + && mInputMethodTarget != null && mInputMethodTarget.mActivityRecord != null && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN // An activity with override bounds should be letterboxed inside its parent bounds, diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index 5d1c85dfc7a3..a685886da032 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -77,10 +77,10 @@ public class Letterbox { mOuter.set(outer); mInner.set(inner); - mTop.layout(outer.left, outer.top, outer.right, inner.top, surfaceOrigin); - mLeft.layout(outer.left, outer.top, inner.left, outer.bottom, surfaceOrigin); - mBottom.layout(outer.left, inner.bottom, outer.right, outer.bottom, surfaceOrigin); - mRight.layout(inner.right, outer.top, outer.right, outer.bottom, surfaceOrigin); + mTop.layout(outer.left, outer.top, inner.right, inner.top, surfaceOrigin); + mLeft.layout(outer.left, inner.top, inner.left, outer.bottom, surfaceOrigin); + mBottom.layout(inner.left, inner.bottom, outer.right, outer.bottom, surfaceOrigin); + mRight.layout(inner.right, outer.top, outer.right, inner.bottom, surfaceOrigin); } @@ -101,29 +101,17 @@ public class Letterbox { } /** - * Returns {@code true} if the letterbox does not overlap with the bar, or the letterbox can - * fully cover the window frame. - * - * @param rect The area of the window frame. + * Returns true if any part of the letterbox overlaps with the given {@code rect}. */ - boolean notIntersectsOrFullyContains(Rect rect) { - int emptyCount = 0; - int noOverlappingCount = 0; + public boolean isOverlappingWith(Rect rect) { for (LetterboxSurface surface : mSurfaces) { - final Rect surfaceRect = surface.mLayoutFrameGlobal; - if (surfaceRect.isEmpty()) { - // empty letterbox - emptyCount++; - } else if (!Rect.intersects(surfaceRect, rect)) { - // no overlapping - noOverlappingCount++; - } else if (surfaceRect.contains(rect)) { - // overlapping and covered + if (surface.isOverlappingWith(rect)) { return true; } } - return (emptyCount + noOverlappingCount) == mSurfaces.length; + return false; } + /** * Hides the letterbox. * @@ -298,6 +286,17 @@ public class Letterbox { return Math.max(0, mLayoutFrameGlobal.height()); } + /** + * Returns if the given {@code rect} overlaps with this letterbox piece. + * @param rect the area to check for overlap in global coordinates + */ + public boolean isOverlappingWith(Rect rect) { + if (mLayoutFrameGlobal.isEmpty()) { + return false; + } + return Rect.intersects(rect, mLayoutFrameGlobal); + } + public void applySurfaceChanges(SurfaceControl.Transaction t) { if (mSurfaceFrameRelative.equals(mLayoutFrameRelative)) { // Nothing changed. diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 00be75fddf04..26bcf3b285ec 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3797,12 +3797,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mActivityRecord.getBounds().equals(mTmpRect); } - /** - * @see Letterbox#notIntersectsOrFullyContains(Rect) - */ - boolean letterboxNotIntersectsOrFullyContains(Rect rect) { - return mActivityRecord == null - || mActivityRecord.letterboxNotIntersectsOrFullyContains(rect); + @Override + public boolean isLetterboxedOverlappingWith(Rect rect) { + return mActivityRecord != null && mActivityRecord.isLetterboxOverlappingWith(rect); } boolean isDragResizeChanged() { diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java index 730f303f036a..a462dc309c24 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java @@ -39,6 +39,7 @@ import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.IActivityManager; import android.app.job.JobInfo; +import android.app.job.JobScheduler; import android.app.usage.UsageStatsManagerInternal; import android.content.ComponentName; import android.content.Context; @@ -56,6 +57,7 @@ import android.os.SystemClock; import com.android.server.AppStateTracker; import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; +import com.android.server.SystemServiceManager; import com.android.server.job.controllers.JobStatus; import com.android.server.usage.AppStandbyInternal; @@ -82,6 +84,7 @@ public class JobSchedulerServiceTest { private class TestJobSchedulerService extends JobSchedulerService { TestJobSchedulerService(Context context) { super(context); + mAppStateTracker = mock(AppStateTracker.class); } @Override @@ -136,6 +139,9 @@ public class JobSchedulerServiceTest { } catch (RemoteException e) { fail("registerUidObserver threw exception: " + e.getMessage()); } + // Called by QuotaTracker + doReturn(mock(SystemServiceManager.class)) + .when(() -> LocalServices.getService(SystemServiceManager.class)); JobSchedulerService.sSystemClock = Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC); JobSchedulerService.sElapsedRealtimeClock = @@ -750,4 +756,90 @@ public class JobSchedulerServiceTest { maybeQueueFunctor.postProcess(); assertEquals(3, mService.mPendingJobs.size()); } + + /** Tests that jobs scheduled by the app itself are counted towards scheduling limits. */ + @Test + public void testScheduleLimiting_RegularSchedule_Blocked() { + mService.mConstants.ENABLE_API_QUOTAS = true; + mService.mConstants.API_QUOTA_SCHEDULE_COUNT = 300; + mService.mConstants.API_QUOTA_SCHEDULE_WINDOW_MS = 300000; + mService.mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION = false; + mService.mConstants.API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = true; + mService.updateQuotaTracker(); + + final JobInfo job = createJobInfo().setPersisted(true).build(); + for (int i = 0; i < 500; ++i) { + final int expected = + i < 300 ? JobScheduler.RESULT_SUCCESS : JobScheduler.RESULT_FAILURE; + assertEquals("Got unexpected result for schedule #" + (i + 1), + expected, + mService.scheduleAsPackage(job, null, 10123, null, 0, "")); + } + } + + /** + * Tests that jobs scheduled by the app itself succeed even if the app is above the scheduling + * limit. + */ + @Test + public void testScheduleLimiting_RegularSchedule_Allowed() { + mService.mConstants.ENABLE_API_QUOTAS = true; + mService.mConstants.API_QUOTA_SCHEDULE_COUNT = 300; + mService.mConstants.API_QUOTA_SCHEDULE_WINDOW_MS = 300000; + mService.mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION = false; + mService.mConstants.API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = false; + mService.updateQuotaTracker(); + + final JobInfo job = createJobInfo().setPersisted(true).build(); + for (int i = 0; i < 500; ++i) { + assertEquals("Got unexpected result for schedule #" + (i + 1), + JobScheduler.RESULT_SUCCESS, + mService.scheduleAsPackage(job, null, 10123, null, 0, "")); + } + } + + /** + * Tests that jobs scheduled through a proxy (eg. system server) don't count towards scheduling + * limits. + */ + @Test + public void testScheduleLimiting_Proxy() { + mService.mConstants.ENABLE_API_QUOTAS = true; + mService.mConstants.API_QUOTA_SCHEDULE_COUNT = 300; + mService.mConstants.API_QUOTA_SCHEDULE_WINDOW_MS = 300000; + mService.mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION = false; + mService.mConstants.API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = true; + mService.updateQuotaTracker(); + + final JobInfo job = createJobInfo().setPersisted(true).build(); + for (int i = 0; i < 500; ++i) { + assertEquals("Got unexpected result for schedule #" + (i + 1), + JobScheduler.RESULT_SUCCESS, + mService.scheduleAsPackage(job, null, 10123, "proxied.package", 0, "")); + } + } + + /** + * Tests that jobs scheduled by an app for itself as if through a proxy are counted towards + * scheduling limits. + */ + @Test + public void testScheduleLimiting_SelfProxy() { + mService.mConstants.ENABLE_API_QUOTAS = true; + mService.mConstants.API_QUOTA_SCHEDULE_COUNT = 300; + mService.mConstants.API_QUOTA_SCHEDULE_WINDOW_MS = 300000; + mService.mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION = false; + mService.mConstants.API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = true; + mService.updateQuotaTracker(); + + final JobInfo job = createJobInfo().setPersisted(true).build(); + for (int i = 0; i < 500; ++i) { + final int expected = + i < 300 ? JobScheduler.RESULT_SUCCESS : JobScheduler.RESULT_FAILURE; + assertEquals("Got unexpected result for schedule #" + (i + 1), + expected, + mService.scheduleAsPackage(job, null, 10123, job.getService().getPackageName(), + 0, "")); + } + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 5b0a7fb9d413..2e49929ec032 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -2088,22 +2088,6 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @Test - public void testShowQSMediaOverrideTrue() { - Global.putInt(getContext().getContentResolver(), - Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1); - mHelper.updateMediaNotificationFilteringEnabled(); // would be called by settings observer - assertTrue(mHelper.isMediaNotificationFilteringEnabled()); - } - - @Test - public void testShowQSMediaOverrideFalse() { - Global.putInt(getContext().getContentResolver(), - Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 0); - mHelper.updateMediaNotificationFilteringEnabled(); // would be called by settings observer - assertFalse(mHelper.isMediaNotificationFilteringEnabled()); - } - - @Test public void testOnLocaleChanged_updatesDefaultChannels() throws Exception { String newLabel = "bananas!"; final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG_N_MR1, diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index d64fdb81107c..94acd776fcb3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -858,6 +858,7 @@ public class DisplayContentTests extends WindowTestsBase { public void testComputeImeParent_app() throws Exception { final DisplayContent dc = createNewDisplay(); dc.mInputMethodTarget = createWindow(null, TYPE_BASE_APPLICATION, "app"); + dc.mInputMethodInputTarget = dc.mInputMethodTarget; assertEquals(dc.mInputMethodTarget.mActivityRecord.getSurfaceControl(), dc.computeImeParent()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java index ce3f270460c1..bf84aecdb6a0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; @@ -55,102 +54,10 @@ public class LetterboxTest { mTransaction = spy(StubTransaction.class); } - private static final int TOP_BAR = 0x1; - private static final int BOTTOM_BAR = 0x2; - private static final int LEFT_BAR = 0x4; - private static final int RIGHT_BAR = 0x8; - @Test - public void testNotIntersectsOrFullyContains_usesGlobalCoordinates() { - final Rect outer = new Rect(0, 0, 10, 50); - final Point surfaceOrig = new Point(1000, 2000); - - final Rect topBar = new Rect(0, 0, 10, 2); - final Rect bottomBar = new Rect(0, 45, 10, 50); - final Rect leftBar = new Rect(0, 0, 2, 50); - final Rect rightBar = new Rect(8, 0, 10, 50); - - final LetterboxLayoutVerifier verifier = - new LetterboxLayoutVerifier(outer, surfaceOrig, mLetterbox); - verifier.setBarRect(topBar, bottomBar, leftBar, rightBar); - - // top - verifier.setInner(0, 2, 10, 50).verifyPositions(TOP_BAR | BOTTOM_BAR, BOTTOM_BAR); - // bottom - verifier.setInner(0, 0, 10, 45).verifyPositions(TOP_BAR | BOTTOM_BAR, TOP_BAR); - // left - verifier.setInner(2, 0, 10, 50).verifyPositions(LEFT_BAR | RIGHT_BAR, RIGHT_BAR); - // right - verifier.setInner(0, 0, 8, 50).verifyPositions(LEFT_BAR | RIGHT_BAR, LEFT_BAR); - // top + bottom - verifier.setInner(0, 2, 10, 45).verifyPositions(TOP_BAR | BOTTOM_BAR, 0); - // left + right - verifier.setInner(2, 0, 8, 50).verifyPositions(LEFT_BAR | RIGHT_BAR, 0); - // top + left - verifier.setInner(2, 2, 10, 50).verifyPositions(TOP_BAR | LEFT_BAR, 0); - // top + left + right - verifier.setInner(2, 2, 8, 50).verifyPositions(TOP_BAR | LEFT_BAR | RIGHT_BAR, 0); - // left + right + bottom - verifier.setInner(2, 0, 8, 45).verifyPositions(LEFT_BAR | RIGHT_BAR | BOTTOM_BAR, 0); - // all - verifier.setInner(2, 2, 8, 45) - .verifyPositions(TOP_BAR | BOTTOM_BAR | LEFT_BAR | RIGHT_BAR, 0); - } - - private static class LetterboxLayoutVerifier { - final Rect mOuter; - final Rect mInner = new Rect(); - final Point mSurfaceOrig; - final Letterbox mLetterbox; - final Rect mTempRect = new Rect(); - - final Rect mTop = new Rect(); - final Rect mBottom = new Rect(); - final Rect mLeft = new Rect(); - final Rect mRight = new Rect(); - - LetterboxLayoutVerifier(Rect outer, Point surfaceOrig, Letterbox letterbox) { - mOuter = new Rect(outer); - mSurfaceOrig = new Point(surfaceOrig); - mLetterbox = letterbox; - } - - LetterboxLayoutVerifier setInner(int left, int top, int right, int bottom) { - mInner.set(left, top, right, bottom); - mLetterbox.layout(mOuter, mInner, mSurfaceOrig); - return this; - } - - void setBarRect(Rect top, Rect bottom, Rect left, Rect right) { - mTop.set(top); - mBottom.set(bottom); - mLeft.set(left); - mRight.set(right); - } - - void verifyPositions(int allowedPos, int noOverlapPos) { - assertEquals(mLetterbox.notIntersectsOrFullyContains(mTop), - (allowedPos & TOP_BAR) != 0); - assertEquals(mLetterbox.notIntersectsOrFullyContains(mBottom), - (allowedPos & BOTTOM_BAR) != 0); - assertEquals(mLetterbox.notIntersectsOrFullyContains(mLeft), - (allowedPos & LEFT_BAR) != 0); - assertEquals(mLetterbox.notIntersectsOrFullyContains(mRight), - (allowedPos & RIGHT_BAR) != 0); - - mTempRect.set(mTop.left, mTop.top, mTop.right, mTop.bottom + 1); - assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect), - (noOverlapPos & TOP_BAR) != 0); - mTempRect.set(mLeft.left, mLeft.top, mLeft.right + 1, mLeft.bottom); - assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect), - (noOverlapPos & LEFT_BAR) != 0); - mTempRect.set(mRight.left - 1, mRight.top, mRight.right, mRight.bottom); - assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect), - (noOverlapPos & RIGHT_BAR) != 0); - mTempRect.set(mBottom.left, mBottom.top - 1, mBottom.right, mBottom.bottom); - assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect), - (noOverlapPos & BOTTOM_BAR) != 0); - } + public void testOverlappingWith_usesGlobalCoordinates() { + mLetterbox.layout(new Rect(0, 0, 10, 50), new Rect(0, 2, 10, 45), new Point(1000, 2000)); + assertTrue(mLetterbox.isOverlappingWith(new Rect(0, 0, 1, 1))); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 3c98272311f7..a979c862a8e4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -269,6 +269,8 @@ public class SizeCompatTests extends ActivityTestsBase { rotateDisplay(mActivity.mDisplayContent, ROTATION_90); mActivity.mDisplayContent.mInputMethodTarget = addWindowToActivity(mActivity); + mActivity.mDisplayContent.mInputMethodInputTarget = + mActivity.mDisplayContent.mInputMethodTarget; // Because the aspect ratio of display doesn't exceed the max aspect ratio of activity. // The activity should still fill its parent container and IME can attach to the activity. assertTrue(mActivity.matchParentBounds()); |