diff options
| author | 2017-06-20 22:56:33 +0000 | |
|---|---|---|
| committer | 2017-06-20 22:56:33 +0000 | |
| commit | ddd031e23d60ef73f3b0449d631abcbec56163ca (patch) | |
| tree | eb6b8f1a4e1e5699449ed9c86a4b9a970cfb659c | |
| parent | b4891d4e52c9e4af524eb44c075d76f9b3cce8ae (diff) | |
| parent | 07b93779ba30dd1d0350ad26d0d7e4aa36e96eb8 (diff) | |
Merge "Retrying the remoteview application on the ui thread" into oc-dev
am: 07b93779ba
Change-Id: I827a9c9d1ece9fec41200c03400bcdf88b248cce
2 files changed, 100 insertions, 7 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java index 7eaa290c9d23..bf926c625e4f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java @@ -48,6 +48,7 @@ import java.util.concurrent.atomic.AtomicInteger; */ public class NotificationInflater { + public static final String TAG = "NotificationInflater"; @VisibleForTesting static final int FLAG_REINFLATE_ALL = ~0; private static final int FLAG_REINFLATE_CONTENT_VIEW = 1<<0; @@ -315,7 +316,8 @@ public class NotificationInflater { return cancellationSignal; } - private static void applyRemoteView(final InflationProgress result, + @VisibleForTesting + static void applyRemoteView(final InflationProgress result, final int reInflateFlags, int inflationId, final ExpandableNotificationRow row, final boolean redactAmbient, boolean isNewView, @@ -325,6 +327,7 @@ public class NotificationInflater { NotificationViewWrapper existingWrapper, final HashMap<Integer, CancellationSignal> runningInflations, ApplyCallback applyCallback) { + RemoteViews newContentView = applyCallback.getRemoteView(); RemoteViews.OnViewAppliedListener listener = new RemoteViews.OnViewAppliedListener() { @@ -343,12 +346,31 @@ public class NotificationInflater { @Override public void onError(Exception e) { - runningInflations.remove(inflationId); - handleInflationError(runningInflations, e, entry.notification, callback); + // Uh oh the async inflation failed. Due to some bugs (see b/38190555), this could + // actually also be a system issue, so let's try on the UI thread again to be safe. + try { + View newView = existingView; + if (isNewView) { + newView = newContentView.apply( + result.packageContext, + parentLayout, + remoteViewClickHandler); + } else { + newContentView.reapply( + result.packageContext, + existingView, + remoteViewClickHandler); + } + Log.wtf(TAG, "Async Inflation failed but normal inflation finished normally.", + e); + onViewApplied(newView); + } catch (Exception anotherException) { + runningInflations.remove(inflationId); + handleInflationError(runningInflations, e, entry.notification, callback); + } } }; CancellationSignal cancellationSignal; - RemoteViews newContentView = applyCallback.getRemoteView(); if (isNewView) { cancellationSignal = newContentView.applyAsync( result.packageContext, @@ -620,14 +642,16 @@ public class NotificationInflater { } } - private static class InflationProgress { + @VisibleForTesting + static class InflationProgress { private RemoteViews newContentView; private RemoteViews newHeadsUpView; private RemoteViews newExpandedView; private RemoteViews newAmbientView; private RemoteViews newPublicView; - private Context packageContext; + @VisibleForTesting + Context packageContext; private View inflatedContentView; private View inflatedHeadsUpView; @@ -636,7 +660,8 @@ public class NotificationInflater { private View inflatedPublicView; } - private abstract static class ApplyCallback { + @VisibleForTesting + abstract static class ApplyCallback { public abstract void setResultView(View v); public abstract RemoteViews getRemoteView(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java index ee8db886ba65..3429d5c6c0f4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java @@ -24,12 +24,17 @@ import static org.mockito.Mockito.verify; import android.app.Notification; import android.content.Context; +import android.os.CancellationSignal; +import android.os.Handler; +import android.os.Looper; import android.service.notification.StatusBarNotification; import android.support.test.InstrumentationRegistry; import android.support.test.annotation.UiThreadTest; import android.support.test.filters.FlakyTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import android.view.View; +import android.view.ViewGroup; import android.widget.RemoteViews; import com.android.systemui.R; @@ -45,7 +50,9 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.HashMap; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; @SmallTest @RunWith(AndroidJUnit4.class) @@ -141,6 +148,41 @@ public class NotificationInflaterTest extends SysuiTestCase { Assert.assertNull(mRow.getEntry().getRunningTask()); } + @Test + public void testInflationIsRetriedIfAsyncFails() throws Exception { + NotificationInflater.InflationProgress result = + new NotificationInflater.InflationProgress(); + result.packageContext = mContext; + CountDownLatch countDownLatch = new CountDownLatch(1); + NotificationInflater.applyRemoteView(result, + NotificationInflater.FLAG_REINFLATE_EXPANDED_VIEW, 0, mRow, + false /* redactAmbient */, true /* isNewView */, new RemoteViews.OnClickHandler(), + new NotificationInflater.InflationCallback() { + @Override + public void handleInflationException(StatusBarNotification notification, + Exception e) { + countDownLatch.countDown(); + throw new RuntimeException("No Exception expected"); + } + + @Override + public void onAsyncInflationFinished(NotificationData.Entry entry) { + countDownLatch.countDown(); + } + }, mRow.getEntry(), mRow.getPrivateLayout(), null, null, new HashMap<>(), + new NotificationInflater.ApplyCallback() { + @Override + public void setResultView(View v) { + } + + @Override + public RemoteViews getRemoteView() { + return new AsyncFailRemoteView(mContext.getPackageName(), + R.layout.custom_view_dark); + } + }); + countDownLatch.await(); + } @Test public void testSupersedesExistingTask() throws Exception { @@ -199,4 +241,30 @@ public class NotificationInflaterTest extends SysuiTestCase { mException = exception; } } + + private class AsyncFailRemoteView extends RemoteViews { + Handler mHandler = new Handler(Looper.getMainLooper()); + + public AsyncFailRemoteView(String packageName, int layoutId) { + super(packageName, layoutId); + } + + @Override + public View apply(Context context, ViewGroup parent) { + return super.apply(context, parent); + } + + @Override + public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor, + OnViewAppliedListener listener, OnClickHandler handler) { + mHandler.post(() -> listener.onError(new RuntimeException("Failed to inflate async"))); + return new CancellationSignal(); + } + + @Override + public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor, + OnViewAppliedListener listener) { + return applyAsync(context, parent, executor, listener, null); + } + } } |