diff options
39 files changed, 774 insertions, 461 deletions
diff --git a/api/current.txt b/api/current.txt index 298914566676..f43ce6dc8f3f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3892,6 +3892,7 @@ package android.app { public class ActivityOptions { method public android.graphics.Rect getLaunchBounds(); + method public int getLaunchDisplayId(); method public static android.app.ActivityOptions makeBasic(); method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int); method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int); @@ -3902,6 +3903,7 @@ package android.app { method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int); method public void requestUsageTimeReport(android.app.PendingIntent); method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect); + method public android.app.ActivityOptions setLaunchDisplayId(int); method public android.os.Bundle toBundle(); method public void update(android.app.ActivityOptions); field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time"; diff --git a/api/system-current.txt b/api/system-current.txt index ab5acf5dafab..f8132044d2ae 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4024,6 +4024,7 @@ package android.app { public class ActivityOptions { method public android.graphics.Rect getLaunchBounds(); + method public int getLaunchDisplayId(); method public static android.app.ActivityOptions makeBasic(); method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int); method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int); @@ -4034,6 +4035,7 @@ package android.app { method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int); method public void requestUsageTimeReport(android.app.PendingIntent); method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect); + method public android.app.ActivityOptions setLaunchDisplayId(int); method public android.os.Bundle toBundle(); method public void update(android.app.ActivityOptions); field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time"; diff --git a/api/test-current.txt b/api/test-current.txt index 76af8c583608..da025ffff1fe 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -3901,6 +3901,7 @@ package android.app { public class ActivityOptions { method public android.graphics.Rect getLaunchBounds(); + method public int getLaunchDisplayId(); method public static android.app.ActivityOptions makeBasic(); method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int); method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int); @@ -3911,6 +3912,7 @@ package android.app { method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int); method public void requestUsageTimeReport(android.app.PendingIntent); method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect); + method public android.app.ActivityOptions setLaunchDisplayId(int); method public void setLaunchStackId(int); method public android.os.Bundle toBundle(); method public void update(android.app.ActivityOptions); diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index d9a46903ee38..1e7f4f04582d 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -18,6 +18,7 @@ package android.app; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.view.Display.INVALID_DISPLAY; import android.annotation.Nullable; import android.annotation.TestApi; @@ -152,6 +153,12 @@ public class ActivityOptions { private static final String KEY_ANIM_SPECS = "android:activity.animSpecs"; /** + * The display id the activity should be launched into. + * @hide + */ + private static final String KEY_LAUNCH_DISPLAY_ID = "android.activity.launchDisplayId"; + + /** * The stack id the activity should be launched into. * @hide */ @@ -240,6 +247,7 @@ public class ActivityOptions { private int mResultCode; private int mExitCoordinatorIndex; private PendingIntent mUsageTimeReport; + private int mLaunchDisplayId = INVALID_DISPLAY; private int mLaunchStackId = INVALID_STACK_ID; private int mLaunchTaskId = -1; private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; @@ -850,6 +858,7 @@ public class ActivityOptions { mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX); break; } + mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY); mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID); mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1); mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false); @@ -1015,6 +1024,25 @@ public class ActivityOptions { } } + /** + * Gets the id of the display where activity should be launched. + * @return The id of the display where activity should be launched, + * {@link android.view.Display#INVALID_DISPLAY} if not set. + */ + public int getLaunchDisplayId() { + return mLaunchDisplayId; + } + + /** + * Sets the id of the display where activity should be launched. + * @param launchDisplayId The id of the display where the activity should be launched. + * @return {@code this} {@link ActivityOptions} instance. + */ + public ActivityOptions setLaunchDisplayId(int launchDisplayId) { + mLaunchDisplayId = launchDisplayId; + return this; + } + /** @hide */ public int getLaunchStackId() { return mLaunchStackId; @@ -1209,6 +1237,7 @@ public class ActivityOptions { b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex); break; } + b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId); b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId); b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId); b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 79ace08e1ef2..1aa13a9348a9 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -5242,7 +5242,14 @@ public final class ActivityThread { } updateDefaultDensity(); - final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24)); + final String use24HourSetting = mCoreSettings.getString(Settings.System.TIME_12_24); + Boolean is24Hr = null; + if (use24HourSetting != null) { + is24Hr = "24".equals(use24HourSetting) ? Boolean.TRUE : Boolean.FALSE; + } + // null : use locale default for 12/24 hour formatting, + // false : use 12 hour format, + // true : use 24 hour format. DateFormat.set24HourTimePref(is24Hr); View.mDebugViewAttributes = diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index 6b16e8f61e14..e222fee6e409 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -764,7 +764,7 @@ final class BackStackRecord extends FragmentTransaction implements } if (!mAllowOptimization) { // Added fragments are added at the end to comply with prior behavior. - mManager.moveToState(mManager.mCurState); + mManager.moveToState(mManager.mCurState, true); } } @@ -810,7 +810,7 @@ final class BackStackRecord extends FragmentTransaction implements } } if (!mAllowOptimization) { - mManager.moveToState(mManager.mCurState); + mManager.moveToState(mManager.mCurState, true); } } diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 5a2c5e771807..07ef136e7ac5 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -1445,11 +1445,24 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } } - void moveToState(int newState) { + /** + * Changes the state of the fragment manager to {@code newState}. If the fragment manager + * changes state or {@code always} is {@code true}, any fragments within it have their + * states updated as well. + * + * @param newState The new state for the fragment manager + * @param always If {@code true}, all fragments update their state, even + * if {@code newState} matches the current fragment manager's state. + */ + void moveToState(int newState, boolean always) { if (mHost == null && newState != Fragment.INITIALIZING) { throw new IllegalStateException("No activity"); } + if (!always && mCurState == newState) { + return; + } + mCurState = newState; if (mActive != null) { @@ -2024,7 +2037,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate // need to run something now FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, postponeIndex, true); - moveToState(mCurState); + moveToState(mCurState, true); } for (int recordNum = startIndex; recordNum < endIndex; recordNum++) { @@ -2117,7 +2130,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate FragmentTransition.startTransitions(this, records, isRecordPop, 0, 1, true); } if (moveToState) { - moveToState(mCurState); + moveToState(mCurState, true); } else if (mActive != null) { final int numActive = mActive.size(); for (int i = 0; i < numActive; i++) { @@ -2691,40 +2704,40 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate public void dispatchCreate() { mStateSaved = false; - moveToState(Fragment.CREATED); + moveToState(Fragment.CREATED, false); } public void dispatchActivityCreated() { mStateSaved = false; - moveToState(Fragment.ACTIVITY_CREATED); + moveToState(Fragment.ACTIVITY_CREATED, false); } public void dispatchStart() { mStateSaved = false; - moveToState(Fragment.STARTED); + moveToState(Fragment.STARTED, false); } public void dispatchResume() { mStateSaved = false; - moveToState(Fragment.RESUMED); + moveToState(Fragment.RESUMED, false); } public void dispatchPause() { - moveToState(Fragment.STARTED); + moveToState(Fragment.STARTED, false); } public void dispatchStop() { - moveToState(Fragment.STOPPED); + moveToState(Fragment.STOPPED, false); } public void dispatchDestroyView() { - moveToState(Fragment.CREATED); + moveToState(Fragment.CREATED, false); } public void dispatchDestroy() { mDestroyed = true; execPendingActions(); - moveToState(Fragment.INITIALIZING); + moveToState(Fragment.INITIALIZING, false); mHost = null; mContainer = null; mParent = null; diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index cbd5a6d54832..d89d2bb93f08 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -357,33 +357,40 @@ public class DeviceAdminReceiver extends BroadcastReceiver { public static final int BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE = 1; /** @hide */ - public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS"; + public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = + "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS"; /** @hide */ - public static final String EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID = "android.app.extra.CHOOSE_PRIVATE_KEY_SENDER_UID"; + public static final String EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID = + "android.app.extra.CHOOSE_PRIVATE_KEY_SENDER_UID"; /** @hide */ - public static final String EXTRA_CHOOSE_PRIVATE_KEY_URI = "android.app.extra.CHOOSE_PRIVATE_KEY_URI"; + public static final String EXTRA_CHOOSE_PRIVATE_KEY_URI = + "android.app.extra.CHOOSE_PRIVATE_KEY_URI"; /** @hide */ - public static final String EXTRA_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.extra.CHOOSE_PRIVATE_KEY_ALIAS"; + public static final String EXTRA_CHOOSE_PRIVATE_KEY_ALIAS = + "android.app.extra.CHOOSE_PRIVATE_KEY_ALIAS"; /** @hide */ - public static final String EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE = "android.app.extra.CHOOSE_PRIVATE_KEY_RESPONSE"; + public static final String EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE = + "android.app.extra.CHOOSE_PRIVATE_KEY_RESPONSE"; /** * Broadcast action: notify device owner that there is a pending system update. * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_NOTIFY_PENDING_SYSTEM_UPDATE = "android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE"; + public static final String ACTION_NOTIFY_PENDING_SYSTEM_UPDATE = + "android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE"; /** * A long type extra for {@link #onSystemUpdatePending} recording the system time as given by * {@link System#currentTimeMillis()} when the current pending system update is first available. * @hide */ - public static final String EXTRA_SYSTEM_UPDATE_RECEIVED_TIME = "android.app.extra.SYSTEM_UPDATE_RECEIVED_TIME"; + public static final String EXTRA_SYSTEM_UPDATE_RECEIVED_TIME = + "android.app.extra.SYSTEM_UPDATE_RECEIVED_TIME"; /** * Name under which a DevicePolicy component publishes information diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 18ce260e7136..a9268d4e3dd9 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -404,6 +404,7 @@ public class RemoteViews implements Parcelable, Filter { // Because pruning can remove the need for bitmaps, we reconstruct the bitmap cache mBitmapCache = new BitmapCache(); setBitmapCache(mBitmapCache); + recalculateMemoryUsage(); } private class SetEmptyView extends Action { @@ -2117,26 +2118,8 @@ public class RemoteViews implements Parcelable, Filter { return mMemoryUsage; } - @SuppressWarnings("deprecation") public void addBitmapMemory(Bitmap b) { - final Bitmap.Config c = b.getConfig(); - // If we don't know, be pessimistic and assume 4 - int bpp = 4; - if (c != null) { - switch (c) { - case ALPHA_8: - bpp = 1; - break; - case RGB_565: - case ARGB_4444: - bpp = 2; - break; - case ARGB_8888: - bpp = 4; - break; - } - } - increment(b.getWidth() * b.getHeight() * bpp); + increment(b.getAllocationByteCount()); } int mMemoryUsage; diff --git a/core/java/com/android/internal/util/ToBooleanFunction.java b/core/java/com/android/internal/util/ToBooleanFunction.java new file mode 100644 index 000000000000..83866c22976f --- /dev/null +++ b/core/java/com/android/internal/util/ToBooleanFunction.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.internal.util; + +import java.util.function.Function; + +/** + * Represents a function that produces an boolean-valued result. This is the + * {@code boolean}-producing primitive specialization for {@link Function}. + * + * <p>This is a <a href="package-summary.html">functional interface</a> + * whose functional method is {@link #apply(Object)}. + * + * @param <T> the type of the input to the function + * + * @see Function + * @since 1.8 + */ +@FunctionalInterface +public interface ToBooleanFunction<T> { + + /** + * Applies this function to the given argument. + * + * @param value the function argument + * @return the function result + */ + boolean apply(T value); +} diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp index f909580b455e..1a67ceebac1c 100644 --- a/core/jni/android_os_HwParcel.cpp +++ b/core/jni/android_os_HwParcel.cpp @@ -425,8 +425,8 @@ static void JHwParcel_native_writeString( status_t err = parcel->writeBuffer(s, sizeof(*s), &parentHandle); if (err == OK) { - err = s->writeEmbeddedToParcel( - parcel, parentHandle, 0 /* parentOffset */); + err = ::android::hardware::writeEmbeddedToParcel( + *s, parcel, parentHandle, 0 /* parentOffset */); } signalExceptionForError(env, err); @@ -453,7 +453,8 @@ static void JHwParcel_native_write ## Suffix ## Vector( \ if (err == OK) { \ size_t childHandle; \ \ - err = vec->writeEmbeddedToParcel( \ + err = ::android::hardware::writeEmbeddedToParcel( \ + *vec, \ parcel, \ parentHandle, \ 0 /* parentOffset */, \ @@ -508,7 +509,8 @@ static void JHwParcel_native_writeBoolVector( if (err == OK) { size_t childHandle; - err = vec->writeEmbeddedToParcel( + err = ::android::hardware::writeEmbeddedToParcel( + *vec, parcel, parentHandle, 0 /* parentOffset */, @@ -568,7 +570,8 @@ static jstring JHwParcel_native_readString(JNIEnv *env, jobject thiz) { return NULL; } - status_t err = const_cast<hidl_string *>(s)->readEmbeddedFromParcel( + status_t err = ::android::hardware::readEmbeddedFromParcel( + const_cast<hidl_string *>(s), *parcel, parentHandle, 0 /* parentOffset */); if (err != OK) { @@ -597,8 +600,8 @@ static Type ## Array JHwParcel_native_read ## Suffix ## Vector( \ \ size_t childHandle; \ \ - status_t err = const_cast<hidl_vec<Type> *>(vec) \ - ->readEmbeddedFromParcel( \ + status_t err = ::android::hardware::readEmbeddedFromParcel( \ + const_cast<hidl_vec<Type> *>(vec), \ *parcel, \ parentHandle, \ 0 /* parentOffset */, \ @@ -639,8 +642,8 @@ static jbooleanArray JHwParcel_native_readBoolVector( size_t childHandle; - status_t err = const_cast<hidl_vec<bool> *>(vec) - ->readEmbeddedFromParcel( + status_t err = ::android::hardware::readEmbeddedFromParcel( + const_cast<hidl_vec<bool> *>(vec), *parcel, parentHandle, 0 /* parentOffset */, @@ -701,12 +704,13 @@ static jobjectArray JHwParcel_native_readStringVector( } size_t childHandle; - status_t err = const_cast<string_vec *>(vec)->readEmbeddedFromParcel( + status_t err = ::android::hardware::readEmbeddedFromParcel( + const_cast<string_vec *>(vec), *parcel, parentHandle, 0 /* parentOffset */, &childHandle); for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) { - err = const_cast<hidl_vec<hidl_string> *>(vec) - ->readEmbeddedFromParcel( + err = android::hardware::readEmbeddedFromParcel( + const_cast<hidl_vec<hidl_string> *>(vec), *parcel, childHandle, i * sizeof(hidl_string), @@ -760,14 +764,16 @@ static void JHwParcel_native_writeStringVector( if (err == OK) { size_t childHandle; - err = vec->writeEmbeddedToParcel( + err = ::android::hardware::writeEmbeddedToParcel( + *vec, parcel, parentHandle, 0 /* parentOffset */, &childHandle); for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) { - err = (*vec)[i].writeEmbeddedToParcel( + err = ::android::hardware::writeEmbeddedToParcel( + (*vec)[i], parcel, childHandle, i * sizeof(hidl_string)); diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp index 17437318470d..b9376d8c6e66 100644 --- a/core/jni/android_view_GraphicBuffer.cpp +++ b/core/jni/android_view_GraphicBuffer.cpp @@ -111,7 +111,7 @@ static jlong android_view_GraphiceBuffer_create(JNIEnv* env, jobject clazz, } status_t error; - sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, usage, &error)); + sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, 1, usage, &error)); if (buffer == NULL) { if (kDebugGraphicBuffer) { ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()"); diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 79c63ee306af..e628cf8af89d 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -1241,6 +1241,11 @@ public final class Bitmap implements Parcelable { * #getAllocationByteCount()}.</p> */ public final int getByteCount() { + if (mRecycled) { + Log.w(TAG, "Called getByteCount() on a recycle()'d bitmap! " + + "This is undefined behavior!"); + return 0; + } // int result permits bitmaps up to 46,340 x 46,340 return getRowBytes() * getHeight(); } @@ -1260,6 +1265,11 @@ public final class Bitmap implements Parcelable { * @see #reconfigure(int, int, Config) */ public final int getAllocationByteCount() { + if (mRecycled) { + Log.w(TAG, "Called getAllocationByteCount() on a recycle()'d bitmap! " + + "This is undefined behavior!"); + return 0; + } return nativeGetAllocationByteCount(mNativePtr); } diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index b8f7d9f01697..2077b0ec87f9 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -227,7 +227,7 @@ sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(uirenderer::renderthread::RenderThr PixelFormat pixelFormat = internalFormatToPixelFormat(internalFormat); status_t error; sp<GraphicBuffer> buffer = alloc->createGraphicBuffer(info.width(), info.height(), pixelFormat, - GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER + 1, GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | GraphicBuffer::USAGE_SW_READ_NEVER , &error); if (!buffer.get()) { diff --git a/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java b/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java index 43cc1d6bfe39..d95af61a27c1 100644 --- a/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java +++ b/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java @@ -530,7 +530,8 @@ public class PlatformAdapter { private int addSP(String xml) throws IOException, SAXException { WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); - return wifiManager.addPasspointManagementObject(xml); + // TODO(b/32883320): use the new API for adding Passpoint configuration. + return 0; } private int modifySP(HomeSP homeSP, Collection<MOData> mods) throws IOException { @@ -540,7 +541,8 @@ public class PlatformAdapter { defMods.add(new PasspointManagementObjectDefinition(mod.getBaseURI(), mod.getURN(), mod.getMOTree().toXml())); } - return wifiManager.modifyPasspointManagementObject(homeSP.getFQDN(), defMods); + // TODO(b/32883320): use the new API to update Passpoint configuration. + return 0; } private void reconnect(Network osuNetwork, int newNwkId) { diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java index ed411be9c3e4..14a0e820a69a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java @@ -18,6 +18,7 @@ package com.android.settingslib.drawer; import android.content.ComponentName; import android.content.Context; import android.support.annotation.VisibleForTesting; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; @@ -25,12 +26,15 @@ import android.util.Pair; import com.android.settingslib.applications.InterestingConfigChanges; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import static java.lang.String.CASE_INSENSITIVE_ORDER; + public class CategoryManager { private static final String TAG = "CategoryManager"; @@ -111,6 +115,7 @@ public class CategoryManager { mCategoryByKeyMap.put(category.key, category); } backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap); + normalizePriority(context, mCategoryByKeyMap); } } @@ -163,4 +168,57 @@ public class CategoryManager { } } } + + /** + * Normalize priority values on tiles across injected from all apps to make sure they don't set + * the same priority value. However internal tiles' priority remains unchanged. + * <p/> + * A list of tiles are considered normalized when their priority value increases in a linear + * scan. + */ + @VisibleForTesting + synchronized void normalizePriority(Context context, + Map<String, DashboardCategory> categoryByKeyMap) { + for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) { + normalizePriorityForExternalTiles(context, categoryEntry.getValue()); + } + } + + /** + * Normalize priority value for tiles within a single {@code DashboardCategory}. + * + * @see #normalizePriority(Context, Map) + */ + private synchronized void normalizePriorityForExternalTiles(Context context, + DashboardCategory dashboardCategory) { + final String skipPackageName = context.getPackageName(); + + // Sort tiles based on [package, priority within package] + Collections.sort(dashboardCategory.tiles, (tile1, tile2) -> { + final String package1 = tile1.intent.getComponent().getPackageName(); + final String package2 = tile2.intent.getComponent().getPackageName(); + final int packageCompare = CASE_INSENSITIVE_ORDER.compare(package1, package2); + // First sort by package name + if (packageCompare != 0) { + return packageCompare; + } else if (TextUtils.equals(package1, skipPackageName)) { + return 0; + } + // Then sort by priority + return tile1.priority - tile2.priority; + }); + // Update priority for all items so no package define the same priority value. + final int count = dashboardCategory.tiles.size(); + for (int i = 0; i < count; i++) { + final String packageName = + dashboardCategory.tiles.get(i).intent.getComponent().getPackageName(); + if (TextUtils.equals(packageName, skipPackageName)) { + // We skip this tile because it's a intent pointing to our own app. We trust the + // priority is set correctly, so don't normalize. + continue; + } + dashboardCategory.tiles.get(i).priority = i; + + } + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java index 380f6226512a..50bb216c9d39 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java @@ -16,7 +16,9 @@ package com.android.settingslib.drawer; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.util.Pair; import com.android.settingslib.TestConfig; @@ -116,4 +118,114 @@ public class CategoryManagerTest { // Old category still exists. assertThat(mCategoryByKeyMap.get(oldCategory).tiles.size()).isEqualTo(1); } + + @Test + public void normalizePriority_singlePackage_shouldReorderBasedOnPriority() { + // Create some fake tiles that are not sorted. + final String testPackage = "com.android.test"; + final DashboardCategory category = new DashboardCategory(); + final Tile tile1 = new Tile(); + tile1.intent = + new Intent().setComponent(new ComponentName(testPackage, "class1")); + tile1.priority = 100; + final Tile tile2 = new Tile(); + tile2.intent = + new Intent().setComponent(new ComponentName(testPackage, "class2")); + tile2.priority = 50; + final Tile tile3 = new Tile(); + tile3.intent = + new Intent().setComponent(new ComponentName(testPackage, "class3")); + tile3.priority = 200; + category.tiles.add(tile1); + category.tiles.add(tile2); + category.tiles.add(tile3); + mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category); + + // Normalize their priorities + mCategoryManager.normalizePriority(ShadowApplication.getInstance().getApplicationContext(), + mCategoryByKeyMap); + + // Verify they are now sorted. + assertThat(category.tiles.get(0)).isSameAs(tile2); + assertThat(category.tiles.get(1)).isSameAs(tile1); + assertThat(category.tiles.get(2)).isSameAs(tile3); + // Verify their priority is normalized + assertThat(category.tiles.get(0).priority).isEqualTo(0); + assertThat(category.tiles.get(1).priority).isEqualTo(1); + assertThat(category.tiles.get(2).priority).isEqualTo(2); + } + + @Test + public void normalizePriority_multiPackage_shouldReorderBasedOnPackageAndPriority() { + // Create some fake tiles that are not sorted. + final String testPackage1 = "com.android.test1"; + final String testPackage2 = "com.android.test2"; + final DashboardCategory category = new DashboardCategory(); + final Tile tile1 = new Tile(); + tile1.intent = + new Intent().setComponent(new ComponentName(testPackage2, "class1")); + tile1.priority = 100; + final Tile tile2 = new Tile(); + tile2.intent = + new Intent().setComponent(new ComponentName(testPackage1, "class2")); + tile2.priority = 100; + final Tile tile3 = new Tile(); + tile3.intent = + new Intent().setComponent(new ComponentName(testPackage1, "class3")); + tile3.priority = 50; + category.tiles.add(tile1); + category.tiles.add(tile2); + category.tiles.add(tile3); + mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category); + + // Normalize their priorities + mCategoryManager.normalizePriority(ShadowApplication.getInstance().getApplicationContext(), + mCategoryByKeyMap); + + // Verify they are now sorted. + assertThat(category.tiles.get(0)).isSameAs(tile3); + assertThat(category.tiles.get(1)).isSameAs(tile2); + assertThat(category.tiles.get(2)).isSameAs(tile1); + // Verify their priority is normalized + assertThat(category.tiles.get(0).priority).isEqualTo(0); + assertThat(category.tiles.get(1).priority).isEqualTo(1); + assertThat(category.tiles.get(2).priority).isEqualTo(2); + } + + @Test + public void normalizePriority_internalPackageTiles_shouldSkipTileForInternalPackage() { + // Create some fake tiles that are not sorted. + final String testPackage = + ShadowApplication.getInstance().getApplicationContext().getPackageName(); + final DashboardCategory category = new DashboardCategory(); + final Tile tile1 = new Tile(); + tile1.intent = + new Intent().setComponent(new ComponentName(testPackage, "class1")); + tile1.priority = 100; + final Tile tile2 = new Tile(); + tile2.intent = + new Intent().setComponent(new ComponentName(testPackage, "class2")); + tile2.priority = 100; + final Tile tile3 = new Tile(); + tile3.intent = + new Intent().setComponent(new ComponentName(testPackage, "class3")); + tile3.priority = 50; + category.tiles.add(tile1); + category.tiles.add(tile2); + category.tiles.add(tile3); + mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category); + + // Normalize their priorities + mCategoryManager.normalizePriority(ShadowApplication.getInstance().getApplicationContext(), + mCategoryByKeyMap); + + // Verify the sorting order is not changed + assertThat(category.tiles.get(0)).isSameAs(tile1); + assertThat(category.tiles.get(1)).isSameAs(tile2); + assertThat(category.tiles.get(2)).isSameAs(tile3); + // Verify their priorities are not changed. + assertThat(category.tiles.get(0).priority).isEqualTo(100); + assertThat(category.tiles.get(1).priority).isEqualTo(100); + assertThat(category.tiles.get(2).priority).isEqualTo(50); + } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java index 8ca277ecdcfd..42b06b2b52c9 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java @@ -797,7 +797,7 @@ public class VolumeDialog implements TunerService.Tunable { // update slider final boolean enableSlider = !zenMuted; - final int vlevel = row.ss.muted && (isRingVibrate || !isRingStream && !zenMuted) ? 0 + final int vlevel = row.ss.muted && (!isRingStream && !zenMuted) ? 0 : row.ss.level; updateVolumeRowSliderH(row, enableSlider, vlevel); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java index 87f6138da15d..12a00e9fe854 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java @@ -552,8 +552,9 @@ public class ZenModePanel extends LinearLayout { setToMidnight(nextAlarm); if (weekRange.compareTo(nextAlarm) >= 0) { - return ZenModeConfig.toNextAlarmCondition(mContext, now, - nextAlarmMs, ActivityManager.getCurrentUser()); + return ZenModeConfig.toTimeCondition(mContext, nextAlarmMs, + Math.round((nextAlarmMs - now) / (float) MINUTES_MS), + ActivityManager.getCurrentUser(), true); } } return null; diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 5cf74c7fe69a..9b4b1868cdbb 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -22,6 +22,27 @@ package com_android_internal_logging; // Wrapper for System UI log events message MetricsEvent { + // Types of events + enum Type { + // Unknown + TYPE_UNKNOWN = 0; + + // The view became visible to the user. + TYPE_OPEN = 1; + + // The view became hidden. + TYPE_CLOSE = 2; + + // The view switched to detail mode (most relevant for quick settings tiles) + TYPE_DETAIL = 3; + + // The view or control was activated. + TYPE_ACTION = 4; + + // The view or control was dismissed. + TYPE_DISMISS = 5; + } + // Known visual elements: views or controls. enum View { // Unknown view diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index bf60e4711c3b..6404604ca097 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -1593,14 +1593,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // Make sure the package runs under the caller uid. mSecurityPolicy.enforceCallFromPackage(callingPackage); - - final int bitmapMemoryUsage = (views != null) ? views.estimateMemoryUsage() : 0; - if (bitmapMemoryUsage > mMaxWidgetBitmapMemory) { - throw new IllegalArgumentException("RemoteViews for widget update exceeds" - + " maximum bitmap memory usage (used: " + bitmapMemoryUsage - + ", max: " + mMaxWidgetBitmapMemory + ")"); - } - synchronized (mLock) { ensureGroupStateLoadedLocked(userId); @@ -1812,6 +1804,15 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // For a full update we replace the RemoteViews completely. widget.views = views; } + int memoryUsage; + if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) && + (widget.views != null) && + ((memoryUsage = widget.views.estimateMemoryUsage()) > mMaxWidgetBitmapMemory)) { + widget.views = null; + throw new IllegalArgumentException("RemoteViews for widget update exceeds" + + " maximum bitmap memory usage (used: " + memoryUsage + + ", max: " + mMaxWidgetBitmapMemory + ")"); + } scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked()); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 52ad72d819fe..14b843a8f638 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -80,6 +80,7 @@ import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; import static android.app.ActivityManager.RESIZE_MODE_USER; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.view.Display.INVALID_DISPLAY; final class ActivityManagerShellCommand extends ShellCommand { public static final String NO_CLASS_ERROR_CODE = "Error type 3"; @@ -114,6 +115,7 @@ final class ActivityManagerShellCommand extends ShellCommand { private String mProfileFile; private int mSamplingInterval; private boolean mAutoStop; + private int mDisplayId; private int mStackId; final boolean mDumping; @@ -249,6 +251,7 @@ final class ActivityManagerShellCommand extends ShellCommand { mSamplingInterval = 0; mAutoStop = false; mUserId = defUser; + mDisplayId = INVALID_DISPLAY; mStackId = INVALID_STACK_ID; return Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() { @@ -278,6 +281,8 @@ final class ActivityManagerShellCommand extends ShellCommand { mUserId = UserHandle.parseUserArg(getNextArgRequired()); } else if (opt.equals("--receiver-permission")) { mReceiverPermission = getNextArgRequired(); + } else if (opt.equals("--display")) { + mDisplayId = Integer.parseInt(getNextArgRequired()); } else if (opt.equals("--stack")) { mStackId = Integer.parseInt(getNextArgRequired()); } else { @@ -354,6 +359,10 @@ final class ActivityManagerShellCommand extends ShellCommand { int res; final long startTime = SystemClock.uptimeMillis(); ActivityOptions options = null; + if (mDisplayId != INVALID_DISPLAY) { + options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(mDisplayId); + } if (mStackId != INVALID_STACK_ID) { options = ActivityOptions.makeBasic(); options.setLaunchStackId(mStackId); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 282ec5052e4f..539ac1620961 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -38,6 +38,8 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.FLAG_PRIVATE; +import static android.view.Display.INVALID_DISPLAY; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS; @@ -90,6 +92,7 @@ import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED; import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS; import android.Manifest; +import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; @@ -1483,16 +1486,35 @@ public class ActivityStackSupervisor extends ConfigurationContainer Slog.w(TAG, message); return false; } - if (options != null && options.getLaunchTaskId() != -1) { - final int startInTaskPerm = mService.checkPermission(START_TASKS_FROM_RECENTS, - callingPid, callingUid); - if (startInTaskPerm != PERMISSION_GRANTED) { - final String msg = "Permission Denial: starting " + intent.toString() - + " from " + callerApp + " (pid=" + callingPid - + ", uid=" + callingUid + ") with launchTaskId=" - + options.getLaunchTaskId(); - Slog.w(TAG, msg); - throw new SecurityException(msg); + if (options != null) { + if (options.getLaunchTaskId() != INVALID_STACK_ID) { + final int startInTaskPerm = mService.checkPermission(START_TASKS_FROM_RECENTS, + callingPid, callingUid); + if (startInTaskPerm != PERMISSION_GRANTED) { + final String msg = "Permission Denial: starting " + intent.toString() + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ") with launchTaskId=" + + options.getLaunchTaskId(); + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + } + // Check if someone tries to launch an activity on a private display with a different + // owner. + final int launchDisplayId = options.getLaunchDisplayId(); + if (launchDisplayId != INVALID_DISPLAY) { + final ActivityDisplay activityDisplay = mActivityDisplays.get(launchDisplayId); + if (activityDisplay != null + && (activityDisplay.mDisplay.getFlags() & FLAG_PRIVATE) != 0) { + if (activityDisplay.mDisplay.getOwnerUid() != callingUid) { + final String msg = "Permission Denial: starting " + intent.toString() + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ") with launchDisplayId=" + + launchDisplayId; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + } } } @@ -1937,7 +1959,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer } ActivityStack getStack(int stackId, boolean createStaticStackIfNeeded, boolean createOnTop) { - ActivityContainer activityContainer = mActivityContainers.get(stackId); + final ActivityContainer activityContainer = mActivityContainers.get(stackId); if (activityContainer != null) { return activityContainer.mStack; } @@ -1948,6 +1970,40 @@ public class ActivityStackSupervisor extends ConfigurationContainer return createStackOnDisplay(stackId, DEFAULT_DISPLAY, createOnTop); } + /** + * Get a topmost stack on the display, that is a valid launch stack for specified activity. + * If there is no such stack, new dynamic stack can be created. + * @param displayId Target display. + * @param r Activity that should be launched there. + * @return Existing stack if there is a valid one, new dynamic stack if it is valid or null. + */ + ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r) { + final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); + if (activityDisplay == null) { + throw new IllegalArgumentException( + "Display with displayId=" + displayId + " not found."); + } + + // Return the topmost valid stack on the display. + for (int i = activityDisplay.mStacks.size() - 1; i >= 0; --i) { + final ActivityStack stack = activityDisplay.mStacks.get(i); + if (mService.mActivityStarter.isValidLaunchStackId(stack.mStackId, r)) { + return stack; + } + } + + // If there is no valid stack on the external display - check if new dynamic stack will do. + if (displayId != Display.DEFAULT_DISPLAY) { + final int newDynamicStackId = getNextStackId(); + if (mService.mActivityStarter.isValidLaunchStackId(newDynamicStackId, r)) { + return createStackOnDisplay(newDynamicStackId, displayId, true /*onTop*/); + } + } + + Slog.w(TAG, "getValidLaunchStackOnDisplay: can't launch on displayId " + displayId); + return null; + } + ArrayList<ActivityStack> getStacks() { ArrayList<ActivityStack> allStacks = new ArrayList<>(); for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { @@ -2326,11 +2382,15 @@ public class ActivityStackSupervisor extends ConfigurationContainer * Restores a recent task to a stack * @param task The recent task to be restored. * @param stackId The stack to restore the task to (default launch stack will be used - * if stackId is {@link android.app.ActivityManager.StackId#INVALID_STACK_ID}). + * if stackId is {@link android.app.ActivityManager.StackId#INVALID_STACK_ID} + * or is not a static stack). * @return true if the task has been restored successfully. */ private boolean restoreRecentTaskLocked(TaskRecord task, int stackId) { - if (stackId == INVALID_STACK_ID) { + if (!StackId.isStaticStack(stackId)) { + // If stack is not static (or stack id is invalid) - use the default one. + // This means that tasks that were on external displays will be restored on the + // primary display. stackId = task.getLaunchStackId(); } else if (stackId == DOCKED_STACK_ID && !task.canGoInDockedStack()) { // Preferred stack is the docked stack, but the task can't go in the docked stack. @@ -3504,7 +3564,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer if (activityDisplay != null) { ArrayList<ActivityStack> stacks = activityDisplay.mStacks; for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - stacks.get(stackNdx).mActivityContainer.removeLocked(); + final ActivityStack stack = stacks.get(stackNdx); + // TODO: Implement proper stack removal and ability to choose the behavior - + // remove stack completely or move it to other display. + moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY); } mActivityDisplays.remove(displayId); } @@ -4155,7 +4218,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer } } - /** Remove the stack completely. */ + /** + * Remove the stack completely. Must be called only when there are no tasks left in it, + * as this method does not finish running activities. + */ void removeLocked() { if (DEBUG_STACK) Slog.d(TAG_STACK, "removeLocked: " + this + " from display=" + mActivityDisplay + " Callers=" + Debug.getCallers(2)); diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 691d6b9cd628..709c3d0dba5e 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -31,6 +31,7 @@ import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.app.ActivityManager.StackId.isStaticStack; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; @@ -50,6 +51,8 @@ import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; +import static android.view.Display.INVALID_DISPLAY; + import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; @@ -254,11 +257,7 @@ class ActivityStarter { if (err == ActivityManager.START_SUCCESS) { Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false) - + "} from uid " + callingUid - + " on display " + (container == null ? (mSupervisor.mFocusedStack == null ? - Display.DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId) : - (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY : - container.mActivityDisplay.mDisplayId))); + + "} from uid " + callingUid); } ActivityRecord sourceRecord = null; @@ -1952,12 +1951,14 @@ class ActivityStarter { // The fullscreen stack can contain any task regardless of if the task is resizeable // or not. So, we let the task go in the fullscreen task if it is the focus stack. + // Same also applies to dynamic stacks, as they behave similar to fullscreen stack. // If the freeform or docked stack has focus, and the activity to be launched is resizeable, // we can also put it in the focused stack. final int focusedStackId = mSupervisor.mFocusedStack.mStackId; final boolean canUseFocusedStack = focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID || (focusedStackId == DOCKED_STACK_ID && r.canGoInDockedStack()) - || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeableOrForced()); + || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeableOrForced()) + || !isStaticStack(focusedStackId); if (canUseFocusedStack && (!newTask || mSupervisor.mFocusedStack.mActivityContainer.isEligibleForNewTasks())) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, @@ -1965,7 +1966,7 @@ class ActivityStarter { return mSupervisor.mFocusedStack; } - // We first try to put the task in the first dynamic stack. + // We first try to put the task in the first dynamic stack on home display. final ArrayList<ActivityStack> homeDisplayStacks = mSupervisor.mHomeStack.mStacks; for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) { stack = homeDisplayStacks.get(stackNdx); @@ -1994,16 +1995,29 @@ class ActivityStarter { return mReuseTask.getStack(); } + final int launchDisplayId = + (aOptions != null) ? aOptions.getLaunchDisplayId() : INVALID_DISPLAY; + final int launchStackId = (aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID; + if (launchStackId != INVALID_STACK_ID && launchDisplayId != INVALID_DISPLAY) { + throw new IllegalArgumentException( + "Stack and display id can't be set at the same time."); + } + if (isValidLaunchStackId(launchStackId, r)) { return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP); - } else if (launchStackId == DOCKED_STACK_ID) { + } + if (launchStackId == DOCKED_STACK_ID) { // The preferred launch stack is the docked stack, but it isn't a valid launch stack // for this activity, so we put the activity in the fullscreen stack. return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP); } + if (launchDisplayId != INVALID_DISPLAY) { + // Stack id has higher priority than display id. + return mSupervisor.getValidLaunchStackOnDisplay(launchDisplayId, r); + } if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) { return null; @@ -2047,9 +2061,8 @@ class ActivityStarter { } } - private boolean isValidLaunchStackId(int stackId, ActivityRecord r) { - if (stackId == INVALID_STACK_ID || stackId == HOME_STACK_ID - || !StackId.isStaticStack(stackId)) { + boolean isValidLaunchStackId(int stackId, ActivityRecord r) { + if (stackId == INVALID_STACK_ID || stackId == HOME_STACK_ID) { return false; } diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java index 6d97796d3d3e..0a7454f31669 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java @@ -36,6 +36,7 @@ import android.webkit.WebViewProviderResponse; import com.android.server.SystemService; import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.Arrays; /** @@ -259,5 +260,18 @@ public class WebViewUpdateService extends SystemService { Binder.restoreCallingIdentity(callingId); } } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + + pw.println("Permission Denial: can't dump webviewupdate service from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); + return; + } + + WebViewUpdateService.this.mImpl.dumpState(pw); + } } } diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java index 453e7458b19c..1a77c68d83d2 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java @@ -30,6 +30,7 @@ import android.webkit.WebViewFactory; import android.webkit.WebViewProviderInfo; import android.webkit.WebViewProviderResponse; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -673,6 +674,27 @@ public class WebViewUpdateServiceImpl { mMinimumVersionCode = minimumVersionCode; return mMinimumVersionCode; } + + public void dumpState(PrintWriter pw) { + synchronized (mLock) { + if (mCurrentWebViewPackage == null) { + pw.println(" Current WebView package is null"); + } else { + pw.println(String.format(" Current WebView package (name, version): (%s, %s)", + mCurrentWebViewPackage.packageName, + mCurrentWebViewPackage.versionName)); + } + pw.println(String.format(" Minimum WebView version code: %d", + mMinimumVersionCode)); + pw.println(String.format(" Number of relros started: %d", + mNumRelroCreationsStarted)); + pw.println(String.format(" Number of relros finished: %d", + mNumRelroCreationsFinished)); + pw.println(String.format(" WebView package dirty: %b", mWebViewPackageDirty)); + pw.println(String.format(" Any WebView package installed: %b", + mAnyWebViewInstalled)); + } + } } private static boolean providerHasValidSignature(WebViewProviderInfo provider, @@ -741,4 +763,14 @@ public class WebViewUpdateServiceImpl { mSystemInterface.setMultiProcessEnabledFromContext(mContext); } } + + /** + * Dump the state of this Service. + */ + void dumpState(PrintWriter pw) { + pw.println("Current WebView Update Service state"); + pw.println(String.format(" Fallback logic enabled: %b", + mSystemInterface.isFallbackLogicEnabled())); + mWebViewUpdater.dumpState(pw); + } } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 05e6f96b1b0c..0844d48b8669 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -47,6 +47,7 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE import static com.android.server.wm.WindowManagerService.logWithStack; import android.os.Debug; +import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputApplicationHandle; import com.android.server.wm.WindowManagerService.H; @@ -66,7 +67,7 @@ import android.view.animation.Animation; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.function.Consumer; +import java.util.function.Function; class AppTokenList extends ArrayList<AppWindowToken> { } @@ -1270,19 +1271,20 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } @Override - void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) { + boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) { // For legacy reasons we process the TaskStack.mExitingAppTokens first in DisplayContent // before the non-exiting app tokens. So, we skip the exiting app tokens here. // TODO: Investigate if we need to continue to do this or if we can just process them // in-order. if (mIsExiting && !waitingForReplacement()) { - return; + return false; } - forAllWindowsUnchecked(callback, traverseTopToBottom); + return forAllWindowsUnchecked(callback, traverseTopToBottom); } - void forAllWindowsUnchecked(Consumer<WindowState> callback, boolean traverseTopToBottom) { - super.forAllWindows(callback, traverseTopToBottom); + boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback, + boolean traverseTopToBottom) { + return super.forAllWindows(callback, traverseTopToBottom); } @Override diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index ff39853833da..e73acde65a3d 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -127,6 +127,7 @@ import android.view.SurfaceControl; import android.view.WindowManagerPolicy; import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.ToBooleanFunction; import com.android.internal.view.IInputMethodClient; import com.android.server.input.InputWindowHandle; @@ -141,6 +142,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.function.Consumer; +import java.util.function.Function; /** * Utility class for keeping track of the WindowStates and other pertinent contents of a @@ -725,7 +727,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo win.getTouchableRegion(mTmpRegion); mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION); } - if (getDockedStackLocked() != null) { + // TODO(multi-display): Support docked stacks on secondary displays. + if (mDisplayId == DEFAULT_DISPLAY && getDockedStackLocked() != null) { mDividerControllerLocked.getTouchRegion(mTmpRect); mTmpRegion.set(mTmpRect); mTouchExcludeRegion.op(mTmpRegion, Op.UNION); @@ -1407,9 +1410,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } void adjustWallpaperWindows() { - if (mWallpaperController.adjustWallpaperWindows(mWindows)) { - assignWindowLayers(true /*setLayoutNeeded*/); - } + mWallpaperController.adjustWallpaperWindows(this); } /** @@ -3235,17 +3236,27 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } @Override - void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) { + boolean forAllWindows(ToBooleanFunction<WindowState> callback, + boolean traverseTopToBottom) { if (traverseTopToBottom) { - super.forAllWindows(callback, traverseTopToBottom); - forAllExitingAppTokenWindows(callback, traverseTopToBottom); + if (super.forAllWindows(callback, traverseTopToBottom)) { + return true; + } + if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) { + return true; + } } else { - forAllExitingAppTokenWindows(callback, traverseTopToBottom); - super.forAllWindows(callback, traverseTopToBottom); + if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) { + return true; + } + if (super.forAllWindows(callback, traverseTopToBottom)) { + return true; + } } + return false; } - private void forAllExitingAppTokenWindows(Consumer<WindowState> callback, + private boolean forAllExitingAppTokenWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) { // For legacy reasons we process the TaskStack.mExitingAppTokens first here before the // app tokens. @@ -3255,7 +3266,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo for (int i = mChildren.size() - 1; i >= 0; --i) { final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens; for (int j = appTokens.size() - 1; j >= 0; --j) { - appTokens.get(j).forAllWindowsUnchecked(callback, traverseTopToBottom); + if (appTokens.get(j).forAllWindowsUnchecked(callback, + traverseTopToBottom)) { + return true; + } } } } else { @@ -3264,10 +3278,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens; final int appTokensCount = appTokens.size(); for (int j = 0; j < appTokensCount; j++) { - appTokens.get(j).forAllWindowsUnchecked(callback, traverseTopToBottom); + if (appTokens.get(j).forAllWindowsUnchecked(callback, + traverseTopToBottom)) { + return true; + } } } } + return false; } @Override diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 4d195e838bf7..40b737df6680 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -271,8 +271,9 @@ class DragState { Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")"); } - mDisplayContent.forAllWindows((w) -> sendDragStartedLw(w, touchX, touchY, mDataDescription), - false /* traverseTopToBottom */ ); + mDisplayContent.forAllWindows(w -> { + sendDragStartedLw(w, touchX, touchY, mDataDescription); + }, false /* traverseTopToBottom */ ); } /* helper - send a ACTION_DRAG_STARTED event, if the diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index d3e8e8eba880..8dbf2b3e019f 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -17,9 +17,9 @@ package com.android.server.wm; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; @@ -30,8 +30,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIG import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT; -import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER; -import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET; import android.os.Bundle; import android.os.Debug; @@ -61,11 +59,8 @@ class WallpaperController { // with the wallpaper. private WindowState mWallpaperTarget = null; // If non-null, we are in the middle of animating from one wallpaper target - // to another, and this is the lower one in Z-order. - private WindowState mLowerWallpaperTarget = null; - // If non-null, we are in the middle of animating from one wallpaper target - // to another, and this is the higher one in Z-order. - private WindowState mUpperWallpaperTarget = null; + // to another, and this is the previous wallpaper target. + private WindowState mPrevWallpaperTarget = null; private int mWallpaperAnimLayerAdjustment; @@ -78,7 +73,7 @@ class WallpaperController { // This is set when we are waiting for a wallpaper to tell us it is done // changing its scroll position. - WindowState mWaitingOnWallpaper; + private WindowState mWaitingOnWallpaper; // The last time we had a timeout when waiting for a wallpaper. private long mLastWallpaperTimeoutTime; @@ -110,14 +105,6 @@ class WallpaperController { return mWallpaperTarget; } - WindowState getLowerWallpaperTarget() { - return mLowerWallpaperTarget; - } - - WindowState getUpperWallpaperTarget() { - return mUpperWallpaperTarget; - } - boolean isWallpaperTarget(WindowState win) { return win == mWallpaperTarget; } @@ -145,13 +132,11 @@ class WallpaperController { + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??") + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null) ? wallpaperTarget.mAppToken.mAppAnimator.animation : null) - + " upper=" + mUpperWallpaperTarget - + " lower=" + mLowerWallpaperTarget); + + " prev=" + mPrevWallpaperTarget); return (wallpaperTarget != null && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null && wallpaperTarget.mAppToken.mAppAnimator.animation != null))) - || mUpperWallpaperTarget != null - || mLowerWallpaperTarget != null; + || mPrevWallpaperTarget != null; } boolean isWallpaperTargetAnimating() { @@ -177,7 +162,7 @@ class WallpaperController { void hideWallpapers(final WindowState winGoingAway) { if (mWallpaperTarget != null - && (mWallpaperTarget != winGoingAway || mLowerWallpaperTarget != null)) { + && (mWallpaperTarget != winGoingAway || mPrevWallpaperTarget != null)) { return; } if (mService.mAppTransition.isRunning()) { @@ -192,8 +177,8 @@ class WallpaperController { final WallpaperWindowToken token = mWallpaperTokens.get(i); token.hideWallpaperToken(wasDeferred, "hideWallpapers"); if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token - + " from " + winGoingAway + " target=" + mWallpaperTarget + " lower=" - + mLowerWallpaperTarget + "\n" + Debug.getCallers(5, " ")); + + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev=" + + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, " ")); } } @@ -299,9 +284,7 @@ class WallpaperController { Bundle sendWindowWallpaperCommand( WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) { - if (window == mWallpaperTarget - || window == mLowerWallpaperTarget - || window == mUpperWallpaperTarget) { + if (window == mWallpaperTarget || window == mPrevWallpaperTarget) { boolean doWait = sync; for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); @@ -388,51 +371,52 @@ class WallpaperController { return mWallpaperAnimLayerAdjustment; } - private void findWallpaperTarget(WindowList windows, FindWallpaperTargetResult result) { + private void findWallpaperTarget(DisplayContent dc , FindWallpaperTargetResult result) { final WindowAnimator winAnimator = mService.mAnimator; result.reset(); - WindowState w = null; - int windowDetachedI = -1; - boolean resetTopWallpaper = false; - boolean inFreeformSpace = false; - boolean replacing = false; - boolean keyguardGoingAwayWithWallpaper = false; - boolean needsShowWhenLockedWallpaper = false; + if (mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) { + // In freeform mode we set the wallpaper as its own target, so we don't need an + // additional window to make it visible. + result.setUseTopWallpaperAsTarget(true); + } - for (int i = windows.size() - 1; i >= 0; i--) { - w = windows.get(i); + dc.forAllWindows(w -> { if ((w.mAttrs.type == TYPE_WALLPAPER)) { - if (result.topWallpaper == null || resetTopWallpaper) { - result.setTopWallpaper(w, i); - resetTopWallpaper = false; + if (result.topWallpaper == null || result.resetTopWallpaper) { + result.setTopWallpaper(w); + result.resetTopWallpaper = false; } - continue; + return false; } - resetTopWallpaper = true; + + result.resetTopWallpaper = true; if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) { // If this window's app token is hidden and not animating, // it is of no interest to us. if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) { if (DEBUG_WALLPAPER) Slog.v(TAG, "Skipping hidden and not animating token: " + w); - continue; + return false; } } - if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": isOnScreen=" - + w.isOnScreen() + " mDrawState=" + w.mWinAnimator.mDrawState); - - if (!inFreeformSpace) { - TaskStack stack = w.getStack(); - inFreeformSpace = stack != null && stack.mStackId == FREEFORM_WORKSPACE_STACK_ID; + if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen() + + " mDrawState=" + w.mWinAnimator.mDrawState); + + if (w.mWillReplaceWindow && mWallpaperTarget == null + && !result.useTopWallpaperAsTarget) { + // When we are replacing a window and there was wallpaper before replacement, we + // want to keep the window until the new windows fully appear and can determine the + // visibility, to avoid flickering. + result.setUseTopWallpaperAsTarget(true); } - replacing |= w.mWillReplaceWindow; - keyguardGoingAwayWithWallpaper |= (w.mAppToken != null + final boolean keyguardGoingAwayWithWallpaper = (w.mAppToken != null && AppTransition.isKeyguardGoingAwayTransit( w.mAppToken.mAppAnimator.getTransit()) && (w.mAppToken.mAppAnimator.getTransitFlags() & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0); + boolean needsShowWhenLockedWallpaper = false; if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && mService.mPolicy.isKeyguardLocked() && mService.mPolicy.isKeyguardOccluded()) { @@ -442,248 +426,147 @@ class WallpaperController { || (w.mAppToken != null && !w.mAppToken.fillsParent()); } + if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) { + // Keep the wallpaper during Keyguard exit but also when it's needed for a + // non-fullscreen show when locked activity. + result.setUseTopWallpaperAsTarget(true); + } + final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0; if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) { - if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: #" + i + "=" + w); - result.setWallpaperTarget(w, i); + if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w); + result.setWallpaperTarget(w); if (w == mWallpaperTarget && w.mWinAnimator.isAnimationSet()) { // The current wallpaper target is animating, so we'll look behind it for // another possible target and figure out what is going on later. if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": token animating, looking behind."); - continue; } - break; + // Found a target! End search. + return true; } else if (w == winAnimator.mWindowDetachedWallpaper) { - windowDetachedI = i; + if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, + "Found animating detached wallpaper target win: " + w); + result.setUseTopWallpaperAsTarget(true); } - } - - if (result.wallpaperTarget != null) { - return; - } - - if (windowDetachedI >= 0) { - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, - "Found animating detached wallpaper activity: #" + windowDetachedI + "=" + w); - result.setWallpaperTarget(w, windowDetachedI); - } else if (inFreeformSpace || (replacing && mWallpaperTarget != null)) { - // In freeform mode we set the wallpaper as its own target, so we don't need an - // additional window to make it visible. When we are replacing a window and there was - // wallpaper before replacement, we want to keep the window until the new windows fully - // appear and can determine the visibility, to avoid flickering. - result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex); + return false; + }, true /* traverseTopToBottom */); - } else if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) { - // Keep the wallpaper during Keyguard exit but also when it's needed for a - // non-fullscreen show when locked activity. - result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex); + if (result.wallpaperTarget == null && result.useTopWallpaperAsTarget) { + result.setWallpaperTarget(result.topWallpaper); } } private boolean isFullscreen(WindowManager.LayoutParams attrs) { return attrs.x == 0 && attrs.y == 0 - && attrs.width == WindowManager.LayoutParams.MATCH_PARENT - && attrs.height == WindowManager.LayoutParams.MATCH_PARENT; + && attrs.width == MATCH_PARENT && attrs.height == MATCH_PARENT; } /** Updates the target wallpaper if needed and returns true if an update happened. */ - private boolean updateWallpaperWindowsTarget( - WindowList windows, FindWallpaperTargetResult result) { + private void updateWallpaperWindowsTarget(DisplayContent dc, + FindWallpaperTargetResult result) { WindowState wallpaperTarget = result.wallpaperTarget; - int wallpaperTargetIndex = result.wallpaperTargetIndex; if (mWallpaperTarget == wallpaperTarget - || (mLowerWallpaperTarget != null && mLowerWallpaperTarget == wallpaperTarget)) { - - if (mLowerWallpaperTarget != null) { - // Is it time to stop animating? - if (!mLowerWallpaperTarget.isAnimatingLw() - || !mUpperWallpaperTarget.isAnimatingLw()) { - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, - "No longer animating wallpaper targets!"); - mLowerWallpaperTarget = null; - mUpperWallpaperTarget = null; - mWallpaperTarget = wallpaperTarget; - return true; - } + || (mPrevWallpaperTarget != null && mPrevWallpaperTarget == wallpaperTarget)) { + + if (mPrevWallpaperTarget == null) { + return; } - return false; + // Is it time to stop animating? + if (!mPrevWallpaperTarget.isAnimatingLw()) { + if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!"); + mPrevWallpaperTarget = null; + mWallpaperTarget = wallpaperTarget; + } + return; } if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, - "New wallpaper target: " + wallpaperTarget + " oldTarget: " + mWallpaperTarget); + "New wallpaper target: " + wallpaperTarget + " prevTarget: " + mWallpaperTarget); - mLowerWallpaperTarget = null; - mUpperWallpaperTarget = null; + mPrevWallpaperTarget = null; - WindowState oldW = mWallpaperTarget; + final WindowState prevWallpaperTarget = mWallpaperTarget; mWallpaperTarget = wallpaperTarget; - if (wallpaperTarget == null || oldW == null) { - return true; + if (wallpaperTarget == null || prevWallpaperTarget == null) { + return; } // Now what is happening... if the current and new targets are animating, // then we are in our super special mode! - boolean oldAnim = oldW.isAnimatingLw(); + boolean oldAnim = prevWallpaperTarget.isAnimatingLw(); boolean foundAnim = wallpaperTarget.isAnimatingLw(); if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "New animation: " + foundAnim + " old animation: " + oldAnim); if (!foundAnim || !oldAnim) { - return true; + return; } - int oldI = windows.indexOf(oldW); - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, - "New i: " + wallpaperTargetIndex + " old i: " + oldI); - - if (oldI < 0) { - return true; + if (dc.getWindow(w -> w == prevWallpaperTarget) == null) { + return; } final boolean newTargetHidden = wallpaperTarget.mAppToken != null && wallpaperTarget.mAppToken.hiddenRequested; - final boolean oldTargetHidden = oldW.mAppToken != null - && oldW.mAppToken.hiddenRequested; - - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old#" + oldI + "=" - + oldW + " hidden=" + oldTargetHidden + " new#" + wallpaperTargetIndex + "=" - + wallpaperTarget + " hidden=" + newTargetHidden); - - // Set the upper and lower wallpaper targets correctly, - // and make sure that we are positioning the wallpaper below the lower. - if (wallpaperTargetIndex > oldI) { - // The new target is on top of the old one. - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Found target above old target."); - mUpperWallpaperTarget = wallpaperTarget; - mLowerWallpaperTarget = oldW; - - wallpaperTarget = oldW; - wallpaperTargetIndex = oldI; - } else { - // The new target is below the old one. - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Found target below old target."); - mUpperWallpaperTarget = oldW; - mLowerWallpaperTarget = wallpaperTarget; - } + final boolean oldTargetHidden = prevWallpaperTarget.mAppToken != null + && prevWallpaperTarget.mAppToken.hiddenRequested; + + if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old: " + + prevWallpaperTarget + " hidden=" + oldTargetHidden + " new: " + wallpaperTarget + + " hidden=" + newTargetHidden); + + mPrevWallpaperTarget = prevWallpaperTarget; if (newTargetHidden && !oldTargetHidden) { if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Old wallpaper still the target."); // Use the old target if new target is hidden but old target // is not. If they're both hidden, still use the new target. - mWallpaperTarget = oldW; + mWallpaperTarget = prevWallpaperTarget; } else if (newTargetHidden == oldTargetHidden && !mService.mOpeningApps.contains(wallpaperTarget.mAppToken) - && (mService.mOpeningApps.contains(oldW.mAppToken) - || mService.mClosingApps.contains(oldW.mAppToken))) { + && (mService.mOpeningApps.contains(prevWallpaperTarget.mAppToken) + || mService.mClosingApps.contains(prevWallpaperTarget.mAppToken))) { // If they're both hidden (or both not hidden), prefer the one that's currently in // opening or closing app list, this allows transition selection logic to better // determine the wallpaper status of opening/closing apps. - mWallpaperTarget = oldW; - } - - result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex); - return true; - } - - private boolean updateWallpaperWindowsTargetByLayer(WindowList windows, - FindWallpaperTargetResult result) { - - WindowState wallpaperTarget = result.wallpaperTarget; - int wallpaperTargetIndex = result.wallpaperTargetIndex; - boolean visible = wallpaperTarget != null; - - if (visible) { - // The window is visible to the compositor...but is it visible to the user? - // That is what the wallpaper cares about. - visible = isWallpaperVisible(wallpaperTarget); - if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible); - - // If the wallpaper target is animating, we may need to copy its layer adjustment. - // Only do this if we are not transferring between two wallpaper targets. - mWallpaperAnimLayerAdjustment = - (mLowerWallpaperTarget == null && wallpaperTarget.mAppToken != null) - ? wallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0; - - final int maxLayer = (mService.mPolicy.getMaxWallpaperLayer() * TYPE_LAYER_MULTIPLIER) - + TYPE_LAYER_OFFSET; - - // Now w is the window we are supposed to be behind... but we - // need to be sure to also be behind any of its attached windows, - // AND any starting window associated with it, AND below the - // maximum layer the policy allows for wallpapers. - while (wallpaperTargetIndex > 0) { - final WindowState wb = windows.get(wallpaperTargetIndex - 1); - final WindowState wbParentWindow = wb.getParentWindow(); - final WindowState wallpaperParentWindow = wallpaperTarget.getParentWindow(); - if (wb.mBaseLayer < maxLayer - && wbParentWindow != wallpaperTarget - && (wallpaperParentWindow == null || wbParentWindow != wallpaperParentWindow) - && (wb.mAttrs.type != TYPE_APPLICATION_STARTING - || wallpaperTarget.mToken == null - || wb.mToken != wallpaperTarget.mToken)) { - // This window is not related to the previous one in any - // interesting way, so stop here. - break; - } - wallpaperTarget = wb; - wallpaperTargetIndex--; - } - } else { - if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target"); + mWallpaperTarget = prevWallpaperTarget; } - result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex); - return visible; + result.setWallpaperTarget(wallpaperTarget); } - private boolean updateWallpaperWindowsPlacement(WindowList windows, - WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible) { - - // TODO(multidisplay): Wallpapers on main screen only. - final DisplayInfo displayInfo = mService.getDefaultDisplayContentLocked().getDisplayInfo(); - final int dw = displayInfo.logicalWidth; - final int dh = displayInfo.logicalHeight; - - // Start stepping backwards from here, ensuring that our wallpaper windows are correctly placed. - boolean changed = false; + private void updateWallpaperTokens(boolean visible) { for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); - changed |= token.updateWallpaperWindowsPlacement(windows, wallpaperTarget, - wallpaperTargetIndex, visible, dw, dh, mWallpaperAnimLayerAdjustment); + token.updateWallpaperWindows(visible, mWallpaperAnimLayerAdjustment); } - - return changed; } - boolean adjustWallpaperWindows(WindowList windows) { + void adjustWallpaperWindows(DisplayContent dc) { mService.mRoot.mWallpaperMayChange = false; // First find top-most window that has asked to be on top of the wallpaper; // all wallpapers go behind it. - findWallpaperTarget(windows, mFindResults); - final boolean targetChanged = updateWallpaperWindowsTarget(windows, mFindResults); - final boolean visible = updateWallpaperWindowsTargetByLayer(windows, mFindResults); - WindowState wallpaperTarget = mFindResults.wallpaperTarget; - int wallpaperTargetIndex = mFindResults.wallpaperTargetIndex; - - if (wallpaperTarget == null && mFindResults.topWallpaper != null) { - // There is no wallpaper target, so it goes at the bottom. - // We will assume it is the same place as last time, if known. - wallpaperTarget = mFindResults.topWallpaper; - wallpaperTargetIndex = mFindResults.topWallpaperIndex + 1; - } else { - // Okay i is the position immediately above the wallpaper. - // Look at what is below it for later. - wallpaperTarget = wallpaperTargetIndex > 0 - ? windows.get(wallpaperTargetIndex - 1) : null; - } + findWallpaperTarget(dc, mFindResults); + updateWallpaperWindowsTarget(dc, mFindResults); + + // The window is visible to the compositor...but is it visible to the user? + // That is what the wallpaper cares about. + final boolean visible = mWallpaperTarget != null && isWallpaperVisible(mWallpaperTarget); + if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible); if (visible) { + // If the wallpaper target is animating, we may need to copy its layer adjustment. + // Only do this if we are not transferring between two wallpaper targets. + mWallpaperAnimLayerAdjustment = + (mPrevWallpaperTarget == null && mWallpaperTarget.mAppToken != null) + ? mWallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0; + if (mWallpaperTarget.mWallpaperX >= 0) { mLastWallpaperX = mWallpaperTarget.mWallpaperX; mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep; @@ -700,14 +583,10 @@ class WallpaperController { } } - final boolean changed = updateWallpaperWindowsPlacement( - windows, wallpaperTarget, wallpaperTargetIndex, visible); - - if (targetChanged && DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target=" - + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper=" - + mUpperWallpaperTarget); + updateWallpaperTokens(visible); - return changed; + if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget + + " prev=" + mPrevWallpaperTarget); } boolean processWallpaperDrawPendingTimeout() { @@ -773,7 +652,7 @@ class WallpaperController { } if (adjust) { - dc.adjustWallpaperWindows(); + adjustWallpaperWindows(dc); } } @@ -787,9 +666,8 @@ class WallpaperController { void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget); - if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) { - pw.print(prefix); pw.print("mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget); - pw.print(prefix); pw.print("mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget); + if (mPrevWallpaperTarget != null) { + pw.print(prefix); pw.print("mPrevWallpaperTarget="); pw.println(mPrevWallpaperTarget); } pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX); pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY); @@ -825,26 +703,28 @@ class WallpaperController { /** Helper class for storing the results of a wallpaper target find operation. */ final private static class FindWallpaperTargetResult { - int topWallpaperIndex = 0; WindowState topWallpaper = null; - int wallpaperTargetIndex = 0; + boolean useTopWallpaperAsTarget = false; WindowState wallpaperTarget = null; + boolean resetTopWallpaper = false; - void setTopWallpaper(WindowState win, int index) { + void setTopWallpaper(WindowState win) { topWallpaper = win; - topWallpaperIndex = index; } - void setWallpaperTarget(WindowState win, int index) { + void setWallpaperTarget(WindowState win) { wallpaperTarget = win; - wallpaperTargetIndex = index; + } + + void setUseTopWallpaperAsTarget(boolean topWallpaperAsTarget) { + useTopWallpaperAsTarget = topWallpaperAsTarget; } void reset() { - topWallpaperIndex = 0; topWallpaper = null; - wallpaperTargetIndex = 0; wallpaperTarget = null; + useTopWallpaperAsTarget = false; + resetTopWallpaper = false; } } } diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index 3a76cd4d1bde..8ea1b3b1355a 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -119,11 +119,8 @@ class WallpaperWindowToken extends WindowToken { } } - boolean updateWallpaperWindowsPlacement(WindowList windowList, - WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible, int dw, int dh, - int wallpaperAnimLayerAdj) { + void updateWallpaperWindows(boolean visible, int animLayerAdj) { - boolean changed = false; if (hidden == visible) { if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "Wallpaper token " + token + " hidden=" + !visible); @@ -132,6 +129,9 @@ class WallpaperWindowToken extends WindowToken { mDisplayContent.setLayoutNeeded(); } + final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); + final int dw = displayInfo.logicalWidth; + final int dh = displayInfo.logicalHeight; final WallpaperController wallpaperController = mDisplayContent.mWallpaperController; for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { final WindowState wallpaper = mChildren.get(wallpaperNdx); @@ -142,66 +142,11 @@ class WallpaperWindowToken extends WindowToken { // First, make sure the client has the current visibility state. wallpaper.dispatchWallpaperVisibility(visible); - wallpaper.adjustAnimLayer(wallpaperAnimLayerAdj); + wallpaper.adjustAnimLayer(animLayerAdj); if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win " + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); - - // First, if this window is at the current index, then all is well. - if (wallpaper == wallpaperTarget) { - wallpaperTargetIndex--; - wallpaperTarget = wallpaperTargetIndex > 0 - ? windowList.get(wallpaperTargetIndex - 1) : null; - continue; - } - - // The window didn't match... the current wallpaper window, - // wherever it is, is in the wrong place, so make sure it is not in the list. - int oldIndex = windowList.indexOf(wallpaper); - if (oldIndex >= 0) { - if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, - "Wallpaper removing at " + oldIndex + ": " + wallpaper); - mDisplayContent.removeFromWindowList(wallpaper); - if (oldIndex < wallpaperTargetIndex) { - wallpaperTargetIndex--; - } - } - - // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost - // layer. For keyguard over wallpaper put the wallpaper under the lowest window that - // is currently on screen, i.e. not hidden by policy. - int insertionIndex = 0; - if (visible && wallpaperTarget != null) { - final int privateFlags = wallpaperTarget.mAttrs.privateFlags; - if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { - insertionIndex = Math.min(windowList.indexOf(wallpaperTarget), - findLowestWindowOnScreen(windowList)); - } - } - if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT - || (DEBUG_ADD_REMOVE && oldIndex != insertionIndex)) Slog.v(TAG, - "Moving wallpaper " + wallpaper + " from " + oldIndex + " to " + insertionIndex); - - mDisplayContent.addToWindowList(wallpaper, insertionIndex); - changed = true; - } - - return changed; - } - - /** - * @return The index in {@param windows} of the lowest window that is currently on screen and - * not hidden by the policy. - */ - private int findLowestWindowOnScreen(WindowList windowList) { - final int size = windowList.size(); - for (int index = 0; index < size; index++) { - final WindowState win = windowList.get(index); - if (win.isOnScreen()) { - return index; - } } - return Integer.MAX_VALUE; } boolean hasVisibleNotDrawnWallpaper() { diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 150160c3302e..a6a907cd50fb 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -19,10 +19,12 @@ package com.android.server.wm; import android.annotation.CallSuper; import android.content.res.Configuration; import android.view.animation.Animation; +import com.android.internal.util.ToBooleanFunction; import java.util.Comparator; import java.util.LinkedList; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; @@ -496,17 +498,38 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon return addIndex; } - void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) { + /** + * For all windows at or below this container call the callback. + * @param callback Calls the {@link ToBooleanFunction#apply} method for each window found and + * stops the search if {@link ToBooleanFunction#apply} returns true. + * @param traverseTopToBottom If true traverses the hierarchy from top-to-bottom in terms of + * z-order, else from bottom-to-top. + * @return True if the search ended before we reached the end of the hierarchy due to + * {@link Function#apply} returning true. + */ + boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) { if (traverseTopToBottom) { for (int i = mChildren.size() - 1; i >= 0; --i) { - mChildren.get(i).forAllWindows(callback, traverseTopToBottom); + if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) { + return true; + } } } else { final int count = mChildren.size(); for (int i = 0; i < count; i++) { - mChildren.get(i).forAllWindows(callback, traverseTopToBottom); + if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) { + return true; + } } } + return false; + } + + void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) { + forAllWindows(w -> { + callback.accept(w); + return false; + }, traverseTopToBottom); } WindowState getWindow(Predicate<WindowState> callback) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 518e55b0fbf7..9648282c00b2 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -4905,9 +4905,9 @@ public class WindowManagerService extends IWindowManager.Stub } if (rotateSeamlessly) { - dc.forAllWindows((w) -> - w.mWinAnimator.seamlesslyRotateWindow(oldRotation, mRotation), - true /* traverseTopToBottom */); + dc.forAllWindows(w -> { + w.mWinAnimator.seamlesslyRotateWindow(oldRotation, mRotation); + }, true /* traverseTopToBottom */); } mDisplayManagerInternal.performTraversalInTransactionFromWindowManager(); @@ -4920,7 +4920,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - dc.forAllWindows((w) -> { + dc.forAllWindows(w -> { // Discard surface after orientation change, these can't be reused. if (w.mAppToken != null) { w.mAppToken.destroySavedSurfaces(); @@ -5183,7 +5183,9 @@ public class WindowManagerService extends IWindowManager.Stub final WindowList windows = new WindowList(); synchronized (mWindowMap) { - mRoot.forAllWindows(windows::add, false /* traverseTopToBottom */); + mRoot.forAllWindows(w -> { + windows.add(w); + }, false /* traverseTopToBottom */); } BufferedWriter out = null; @@ -8260,7 +8262,7 @@ public class WindowManagerService extends IWindowManager.Stub mRoot.dumpChildrenNames(output, " "); pw.println(output.toString()); pw.println(" "); - mRoot.forAllWindows(pw::println, true /* traverseTopToBottom */); + mRoot.forAllWindows(w -> {pw.println(w);}, true /* traverseTopToBottom */); } return; } else { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 5e65aec28c40..c0b3f27fd1ef 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -53,6 +53,7 @@ import android.view.WindowInfo; import android.view.WindowManager; import android.view.WindowManagerPolicy; +import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputWindowHandle; import java.io.PrintWriter; @@ -60,6 +61,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.LinkedList; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import static android.app.ActivityManager.StackId; @@ -3833,21 +3835,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } @Override - void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) { + boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) { if (mChildren.isEmpty()) { // The window has no children so we just return it. - callback.accept(this); - return; + return callback.apply(this); } if (traverseTopToBottom) { - forAllWindowTopToBottom(callback); + return forAllWindowTopToBottom(callback); } else { - forAllWindowBottomToTop(callback); + return forAllWindowBottomToTop(callback); } } - private void forAllWindowBottomToTop(Consumer<WindowState> callback) { + private boolean forAllWindowBottomToTop(ToBooleanFunction<WindowState> callback) { // We want to consumer the negative sublayer children first because they need to appear // below the parent, then this window (the parent), and then the positive sublayer children // because they need to appear above the parent. @@ -3856,7 +3857,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP WindowState child = mChildren.get(i); while (i < count && child.mSubLayer < 0) { - callback.accept(child); + if (callback.apply(child)) { + return true; + } i++; if (i >= count) { break; @@ -3864,19 +3867,25 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP child = mChildren.get(i); } - callback.accept(this); + if (callback.apply(this)) { + return true; + } while (i < count) { - callback.accept(child); + if (callback.apply(child)) { + return true; + } i++; if (i >= count) { break; } child = mChildren.get(i); } + + return false; } - private void forAllWindowTopToBottom(Consumer<WindowState> callback) { + private boolean forAllWindowTopToBottom(ToBooleanFunction<WindowState> callback) { // We want to consumer the positive sublayer children first because they need to appear // above the parent, then this window (the parent), and then the negative sublayer children // because they need to appear above the parent. @@ -3884,7 +3893,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP WindowState child = mChildren.get(i); while (i >= 0 && child.mSubLayer >= 0) { - callback.accept(child); + if (callback.apply(child)) { + return true; + } --i; if (i < 0) { break; @@ -3892,16 +3903,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP child = mChildren.get(i); } - callback.accept(this); + if (callback.apply(this)) { + return true; + } while (i >= 0) { - callback.accept(child); + if (callback.apply(child)) { + return true; + } --i; if (i < 0) { break; } child = mChildren.get(i); } + + return false; } WindowState getWindow(Predicate<WindowState> callback) { diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index f2682baea614..7e1880fb65d6 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -266,21 +266,9 @@ class WindowSurfacePlacer { mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(displayContent, mService.mOpeningApps); - final WindowState lowerWallpaperTarget = - mWallpaperControllerLocked.getLowerWallpaperTarget(); - final WindowState upperWallpaperTarget = - mWallpaperControllerLocked.getUpperWallpaperTarget(); - + final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget(); boolean openingAppHasWallpaper = false; boolean closingAppHasWallpaper = false; - final AppWindowToken lowerWallpaperAppToken; - final AppWindowToken upperWallpaperAppToken; - if (lowerWallpaperTarget == null) { - lowerWallpaperAppToken = upperWallpaperAppToken = null; - } else { - lowerWallpaperAppToken = lowerWallpaperTarget.mAppToken; - upperWallpaperAppToken = upperWallpaperTarget.mAppToken; - } // Do a first pass through the tokens for two things: // (1) Determine if both the closing and opening app token sets are wallpaper targets, in @@ -294,12 +282,12 @@ class WindowSurfacePlacer { final AppWindowToken wtoken; if (i < closingAppsCount) { wtoken = mService.mClosingApps.valueAt(i); - if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) { + if (wallpaperTarget != null && wtoken.windowsCanBeWallpaperTarget()) { closingAppHasWallpaper = true; } } else { wtoken = mService.mOpeningApps.valueAt(i - closingAppsCount); - if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) { + if (wallpaperTarget != null && wtoken.windowsCanBeWallpaperTarget()) { openingAppHasWallpaper = true; } } @@ -307,14 +295,14 @@ class WindowSurfacePlacer { voiceInteraction |= wtoken.voiceInteraction; if (wtoken.fillsParent()) { - WindowState ws = wtoken.findMainWindow(); + final WindowState ws = wtoken.findMainWindow(); if (ws != null) { animLp = ws.mAttrs; bestAnimLayer = ws.mLayer; fullscreenAnim = true; } } else if (!fullscreenAnim) { - WindowState ws = wtoken.findMainWindow(); + final WindowState ws = wtoken.findMainWindow(); if (ws != null) { if (ws.mLayer > bestAnimLayer) { animLp = ws.mAttrs; @@ -325,7 +313,7 @@ class WindowSurfacePlacer { } transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper, - closingAppHasWallpaper, lowerWallpaperTarget, upperWallpaperTarget); + closingAppHasWallpaper); // If all closing windows are obscured, then there is no need to do an animation. This is // the case, for example, when this transition is being done behind the lock screen. @@ -578,8 +566,7 @@ class WindowSurfacePlacer { } private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper, - boolean closingAppHasWallpaper, WindowState lowerWallpaperTarget, - WindowState upperWallpaperTarget) { + boolean closingAppHasWallpaper) { // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget(); final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating() @@ -590,8 +577,6 @@ class WindowSurfacePlacer { if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New wallpaper target=" + wallpaperTarget + ", oldWallpaper=" + oldWallpaper - + ", lower target=" + lowerWallpaperTarget - + ", upper target=" + upperWallpaperTarget + ", openingApps=" + openingApps + ", closingApps=" + closingApps); mService.mAnimateWallpaperWithTarget = false; diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java index 0533efc6d862..225dc5d2d66a 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java @@ -98,7 +98,7 @@ public class DisplayContentTests { final ArrayList<WindowState> windows = new ArrayList(); // Test forward traversal. - dc.forAllWindows(windows::add, false /* traverseTopToBottom */); + dc.forAllWindows(w -> {windows.add(w);}, false /* traverseTopToBottom */); assertEquals(wallpaperWindow, windows.get(0)); assertEquals(exitingAppWindow, windows.get(1)); @@ -112,7 +112,7 @@ public class DisplayContentTests { // Test backward traversal. windows.clear(); - dc.forAllWindows(windows::add, true /* traverseTopToBottom */); + dc.forAllWindows(w -> {windows.add(w);}, true /* traverseTopToBottom */); assertEquals(wallpaperWindow, windows.get(8)); assertEquals(exitingAppWindow, windows.get(7)); diff --git a/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl b/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl index 5b7114982758..2ae424f4af8e 100644 --- a/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl +++ b/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl @@ -89,4 +89,11 @@ interface IPresenceListener */ void listCapInfoReceived(in PresRlmiInfo rlmiInfo, in PresResInfo [] resInfo); + + /** + * Callback function to be invoked to inform the client when Unpublish message + * is sent to network. + */ + void unpublishMessageSent(); + }
\ No newline at end of file diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class Binary files differindex c3630552c7fe..dd7999857f5a 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png Binary files differindex 7b58539f41d8..f274dbfbbdd6 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png |