11a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek/* 21a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * Copyright (C) 2017 The Android Open Source Project 31a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * 41a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * Licensed under the Apache License, Version 2.0 (the "License"); 51a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * you may not use this file except in compliance with the License. 61a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * You may obtain a copy of the License at 71a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * 81a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * http://www.apache.org/licenses/LICENSE-2.0 91a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * 101a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * Unless required by applicable law or agreed to in writing, software 111a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * distributed under the License is distributed on an "AS IS" BASIS, 121a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * See the License for the specific language governing permissions and 141a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * limitations under the License 151a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek */ 161a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 171a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinekpackage com.android.systemui.statusbar.notification; 181a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 1901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinekimport android.annotation.Nullable; 201a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinekimport android.app.Notification; 211a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinekimport android.content.Context; 222630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport android.os.AsyncTask; 2301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinekimport android.os.CancellationSignal; 241a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinekimport android.service.notification.StatusBarNotification; 251a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinekimport android.util.Log; 261a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinekimport android.view.View; 271a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinekimport android.widget.RemoteViews; 281a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 2910790672a98debafb8882971e94ff26aec9a6bfaSelim Cinekimport com.android.internal.annotations.VisibleForTesting; 30ac5f02749a595d39711beb4a1defb01949eb548aSelim Cinekimport com.android.systemui.R; 3167ff248168fb77dadd81886df134cbfe048a6001Selim Cinekimport com.android.systemui.statusbar.InflationTask; 321a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinekimport com.android.systemui.statusbar.ExpandableNotificationRow; 331a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinekimport com.android.systemui.statusbar.NotificationContentView; 341a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinekimport com.android.systemui.statusbar.NotificationData; 351a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinekimport com.android.systemui.statusbar.phone.StatusBar; 3601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinekimport com.android.systemui.util.Assert; 3701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 3801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinekimport java.util.HashMap; 39ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinekimport java.util.concurrent.Executor; 40ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinekimport java.util.concurrent.LinkedBlockingQueue; 41ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinekimport java.util.concurrent.ThreadFactory; 42ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinekimport java.util.concurrent.ThreadPoolExecutor; 43ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinekimport java.util.concurrent.TimeUnit; 44ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinekimport java.util.concurrent.atomic.AtomicInteger; 451a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 461a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek/** 471a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek * A utility that inflates the right kind of contentView based on the state 481a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek */ 491a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinekpublic class NotificationInflater { 501a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 51d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek public static final String TAG = "NotificationInflater"; 5210790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek @VisibleForTesting 5310790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek static final int FLAG_REINFLATE_ALL = ~0; 54c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek private static final int FLAG_REINFLATE_CONTENT_VIEW = 1<<0; 552630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek @VisibleForTesting 562630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek static final int FLAG_REINFLATE_EXPANDED_VIEW = 1<<1; 57c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek private static final int FLAG_REINFLATE_HEADS_UP_VIEW = 1<<2; 58c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek private static final int FLAG_REINFLATE_PUBLIC_VIEW = 1<<3; 59c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek private static final int FLAG_REINFLATE_AMBIENT_VIEW = 1<<4; 60ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek private static final InflationExecutor EXECUTOR = new InflationExecutor(); 61c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek 621a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek private final ExpandableNotificationRow mRow; 631a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek private boolean mIsLowPriority; 641a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek private boolean mUsesIncreasedHeight; 651a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek private boolean mUsesIncreasedHeadsUpHeight; 661a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek private RemoteViews.OnClickHandler mRemoteViewClickHandler; 67c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek private boolean mIsChildInGroup; 682630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek private InflationCallback mCallback; 691a1ecfcf5ae32482aee23ebc7c4389daf164caddAdrian Roos private boolean mRedactAmbient; 701a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 711a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek public NotificationInflater(ExpandableNotificationRow row) { 721a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek mRow = row; 731a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 741a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 751a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek public void setIsLowPriority(boolean isLowPriority) { 761a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek mIsLowPriority = isLowPriority; 771a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 781a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 79c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek /** 80c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek * Set whether the notification is a child in a group 81c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek * 82c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek * @return whether the view was re-inflated 83c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek */ 842630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek public void setIsChildInGroup(boolean childInGroup) { 85c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek if (childInGroup != mIsChildInGroup) { 86c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek mIsChildInGroup = childInGroup; 87c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek if (mIsLowPriority) { 882630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek int flags = FLAG_REINFLATE_CONTENT_VIEW | FLAG_REINFLATE_EXPANDED_VIEW; 892630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek inflateNotificationViews(flags); 90c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek } 912630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek } ; 92c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek } 93c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek 941a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek public void setUsesIncreasedHeight(boolean usesIncreasedHeight) { 951a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek mUsesIncreasedHeight = usesIncreasedHeight; 961a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 971a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 981a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek public void setUsesIncreasedHeadsUpHeight(boolean usesIncreasedHeight) { 991a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek mUsesIncreasedHeadsUpHeight = usesIncreasedHeight; 1001a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 1011a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 1021a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) { 1031a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek mRemoteViewClickHandler = remoteViewClickHandler; 1041a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 1051a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 1061a1ecfcf5ae32482aee23ebc7c4389daf164caddAdrian Roos public void setRedactAmbient(boolean redactAmbient) { 1071a1ecfcf5ae32482aee23ebc7c4389daf164caddAdrian Roos if (mRedactAmbient != redactAmbient) { 1081a1ecfcf5ae32482aee23ebc7c4389daf164caddAdrian Roos mRedactAmbient = redactAmbient; 1091a1ecfcf5ae32482aee23ebc7c4389daf164caddAdrian Roos if (mRow.getEntry() == null) { 1101a1ecfcf5ae32482aee23ebc7c4389daf164caddAdrian Roos return; 1111a1ecfcf5ae32482aee23ebc7c4389daf164caddAdrian Roos } 1122630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek inflateNotificationViews(FLAG_REINFLATE_AMBIENT_VIEW); 1131a1ecfcf5ae32482aee23ebc7c4389daf164caddAdrian Roos } 1141a1ecfcf5ae32482aee23ebc7c4389daf164caddAdrian Roos } 1151a1ecfcf5ae32482aee23ebc7c4389daf164caddAdrian Roos 1162630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek /** 1172630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * Inflate all views of this notification on a background thread. This is asynchronous and will 1182630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * notify the callback once it's finished. 1192630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek */ 1202630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek public void inflateNotificationViews() { 121c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek inflateNotificationViews(FLAG_REINFLATE_ALL); 122c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek } 123c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek 124c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek /** 1252630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * Reinflate all views for the specified flags on a background thread. This is asynchronous and 1262630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * will notify the callback once it's finished. 1272630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * 128c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek * @param reInflateFlags flags which views should be reinflated. Use {@link #FLAG_REINFLATE_ALL} 129c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek * to reinflate all of views. 130c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek */ 1312630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek @VisibleForTesting 1322630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek void inflateNotificationViews(int reInflateFlags) { 13367ff248168fb77dadd81886df134cbfe048a6001Selim Cinek if (mRow.isRemoved()) { 13467ff248168fb77dadd81886df134cbfe048a6001Selim Cinek // We don't want to reinflate anything for removed notifications. Otherwise views might 13567ff248168fb77dadd81886df134cbfe048a6001Selim Cinek // be readded to the stack, leading to leaks. This may happen with low-priority groups 13667ff248168fb77dadd81886df134cbfe048a6001Selim Cinek // where the removal of already removed children can lead to a reinflation. 13767ff248168fb77dadd81886df134cbfe048a6001Selim Cinek return; 13867ff248168fb77dadd81886df134cbfe048a6001Selim Cinek } 13910790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek StatusBarNotification sbn = mRow.getEntry().notification; 1406dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk AsyncInflationTask task = new AsyncInflationTask(sbn, reInflateFlags, mRow, 1416dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk mIsLowPriority, 14201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient, 1436dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk mCallback, mRemoteViewClickHandler); 1446dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk if (mCallback != null && mCallback.doInflateSynchronous()) { 1456dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk task.onPostExecute(task.doInBackground()); 1466dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk } else { 1476dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk task.execute(); 1486dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk } 14910790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek } 1501a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 15110790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek @VisibleForTesting 15201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek InflationProgress inflateNotificationViews(int reInflateFlags, 15310790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek Notification.Builder builder, Context packageContext) { 15401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek InflationProgress result = createRemoteViews(reInflateFlags, builder, mIsLowPriority, 15501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, 15601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mRedactAmbient, packageContext); 15701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek apply(result, reInflateFlags, mRow, mRedactAmbient, mRemoteViewClickHandler, null); 15801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek return result; 15901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 1601a1ecfcf5ae32482aee23ebc7c4389daf164caddAdrian Roos 16101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private static InflationProgress createRemoteViews(int reInflateFlags, 16201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek Notification.Builder builder, boolean isLowPriority, boolean isChildInGroup, 16301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight, boolean redactAmbient, 16401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek Context packageContext) { 16501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek InflationProgress result = new InflationProgress(); 16601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek isLowPriority = isLowPriority && !isChildInGroup; 16710790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) { 16801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight); 16910790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek } 170c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek 17110790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) { 17201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek result.newExpandedView = createExpandedView(builder, isLowPriority); 17310790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek } 1741a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 17510790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) { 17601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight); 17710790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek } 1781a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 17910790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) { 18001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek result.newPublicView = builder.makePublicContentView(); 18110790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek } 18210790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek 18310790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) { 18401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek result.newAmbientView = redactAmbient ? builder.makePublicAmbientNotification() 1851a1ecfcf5ae32482aee23ebc7c4389daf164caddAdrian Roos : builder.makeAmbientNotification(); 18601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 18701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek result.packageContext = packageContext; 188aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek result.headsUpStatusBarText = builder.getHeadsUpStatusBarText(false /* showingPublic */); 189aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek result.headsUpStatusBarTextPublic = builder.getHeadsUpStatusBarText( 190aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek true /* showingPublic */); 19101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek return result; 19201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 19301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 19401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public static CancellationSignal apply(InflationProgress result, int reInflateFlags, 19501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek ExpandableNotificationRow row, boolean redactAmbient, 19601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek RemoteViews.OnClickHandler remoteViewClickHandler, 19701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Nullable InflationCallback callback) { 19801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek NotificationData.Entry entry = row.getEntry(); 19901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek NotificationContentView privateLayout = row.getPrivateLayout(); 20001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek NotificationContentView publicLayout = row.getPublicLayout(); 20101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek final HashMap<Integer, CancellationSignal> runningInflations = new HashMap<>(); 20201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 20301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek int flag = FLAG_REINFLATE_CONTENT_VIEW; 20401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if ((reInflateFlags & flag) != 0) { 205fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek boolean isNewView = !canReapplyRemoteView(result.newContentView, entry.cachedContentView); 20601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek ApplyCallback applyCallback = new ApplyCallback() { 20701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 20801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public void setResultView(View v) { 20901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek result.inflatedContentView = v; 21001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 21101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 21201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 21301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public RemoteViews getRemoteView() { 21401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek return result.newContentView; 21501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 21601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek }; 21701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek applyRemoteView(result, reInflateFlags, flag, row, redactAmbient, 21801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek isNewView, remoteViewClickHandler, callback, entry, privateLayout, 219131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek privateLayout.getContractedChild(), privateLayout.getVisibleWrapper( 220131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek NotificationContentView.VISIBLE_TYPE_CONTRACTED), 22101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek runningInflations, applyCallback); 22201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 22301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 22401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek flag = FLAG_REINFLATE_EXPANDED_VIEW; 22501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if ((reInflateFlags & flag) != 0) { 22601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if (result.newExpandedView != null) { 227fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek boolean isNewView = !canReapplyRemoteView(result.newExpandedView, 22801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek entry.cachedBigContentView); 22901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek ApplyCallback applyCallback = new ApplyCallback() { 23001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 23101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public void setResultView(View v) { 23201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek result.inflatedExpandedView = v; 23301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 23401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 23501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 23601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public RemoteViews getRemoteView() { 23701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek return result.newExpandedView; 23801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 23901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek }; 24001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek applyRemoteView(result, reInflateFlags, flag, row, 24101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek redactAmbient, isNewView, remoteViewClickHandler, callback, entry, 242131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek privateLayout, privateLayout.getExpandedChild(), 243131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek privateLayout.getVisibleWrapper( 244131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek NotificationContentView.VISIBLE_TYPE_EXPANDED), runningInflations, 24501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek applyCallback); 24601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 24701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 24801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 24901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek flag = FLAG_REINFLATE_HEADS_UP_VIEW; 25001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if ((reInflateFlags & flag) != 0) { 25101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if (result.newHeadsUpView != null) { 252fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek boolean isNewView = !canReapplyRemoteView(result.newHeadsUpView, 25301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek entry.cachedHeadsUpContentView); 25401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek ApplyCallback applyCallback = new ApplyCallback() { 25501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 25601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public void setResultView(View v) { 25701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek result.inflatedHeadsUpView = v; 25801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 25901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 26001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 26101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public RemoteViews getRemoteView() { 26201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek return result.newHeadsUpView; 26301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 26401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek }; 26501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek applyRemoteView(result, reInflateFlags, flag, row, 26601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek redactAmbient, isNewView, remoteViewClickHandler, callback, entry, 267131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek privateLayout, privateLayout.getHeadsUpChild(), 268131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek privateLayout.getVisibleWrapper( 269131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek NotificationContentView.VISIBLE_TYPE_HEADSUP), runningInflations, 27001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek applyCallback); 27110790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek } 2721a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 27301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 27401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek flag = FLAG_REINFLATE_PUBLIC_VIEW; 27501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if ((reInflateFlags & flag) != 0) { 276fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek boolean isNewView = !canReapplyRemoteView(result.newPublicView, 27701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek entry.cachedPublicContentView); 27801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek ApplyCallback applyCallback = new ApplyCallback() { 27901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 28001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public void setResultView(View v) { 28101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek result.inflatedPublicView = v; 28201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 28301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 28401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 28501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public RemoteViews getRemoteView() { 28601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek return result.newPublicView; 28701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 28801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek }; 28901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek applyRemoteView(result, reInflateFlags, flag, row, 29001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek redactAmbient, isNewView, remoteViewClickHandler, callback, entry, 291131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek publicLayout, publicLayout.getContractedChild(), 292131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek publicLayout.getVisibleWrapper(NotificationContentView.VISIBLE_TYPE_CONTRACTED), 293131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek runningInflations, applyCallback); 29401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 29501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 29601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek flag = FLAG_REINFLATE_AMBIENT_VIEW; 29701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if ((reInflateFlags & flag) != 0) { 29801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek NotificationContentView newParent = redactAmbient ? publicLayout : privateLayout; 29901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek boolean isNewView = !canReapplyAmbient(row, redactAmbient) || 300fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek !canReapplyRemoteView(result.newAmbientView, entry.cachedAmbientContentView); 30101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek ApplyCallback applyCallback = new ApplyCallback() { 30201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 30301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public void setResultView(View v) { 30401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek result.inflatedAmbientView = v; 30501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 30601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 30701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 30801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public RemoteViews getRemoteView() { 30901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek return result.newAmbientView; 31001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 31101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek }; 31201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek applyRemoteView(result, reInflateFlags, flag, row, 31301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek redactAmbient, isNewView, remoteViewClickHandler, callback, entry, 314131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek newParent, newParent.getAmbientChild(), newParent.getVisibleWrapper( 315131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek NotificationContentView.VISIBLE_TYPE_AMBIENT), runningInflations, 31601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek applyCallback); 31701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 31801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 31901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek // Let's try to finish, maybe nobody is even inflating anything 32001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek finishIfDone(result, reInflateFlags, runningInflations, callback, row, 32101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek redactAmbient); 32201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek CancellationSignal cancellationSignal = new CancellationSignal(); 32301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek cancellationSignal.setOnCancelListener( 32401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek () -> runningInflations.values().forEach(CancellationSignal::cancel)); 32501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek return cancellationSignal; 32601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 32701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 328d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek @VisibleForTesting 329d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek static void applyRemoteView(final InflationProgress result, 33001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek final int reInflateFlags, int inflationId, 33101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek final ExpandableNotificationRow row, 33201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek final boolean redactAmbient, boolean isNewView, 33301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek RemoteViews.OnClickHandler remoteViewClickHandler, 33401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Nullable final InflationCallback callback, NotificationData.Entry entry, 33501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek NotificationContentView parentLayout, View existingView, 336131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek NotificationViewWrapper existingWrapper, 33701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek final HashMap<Integer, CancellationSignal> runningInflations, 33801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek ApplyCallback applyCallback) { 339d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek RemoteViews newContentView = applyCallback.getRemoteView(); 3406dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk if (callback != null && callback.doInflateSynchronous()) { 3416dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk try { 3426dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk if (isNewView) { 3436dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk View v = newContentView.apply( 3446dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk result.packageContext, 3456dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk parentLayout, 3466dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk remoteViewClickHandler); 3476dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk v.setIsRootNamespace(true); 3486dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk applyCallback.setResultView(v); 3496dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk } else { 3506dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk newContentView.reapply( 3516dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk result.packageContext, 3526dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk existingView, 3536dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk remoteViewClickHandler); 3546dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk existingWrapper.onReinflated(); 3556dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk } 3566dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk } catch (Exception e) { 3576dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk handleInflationError(runningInflations, e, entry.notification, callback); 3586dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk // Add a running inflation to make sure we don't trigger callbacks. 3596dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk // Safe to do because only happens in tests. 3606dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk runningInflations.put(inflationId, new CancellationSignal()); 3616dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk } 3626dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk return; 3636dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk } 36401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek RemoteViews.OnViewAppliedListener listener 36501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek = new RemoteViews.OnViewAppliedListener() { 36601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 36701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 36801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public void onViewApplied(View v) { 36901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if (isNewView) { 37001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek v.setIsRootNamespace(true); 37101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek applyCallback.setResultView(v); 372131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek } else if (existingWrapper != null) { 373131f1a4bc491c07f0c3f643ac5b2551061799024Selim Cinek existingWrapper.onReinflated(); 37401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 37501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek runningInflations.remove(inflationId); 37601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek finishIfDone(result, reInflateFlags, runningInflations, callback, row, 37701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek redactAmbient); 37801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 37901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 38001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 38101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public void onError(Exception e) { 382d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek // Uh oh the async inflation failed. Due to some bugs (see b/38190555), this could 383d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek // actually also be a system issue, so let's try on the UI thread again to be safe. 384d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek try { 385d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek View newView = existingView; 386d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek if (isNewView) { 387d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek newView = newContentView.apply( 388d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek result.packageContext, 389d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek parentLayout, 390d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek remoteViewClickHandler); 391d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek } else { 392d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek newContentView.reapply( 393d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek result.packageContext, 394d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek existingView, 395d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek remoteViewClickHandler); 396d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek } 397d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek Log.wtf(TAG, "Async Inflation failed but normal inflation finished normally.", 398d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek e); 399d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek onViewApplied(newView); 400d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek } catch (Exception anotherException) { 401d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek runningInflations.remove(inflationId); 402d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek handleInflationError(runningInflations, e, entry.notification, callback); 403d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek } 40401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 40501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek }; 40601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek CancellationSignal cancellationSignal; 40701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if (isNewView) { 40801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek cancellationSignal = newContentView.applyAsync( 40901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek result.packageContext, 41001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek parentLayout, 411ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek EXECUTOR, 41201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek listener, 41301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek remoteViewClickHandler); 41401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } else { 41501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek cancellationSignal = newContentView.reapplyAsync( 41601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek result.packageContext, 41701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek existingView, 418ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek EXECUTOR, 41901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek listener, 42001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek remoteViewClickHandler); 42101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 42201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek runningInflations.put(inflationId, cancellationSignal); 4231a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 4241a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 42501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private static void handleInflationError(HashMap<Integer, CancellationSignal> runningInflations, 42601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek Exception e, StatusBarNotification notification, @Nullable InflationCallback callback) { 42701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek Assert.isMainThread(); 42801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek runningInflations.values().forEach(CancellationSignal::cancel); 42901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if (callback != null) { 43001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek callback.handleInflationException(notification, e); 43101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 43201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 43301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 43401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek /** 43501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek * Finish the inflation of the views 43601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek * 43701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek * @return true if the inflation was finished 43801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek */ 43901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private static boolean finishIfDone(InflationProgress result, int reInflateFlags, 44001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek HashMap<Integer, CancellationSignal> runningInflations, 44101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Nullable InflationCallback endListener, ExpandableNotificationRow row, 44201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek boolean redactAmbient) { 44301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek Assert.isMainThread(); 44401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek NotificationData.Entry entry = row.getEntry(); 44501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek NotificationContentView privateLayout = row.getPrivateLayout(); 44601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek NotificationContentView publicLayout = row.getPublicLayout(); 44701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if (runningInflations.isEmpty()) { 44801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) { 44901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if (result.inflatedContentView != null) { 45001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek privateLayout.setContractedChild(result.inflatedContentView); 45101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 45201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek entry.cachedContentView = result.newContentView; 45301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 45401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 45501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) { 45601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if (result.inflatedExpandedView != null) { 45701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek privateLayout.setExpandedChild(result.inflatedExpandedView); 45801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } else if (result.newExpandedView == null) { 45901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek privateLayout.setExpandedChild(null); 46001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 46101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek entry.cachedBigContentView = result.newExpandedView; 46201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek row.setExpandable(result.newExpandedView != null); 46301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 46401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 46501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) { 46601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if (result.inflatedHeadsUpView != null) { 46701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek privateLayout.setHeadsUpChild(result.inflatedHeadsUpView); 46801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } else if (result.newHeadsUpView == null) { 46901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek privateLayout.setHeadsUpChild(null); 47001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 47101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek entry.cachedHeadsUpContentView = result.newHeadsUpView; 47201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 47301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 47401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) { 47501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if (result.inflatedPublicView != null) { 47601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek publicLayout.setContractedChild(result.inflatedPublicView); 47701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 47801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek entry.cachedPublicContentView = result.newPublicView; 47901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 48001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 48101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) { 48201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if (result.inflatedAmbientView != null) { 48301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek NotificationContentView newParent = redactAmbient 48401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek ? publicLayout : privateLayout; 48501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek NotificationContentView otherParent = !redactAmbient 48601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek ? publicLayout : privateLayout; 48701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek newParent.setAmbientChild(result.inflatedAmbientView); 48801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek otherParent.setAmbientChild(null); 48901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 49001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek entry.cachedAmbientContentView = result.newAmbientView; 49101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 492aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek entry.headsUpStatusBarText = result.headsUpStatusBarText; 493aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek entry.headsUpStatusBarTextPublic = result.headsUpStatusBarTextPublic; 49401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if (endListener != null) { 49501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek endListener.onAsyncInflationFinished(row.getEntry()); 49601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 49701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek return true; 49801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 49901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek return false; 50001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 50101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 50201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private static RemoteViews createExpandedView(Notification.Builder builder, 5031a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek boolean isLowPriority) { 5041a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek RemoteViews bigContentView = builder.createBigContentView(); 5051a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek if (bigContentView != null) { 5061a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek return bigContentView; 5071a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 5081a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek if (isLowPriority) { 5091a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek RemoteViews contentView = builder.createContentView(); 5101a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek Notification.Builder.makeHeaderExpanded(contentView); 5111a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek return contentView; 5121a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 5131a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek return null; 5141a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 5151a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 51601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private static RemoteViews createContentView(Notification.Builder builder, 5171a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek boolean isLowPriority, boolean useLarge) { 5181a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek if (isLowPriority) { 5191a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek return builder.makeLowPriorityContentView(false /* useRegularSubtext */); 5201a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 5211a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek return builder.createContentView(useLarge); 5221a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 5231a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 524fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek /** 525fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek * @param newView The new view that will be applied 526fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek * @param oldView The old view that was applied to the existing view before 527fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek * @return {@code true} if the RemoteViews are the same and the view can be reused to reapply. 528fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek */ 529fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek @VisibleForTesting 530fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek static boolean canReapplyRemoteView(final RemoteViews newView, 531fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek final RemoteViews oldView) { 532fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek return (newView == null && oldView == null) || 533fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek (newView != null && oldView != null 534fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek && oldView.getPackage() != null 535fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek && newView.getPackage() != null 536fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek && newView.getPackage().equals(oldView.getPackage()) 537fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek && newView.getLayoutId() == oldView.getLayoutId() 538fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek && !oldView.isReapplyDisallowed()); 5391a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 540c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek 5412630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek public void setInflationCallback(InflationCallback callback) { 5422630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek mCallback = callback; 543c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek } 544c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek 5452630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek public interface InflationCallback { 54601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek void handleInflationException(StatusBarNotification notification, Exception e); 5472630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek void onAsyncInflationFinished(NotificationData.Entry entry); 5486dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk 5496dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk /** 5506dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk * Used to disable async-ness for tests. Should only be used for tests. 5516dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk */ 5526dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk default boolean doInflateSynchronous() { 5536dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk return false; 5546dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk } 555c478f9023d7649d85e60759c9e6c0e033774293bSelim Cinek } 55610790672a98debafb8882971e94ff26aec9a6bfaSelim Cinek 5571a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek public void onDensityOrFontScaleChanged() { 5581a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek NotificationData.Entry entry = mRow.getEntry(); 5591a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek entry.cachedAmbientContentView = null; 5601a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek entry.cachedBigContentView = null; 5611a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek entry.cachedContentView = null; 5621a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek entry.cachedHeadsUpContentView = null; 5631a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek entry.cachedPublicContentView = null; 5642630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek inflateNotificationViews(); 5652630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek } 5662630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek 56701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private static boolean canReapplyAmbient(ExpandableNotificationRow row, boolean redactAmbient) { 56801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek NotificationContentView ambientView = redactAmbient ? row.getPublicLayout() 56901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek : row.getPrivateLayout(); ; 57001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek return ambientView.getAmbientChild() != null; 57101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 57201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 57301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress> 57467ff248168fb77dadd81886df134cbfe048a6001Selim Cinek implements InflationCallback, InflationTask { 5752630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek 5762630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek private final StatusBarNotification mSbn; 5772630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek private final Context mContext; 57801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private final boolean mIsLowPriority; 57901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private final boolean mIsChildInGroup; 58001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private final boolean mUsesIncreasedHeight; 58101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private final InflationCallback mCallback; 58201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private final boolean mUsesIncreasedHeadsUpHeight; 58301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private final boolean mRedactAmbient; 58467ff248168fb77dadd81886df134cbfe048a6001Selim Cinek private int mReInflateFlags; 58501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private ExpandableNotificationRow mRow; 5862630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek private Exception mError; 58701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private RemoteViews.OnClickHandler mRemoteViewClickHandler; 58801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private CancellationSignal mCancellationSignal; 58901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 59001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private AsyncInflationTask(StatusBarNotification notification, 59101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek int reInflateFlags, ExpandableNotificationRow row, boolean isLowPriority, 59201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek boolean isChildInGroup, boolean usesIncreasedHeight, 59301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek boolean usesIncreasedHeadsUpHeight, boolean redactAmbient, 59401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek InflationCallback callback, 59501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek RemoteViews.OnClickHandler remoteViewClickHandler) { 59601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mRow = row; 5972630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek mSbn = notification; 5982630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek mReInflateFlags = reInflateFlags; 59901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mContext = mRow.getContext(); 60001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mIsLowPriority = isLowPriority; 60101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mIsChildInGroup = isChildInGroup; 60201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mUsesIncreasedHeight = usesIncreasedHeight; 60301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mUsesIncreasedHeadsUpHeight = usesIncreasedHeadsUpHeight; 60401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mRedactAmbient = redactAmbient; 60501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mRemoteViewClickHandler = remoteViewClickHandler; 60601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mCallback = callback; 60767ff248168fb77dadd81886df134cbfe048a6001Selim Cinek NotificationData.Entry entry = row.getEntry(); 60867ff248168fb77dadd81886df134cbfe048a6001Selim Cinek entry.setInflationTask(this); 60967ff248168fb77dadd81886df134cbfe048a6001Selim Cinek } 61067ff248168fb77dadd81886df134cbfe048a6001Selim Cinek 61167ff248168fb77dadd81886df134cbfe048a6001Selim Cinek @VisibleForTesting 61267ff248168fb77dadd81886df134cbfe048a6001Selim Cinek public int getReInflateFlags() { 61367ff248168fb77dadd81886df134cbfe048a6001Selim Cinek return mReInflateFlags; 6142630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek } 6152630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek 6162630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek @Override 61701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek protected InflationProgress doInBackground(Void... params) { 6182630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek try { 6192630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek final Notification.Builder recoveredBuilder 6202630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek = Notification.Builder.recoverBuilder(mContext, 6212630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek mSbn.getNotification()); 62201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek Context packageContext = mSbn.getPackageContext(mContext); 6235fb73f86299d9cc616ca741f8c7c4af2485cc273Selim Cinek Notification notification = mSbn.getNotification(); 6240847acd4d48deb716de99d259364bc99b592a8bcSelim Cinek if (notification.isMediaNotification()) { 6250847acd4d48deb716de99d259364bc99b592a8bcSelim Cinek MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext, 62601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek packageContext); 6275fb73f86299d9cc616ca741f8c7c4af2485cc273Selim Cinek processor.processNotification(notification, recoveredBuilder); 6285fb73f86299d9cc616ca741f8c7c4af2485cc273Selim Cinek } 62901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek return createRemoteViews(mReInflateFlags, 63001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek recoveredBuilder, mIsLowPriority, mIsChildInGroup, 63101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient, 63201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek packageContext); 6332630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek } catch (Exception e) { 6342630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek mError = e; 6352630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek return null; 6362630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek } 6372630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek } 6382630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek 6392630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek @Override 64001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek protected void onPostExecute(InflationProgress result) { 6412630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek if (mError == null) { 64201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mCancellationSignal = apply(result, mReInflateFlags, mRow, mRedactAmbient, 64301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mRemoteViewClickHandler, this); 6442630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek } else { 6452630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek handleError(mError); 6462630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek } 6472630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek } 6482630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek 64901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private void handleError(Exception e) { 65001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mRow.getEntry().onInflationTaskFinished(); 65101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek StatusBarNotification sbn = mRow.getStatusBarNotification(); 65201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek final String ident = sbn.getPackageName() + "/0x" 65301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek + Integer.toHexString(sbn.getId()); 65401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e); 65501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mCallback.handleInflationException(sbn, 65601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek new InflationException("Couldn't inflate contentViews" + e)); 65701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 65801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 6590f66a4cc16ec1a927c90ac559c73c80ddcb5ee71Selim Cinek @Override 66001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public void abort() { 66101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek cancel(true /* mayInterruptIfRunning */); 66201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek if (mCancellationSignal != null) { 66301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mCancellationSignal.cancel(); 66401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 66501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 66601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 66701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 66867ff248168fb77dadd81886df134cbfe048a6001Selim Cinek public void supersedeTask(InflationTask task) { 66967ff248168fb77dadd81886df134cbfe048a6001Selim Cinek if (task instanceof AsyncInflationTask) { 67067ff248168fb77dadd81886df134cbfe048a6001Selim Cinek // We want to inflate all flags of the previous task as well 67167ff248168fb77dadd81886df134cbfe048a6001Selim Cinek mReInflateFlags |= ((AsyncInflationTask) task).mReInflateFlags; 67267ff248168fb77dadd81886df134cbfe048a6001Selim Cinek } 67367ff248168fb77dadd81886df134cbfe048a6001Selim Cinek } 67467ff248168fb77dadd81886df134cbfe048a6001Selim Cinek 67567ff248168fb77dadd81886df134cbfe048a6001Selim Cinek @Override 67601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public void handleInflationException(StatusBarNotification notification, Exception e) { 6772630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek handleError(e); 6781a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 67901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 68001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek @Override 68101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public void onAsyncInflationFinished(NotificationData.Entry entry) { 68201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mRow.getEntry().onInflationTaskFinished(); 68301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mRow.onNotificationUpdated(); 68401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek mCallback.onAsyncInflationFinished(mRow.getEntry()); 68501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 6866dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk 6876dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk @Override 6886dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk public boolean doInflateSynchronous() { 6896dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk return mCallback != null && mCallback.doInflateSynchronous(); 6906dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk } 69101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek } 69201d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 693d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek @VisibleForTesting 694d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek static class InflationProgress { 69501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private RemoteViews newContentView; 69601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private RemoteViews newHeadsUpView; 69701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private RemoteViews newExpandedView; 69801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private RemoteViews newAmbientView; 69901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private RemoteViews newPublicView; 70001d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 701d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek @VisibleForTesting 702d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek Context packageContext; 70301d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek 70401d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private View inflatedContentView; 70501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private View inflatedHeadsUpView; 70601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private View inflatedExpandedView; 70701d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private View inflatedAmbientView; 70801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek private View inflatedPublicView; 709aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek private CharSequence headsUpStatusBarText; 710aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek private CharSequence headsUpStatusBarTextPublic; 7111a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek } 7121a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek 713d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek @VisibleForTesting 714d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek abstract static class ApplyCallback { 71501d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public abstract void setResultView(View v); 71601d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek public abstract RemoteViews getRemoteView(); 7172630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek } 718ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek 719ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek /** 720ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek * A custom executor that allows more tasks to be queued. Default values are copied from 721ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek * AsyncTask 722ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek */ 723ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek private static class InflationExecutor implements Executor { 724ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); 725ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek // We want at least 2 threads and at most 4 threads in the core pool, 726ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek // preferring to have 1 less than the CPU count to avoid saturating 727ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek // the CPU with background work 728ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4)); 729ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; 730ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek private static final int KEEP_ALIVE_SECONDS = 30; 731ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek 732ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek private static final ThreadFactory sThreadFactory = new ThreadFactory() { 733ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek private final AtomicInteger mCount = new AtomicInteger(1); 734ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek 735ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek public Thread newThread(Runnable r) { 736ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek return new Thread(r, "InflaterThread #" + mCount.getAndIncrement()); 737ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek } 738ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek }; 739ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek 740ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek private final ThreadPoolExecutor mExecutor; 741ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek 742ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek private InflationExecutor() { 743ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek mExecutor = new ThreadPoolExecutor( 744ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, 745ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek new LinkedBlockingQueue<>(), sThreadFactory); 746ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek mExecutor.allowCoreThreadTimeOut(true); 747ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek } 748ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek 749ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek @Override 750ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek public void execute(Runnable runnable) { 751ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek mExecutor.execute(runnable); 752ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek } 753ae8de8c77c51b7b26ba92f2cce76bb5dd74bea73Selim Cinek } 7541a48babb5ed30e8a3eb9645355d6455b21041406Selim Cinek} 755