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