OSDN Git Service

Merge "Don't even think about changing keyguard transit" into oc-dev
authorTreeHugger Robot <treehugger-gerrit@google.com>
Fri, 16 Jun 2017 01:04:09 +0000 (01:04 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Fri, 16 Jun 2017 01:04:15 +0000 (01:04 +0000)
44 files changed:
core/java/android/app/ActivityManagerInternal.java
core/java/android/os/Handler.java
core/java/android/os/Looper.java
core/java/android/os/MessageQueue.java
core/java/android/provider/Settings.java
media/jni/android_media_ImageReader.cpp
packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java
packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
packages/SystemUI/res/layout/tv_pip_controls.xml
packages/SystemUI/res/layout/tv_pip_custom_control.xml [new file with mode: 0644]
packages/SystemUI/res/values-tvdpi/dimens.xml
packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
packages/SystemUI/src/com/android/systemui/pip/tv/PipControlButtonView.java
packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java
packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
services/core/java/com/android/server/am/ActiveServices.java
services/core/java/com/android/server/am/ActivityManagerConstants.java
services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
services/core/java/com/android/server/am/ActivityManagerService.java
services/core/java/com/android/server/am/ActivityMetricsLogger.java
services/core/java/com/android/server/am/ActivityRecord.java
services/core/java/com/android/server/am/ActivityStackSupervisor.java
services/core/java/com/android/server/notification/NotificationManagerService.java
services/core/java/com/android/server/pm/PackageInstallerSession.java
services/core/java/com/android/server/pm/PackageManagerService.java
services/core/java/com/android/server/wm/AppWindowContainerController.java
services/core/java/com/android/server/wm/AppWindowContainerListener.java
services/core/java/com/android/server/wm/AppWindowToken.java
services/core/java/com/android/server/wm/TaskSnapshotSurface.java
services/core/java/com/android/server/wm/WindowAnimator.java
services/core/java/com/android/server/wm/WindowManagerService.java
services/core/java/com/android/server/wm/WindowStateAnimator.java
services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java

index d3b4b40..e5fe240 100644 (file)
@@ -24,6 +24,7 @@ import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.SystemClock;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.SparseIntArray;
 
@@ -134,8 +135,10 @@ public abstract class ActivityManagerInternal {
      *
      * @param reasons A map from stack id to a reason integer why the transition was started,, which
      *                must be one of the APP_TRANSITION_* values.
+     * @param timestamp The time at which the app transition started in
+     *                  {@link SystemClock#uptimeMillis()} timebase.
      */
-    public abstract void notifyAppTransitionStarting(SparseIntArray reasons);
+    public abstract void notifyAppTransitionStarting(SparseIntArray reasons, long timestamp);
 
     /**
      * Callback for window manager to let activity manager know that the app transition was
index 8678d95..b69a23a 100644 (file)
@@ -696,6 +696,14 @@ public class Handler {
     }
 
     /**
+     * Return whether there are any messages or callbacks currently scheduled on this handler.
+     * @hide
+     */
+    public final boolean hasMessagesOrCallbacks() {
+        return mQueue.hasMessages(this);
+    }
+
+    /**
      * Check if there are any pending posts of messages with code 'what' and
      * whose obj is 'object' in the message queue.
      */
@@ -728,6 +736,18 @@ public class Handler {
         }
     }
 
+    /**
+     * @hide
+     */
+    public final void dumpMine(Printer pw, String prefix) {
+        pw.println(prefix + this + " @ " + SystemClock.uptimeMillis());
+        if (mLooper == null) {
+            pw.println(prefix + "looper uninitialized");
+        } else {
+            mLooper.dump(pw, prefix + "  ", this);
+        }
+    }
+
     @Override
     public String toString() {
         return "Handler (" + getClass().getName() + ") {"
index 44dbcfb..04cceb8 100644 (file)
@@ -310,7 +310,20 @@ public final class Looper {
      */
     public void dump(@NonNull Printer pw, @NonNull String prefix) {
         pw.println(prefix + toString());
-        mQueue.dump(pw, prefix + "  ");
+        mQueue.dump(pw, prefix + "  ", null);
+    }
+
+    /**
+     * Dumps the state of the looper for debugging purposes.
+     *
+     * @param pw A printer to receive the contents of the dump.
+     * @param prefix A prefix to prepend to each line which is printed.
+     * @param handler Only dump messages for this Handler.
+     * @hide
+     */
+    public void dump(@NonNull Printer pw, @NonNull String prefix, Handler handler) {
+        pw.println(prefix + toString());
+        mQueue.dump(pw, prefix + "  ", handler);
     }
 
     /** @hide */
index 2a8c52e..624e28a 100644 (file)
@@ -620,6 +620,23 @@ public final class MessageQueue {
         }
     }
 
+    boolean hasMessages(Handler h) {
+        if (h == null) {
+            return false;
+        }
+
+        synchronized (this) {
+            Message p = mMessages;
+            while (p != null) {
+                if (p.target == h) {
+                    return true;
+                }
+                p = p.next;
+            }
+            return false;
+        }
+    }
+
     void removeMessages(Handler h, int what, Object object) {
         if (h == null) {
             return;
@@ -759,12 +776,14 @@ public final class MessageQueue {
         }
     }
 
-    void dump(Printer pw, String prefix) {
+    void dump(Printer pw, String prefix, Handler h) {
         synchronized (this) {
             long now = SystemClock.uptimeMillis();
             int n = 0;
             for (Message msg = mMessages; msg != null; msg = msg.next) {
-                pw.println(prefix + "Message " + n + ": " + msg.toString(now));
+                if (h == null || h == msg.target) {
+                    pw.println(prefix + "Message " + n + ": " + msg.toString(now));
+                }
                 n++;
             }
             pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
index f1ce9d5..65669ee 100755 (executable)
@@ -9029,7 +9029,10 @@ public final class Settings {
          * <pre>
          * max_cached_processes                 (int)
          * background_settle_time               (long)
-         * foreground_service_ui_min_time       (long)
+         * fgservice_min_shown_time             (long)
+         * fgservice_min_report_time            (long)
+         * fgservice_screen_on_before_time      (long)
+         * fgservice_screen_on_after_time       (long)
          * content_provider_retain_time         (long)
          * gc_timeout                           (long)
          * gc_min_interval                      (long)
index 163c4b0..f408e57 100644 (file)
@@ -177,6 +177,7 @@ BufferItem* JNIImageReaderContext::getBufferItem() {
 }
 
 void JNIImageReaderContext::returnBufferItem(BufferItem* buffer) {
+    buffer->mGraphicBuffer = nullptr;
     mBuffers.push_back(buffer);
 }
 
index 474de90..1cbb745 100644 (file)
@@ -88,21 +88,16 @@ public class ZoneGetter {
     private static final String XMLTAG_TIMEZONE = "timezone";
 
     public static CharSequence getTimeZoneOffsetAndName(Context context, TimeZone tz, Date now) {
-        final Locale locale = Locale.getDefault();
-        final CharSequence gmtText = getGmtOffsetText(context, locale, tz, now);
-        final TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
-        final ZoneGetterData data = new ZoneGetterData(context);
-
-        final boolean useExemplarLocationForLocalNames =
-                shouldUseExemplarLocationForLocalNames(data, timeZoneNames);
-        final CharSequence zoneName = getTimeZoneDisplayName(data, timeZoneNames,
-                useExemplarLocationForLocalNames, tz, tz.getID());
-        if (zoneName == null) {
+        Locale locale = Locale.getDefault();
+        CharSequence gmtText = getGmtOffsetText(context, locale, tz, now);
+        TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
+        String zoneNameString = getZoneLongName(timeZoneNames, tz, now);
+        if (zoneNameString == null) {
             return gmtText;
         }
 
         // We don't use punctuation here to avoid having to worry about localizing that too!
-        return TextUtils.concat(gmtText, " ", zoneName);
+        return TextUtils.concat(gmtText, " ", zoneNameString);
     }
 
     public static List<Map<String, Object>> getZonesList(Context context) {
index 40a59cf..fcc9090 100644 (file)
@@ -142,6 +142,7 @@ public class WifiTracker {
 
     @VisibleForTesting
     Scanner mScanner;
+    private boolean mStaleScanResults = false;
 
     public WifiTracker(Context context, WifiListener wifiListener,
             boolean includeSaved, boolean includeScans) {
@@ -330,7 +331,11 @@ public class WifiTracker {
      * Stop tracking wifi networks and scores.
      *
      * <p>This should always be called when done with a WifiTracker (if startTracking was called) to
-     * ensure proper cleanup and prevent any further callbacks from occuring.
+     * ensure proper cleanup and prevent any further callbacks from occurring.
+     *
+     * <p>Calling this method will set the {@link #mStaleScanResults} bit, which prevents
+     * {@link WifiListener#onAccessPointsChanged()} callbacks from being invoked (until the bit
+     * is unset on the next SCAN_RESULTS_AVAILABLE_ACTION).
      */
     @MainThread
     public void stopTracking() {
@@ -346,6 +351,7 @@ public class WifiTracker {
             mWorkHandler.removePendingMessages();
             mMainHandler.removePendingMessages();
         }
+        mStaleScanResults = true;
     }
 
     private void unregisterAndClearScoreCache() {
@@ -712,6 +718,11 @@ public class WifiTracker {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
+
+            if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
+                mStaleScanResults = false;
+            }
+
             if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
                 updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
                         WifiManager.WIFI_STATE_UNKNOWN));
@@ -822,7 +833,9 @@ public class WifiTracker {
 
             switch (msg.what) {
                 case MSG_UPDATE_ACCESS_POINTS:
-                    updateAccessPointsLocked();
+                    if (!mStaleScanResults) {
+                        updateAccessPointsLocked();
+                    }
                     break;
                 case MSG_UPDATE_NETWORK_INFO:
                     updateNetworkInfo((NetworkInfo) msg.obj);
index 703e9d2..a3345ee 100644 (file)
@@ -47,9 +47,9 @@ public class ZoneGetterTest {
     }
 
     @Test
-    public void getTimeZoneOffsetAndName_setLondon_returnLondon() {
-        // Check it will ends with 'London', not 'British Summer Time' or sth else
-        testTimeZoneOffsetAndNameInner(TIME_ZONE_LONDON_ID, "London");
+    public void getTimeZoneOffsetAndName_setLondon_returnBritishSummerTime() {
+        // Check it will ends with 'British Summer Time', not 'London' or sth else
+        testTimeZoneOffsetAndNameInner(TIME_ZONE_LONDON_ID, "British Summer Time");
     }
 
     @Test
index c526432..eb9a7f6 100644 (file)
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -748,4 +749,36 @@ public class WifiTrackerTest {
 
         verifyNoMoreInteractions(mockWifiListener);
     }
+
+    @Test
+    public void stopTrackingShouldSetStaleBitWhichPreventsCallbacksUntilNextScanResult()
+            throws Exception {
+        WifiTracker tracker = createMockedWifiTracker();
+        startTracking(tracker);
+        tracker.stopTracking();
+
+        CountDownLatch latch1 = new CountDownLatch(1);
+        tracker.mMainHandler.post(() -> {
+                latch1.countDown();
+        });
+        assertTrue("Latch 1 timed out", latch1.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
+
+        startTracking(tracker);
+
+        tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
+        tracker.mReceiver.onReceive(
+                mContext, new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION));
+        tracker.mReceiver.onReceive(
+                mContext, new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION));
+
+        CountDownLatch latch2 = new CountDownLatch(1);
+        tracker.mMainHandler.post(() -> {
+            latch2.countDown();
+        });
+        assertTrue("Latch 2 timed out", latch2.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
+
+        verify(mockWifiListener, never()).onAccessPointsChanged();
+
+        sendScanResultsAndProcess(tracker); // verifies onAccessPointsChanged is invoked
+    }
 }
index 61ac6f6..0b7bce1 100644 (file)
 
     <com.android.systemui.pip.tv.PipControlButtonView
         android:id="@+id/full_button"
-        android:layout_width="100dp"
+        android:layout_width="@dimen/picture_in_picture_button_width"
         android:layout_height="wrap_content"
         android:src="@drawable/ic_fullscreen_white_24dp"
         android:text="@string/pip_fullscreen" />
 
     <com.android.systemui.pip.tv.PipControlButtonView
         android:id="@+id/close_button"
-        android:layout_width="100dp"
+        android:layout_width="@dimen/picture_in_picture_button_width"
         android:layout_height="wrap_content"
-        android:layout_marginStart="-50dp"
+        android:layout_marginStart="@dimen/picture_in_picture_button_start_margin"
         android:src="@drawable/ic_close_white"
         android:text="@string/pip_close" />
 
     <com.android.systemui.pip.tv.PipControlButtonView
         android:id="@+id/play_pause_button"
-        android:layout_width="100dp"
+        android:layout_width="@dimen/picture_in_picture_button_width"
         android:layout_height="wrap_content"
-        android:layout_marginStart="-50dp"
+        android:layout_marginStart="@dimen/picture_in_picture_button_start_margin"
         android:src="@drawable/ic_pause_white"
         android:text="@string/pip_pause"
         android:visibility="gone" />
diff --git a/packages/SystemUI/res/layout/tv_pip_custom_control.xml b/packages/SystemUI/res/layout/tv_pip_custom_control.xml
new file mode 100644 (file)
index 0000000..dd0fce4
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<com.android.systemui.pip.tv.PipControlButtonView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/picture_in_picture_button_width"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="@dimen/picture_in_picture_button_start_margin" />
index 5327cee..4d978aa 100644 (file)
@@ -24,4 +24,8 @@
     <fraction name="battery_subpixel_smoothing_right">10%</fraction>
 
     <dimen name="battery_margin_bottom">1px</dimen>
+
+    <!-- The dimensions to user for picture-in-picture action buttons. -->
+    <dimen name="picture_in_picture_button_width">100dp</dimen>
+    <dimen name="picture_in_picture_button_start_margin">-50dp</dimen>
 </resources>
index 0f69f47..a5ee198 100644 (file)
@@ -427,11 +427,7 @@ public class PipMenuActivity extends Activity {
         } else {
             actionsContainer.setVisibility(View.VISIBLE);
             if (mActionsGroup != null) {
-                // Hide extra views
-                for (int i = mActions.size(); i < mActionsGroup.getChildCount(); i++) {
-                    mActionsGroup.getChildAt(i).setVisibility(View.GONE);
-                }
-                // Add needed views
+                // Ensure we have as many buttons as actions
                 final LayoutInflater inflater = LayoutInflater.from(this);
                 while (mActionsGroup.getChildCount() < mActions.size()) {
                     final ImageView actionView = (ImageView) inflater.inflate(
@@ -439,6 +435,13 @@ public class PipMenuActivity extends Activity {
                     mActionsGroup.addView(actionView);
                 }
 
+                // Update the visibility of all views
+                for (int i = 0; i < mActionsGroup.getChildCount(); i++) {
+                    mActionsGroup.getChildAt(i).setVisibility(i < mActions.size()
+                            ? View.VISIBLE
+                            : View.GONE);
+                }
+
                 // Recreate the layout
                 final boolean isLandscapePip = stackBounds != null &&
                         (stackBounds.width() > stackBounds.height());
@@ -460,10 +463,9 @@ public class PipMenuActivity extends Activity {
                                 Log.w(TAG, "Failed to send action", e);
                             }
                         });
-                    } else {
-                        actionView.setAlpha(DISABLED_ACTION_ALPHA);
                     }
                     actionView.setEnabled(action.isEnabled());
+                    actionView.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA);
 
                     // Update the margin between actions
                     LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
index 40a63d7..b21cd95 100644 (file)
@@ -20,6 +20,7 @@ import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -33,6 +34,7 @@ import com.android.systemui.R;
  * A view containing PIP controls including fullscreen, close, and media controls.
  */
 public class PipControlButtonView extends RelativeLayout {
+
     private OnFocusChangeListener mFocusChangeListener;
     private ImageView mIconImageView;
     ImageView mButtonImageView;
@@ -122,18 +124,37 @@ public class PipControlButtonView extends RelativeLayout {
     }
 
     /**
+     * Sets the drawable for the button with the given drawable.
+     */
+    public void setImageDrawable(Drawable d) {
+        mIconImageView.setImageDrawable(d);
+    }
+
+    /**
      * Sets the drawable for the button with the given resource id.
      */
     public void setImageResource(int resId) {
-        mIconImageView.setImageResource(resId);
+        if (resId != 0) {
+            mIconImageView.setImageResource(resId);
+        }
+    }
+
+    /**
+     * Sets the text for description the with the given string.
+     */
+    public void setText(CharSequence text) {
+        mButtonImageView.setContentDescription(text);
+        mDescriptionTextView.setText(text);
     }
 
     /**
      * Sets the text for description the with the given resource id.
      */
     public void setText(int resId) {
-        mButtonImageView.setContentDescription(getContext().getString(resId));
-        mDescriptionTextView.setText(resId);
+        if (resId != 0) {
+            mButtonImageView.setContentDescription(getContext().getString(resId));
+            mDescriptionTextView.setText(resId);
+        }
     }
 
     private static void cancelAnimator(Animator animator) {
index acea3b6..10206d4 100644 (file)
 
 package com.android.systemui.pip.tv;
 
+import android.app.ActivityManager;
+import android.app.PendingIntent.CanceledException;
+import android.app.RemoteAction;
 import android.content.Context;
+import android.graphics.Color;
 import android.media.session.MediaController;
 import android.media.session.PlaybackState;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
 import android.view.View;
 import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.util.AttributeSet;
 
@@ -30,11 +38,19 @@ import com.android.systemui.R;
 import static android.media.session.PlaybackState.ACTION_PAUSE;
 import static android.media.session.PlaybackState.ACTION_PLAY;
 
+import java.util.ArrayList;
+import java.util.List;
+
 
 /**
  * A view containing PIP controls including fullscreen, close, and media controls.
  */
 public class PipControlsView extends LinearLayout {
+
+    private static final String TAG = PipControlsView.class.getSimpleName();
+
+    private static final float DISABLED_ACTION_ALPHA = 0.54f;
+
     /**
      * An interface to listen user action.
      */
@@ -47,19 +63,23 @@ public class PipControlsView extends LinearLayout {
 
     private MediaController mMediaController;
 
-    final PipManager mPipManager = PipManager.getInstance();
-    Listener mListener;
+    private final PipManager mPipManager = PipManager.getInstance();
+    private final LayoutInflater mLayoutInflater;
+    private final Handler mHandler;
+    private Listener mListener;
 
     private PipControlButtonView mFullButtonView;
     private PipControlButtonView mCloseButtonView;
     private PipControlButtonView mPlayPauseButtonView;
+    private ArrayList<PipControlButtonView> mCustomButtonViews = new ArrayList<>();
+    private List<RemoteAction> mCustomActions = new ArrayList<>();
 
     private PipControlButtonView mFocusedChild;
 
     private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
         @Override
         public void onPlaybackStateChanged(PlaybackState state) {
-            updatePlayPauseView();
+            updateUserActions();
         }
     };
 
@@ -95,9 +115,10 @@ public class PipControlsView extends LinearLayout {
 
     public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        LayoutInflater inflater = (LayoutInflater) getContext()
+        mLayoutInflater = (LayoutInflater) getContext()
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        inflater.inflate(R.layout.tv_pip_controls, this);
+        mLayoutInflater.inflate(R.layout.tv_pip_controls, this);
+        mHandler = new Handler();
 
         setOrientation(LinearLayout.HORIZONTAL);
         setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
@@ -176,21 +197,74 @@ public class PipControlsView extends LinearLayout {
         if (mMediaController != null) {
             mMediaController.registerCallback(mMediaControllerCallback);
         }
-        updatePlayPauseView();
+        updateUserActions();
     }
 
-    private void updatePlayPauseView() {
-        int state = mPipManager.getPlaybackState();
-        if (state == PipManager.PLAYBACK_STATE_UNAVAILABLE) {
+    /**
+     * Updates the actions for the PIP. If there are no custom actions, then the media session
+     * actions are shown.
+     */
+    private void updateUserActions() {
+        if (!mCustomActions.isEmpty()) {
+            // Ensure we have as many buttons as actions
+            while (mCustomButtonViews.size() < mCustomActions.size()) {
+                PipControlButtonView buttonView = (PipControlButtonView) mLayoutInflater.inflate(
+                        R.layout.tv_pip_custom_control, this, false);
+                addView(buttonView);
+                mCustomButtonViews.add(buttonView);
+            }
+
+            // Update the visibility of all views
+            for (int i = 0; i < mCustomButtonViews.size(); i++) {
+                mCustomButtonViews.get(i).setVisibility(i < mCustomActions.size()
+                        ? View.VISIBLE
+                        : View.GONE);
+            }
+
+            // Update the state and visibility of the action buttons, and hide the rest
+            for (int i = 0; i < mCustomActions.size(); i++) {
+                final RemoteAction action = mCustomActions.get(i);
+                PipControlButtonView actionView = mCustomButtonViews.get(i);
+
+                // TODO: Check if the action drawable has changed before we reload it
+                action.getIcon().loadDrawableAsync(getContext(), d -> {
+                    d.setTint(Color.WHITE);
+                    actionView.setImageDrawable(d);
+                }, mHandler);
+                actionView.setText(action.getContentDescription());
+                if (action.isEnabled()) {
+                    actionView.setOnClickListener(v -> {
+                        try {
+                            action.getActionIntent().send();
+                        } catch (CanceledException e) {
+                            Log.w(TAG, "Failed to send action", e);
+                        }
+                    });
+                }
+                actionView.setEnabled(action.isEnabled());
+                actionView.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA);
+            }
+
+            // Hide the media session buttons
             mPlayPauseButtonView.setVisibility(View.GONE);
         } else {
-            mPlayPauseButtonView.setVisibility(View.VISIBLE);
-            if (state == PipManager.PLAYBACK_STATE_PLAYING) {
-                mPlayPauseButtonView.setImageResource(R.drawable.ic_pause_white);
-                mPlayPauseButtonView.setText(R.string.pip_pause);
+            int state = mPipManager.getPlaybackState();
+            if (state == PipManager.PLAYBACK_STATE_UNAVAILABLE) {
+                mPlayPauseButtonView.setVisibility(View.GONE);
             } else {
-                mPlayPauseButtonView.setImageResource(R.drawable.ic_play_arrow_white);
-                mPlayPauseButtonView.setText(R.string.pip_play);
+                mPlayPauseButtonView.setVisibility(View.VISIBLE);
+                if (state == PipManager.PLAYBACK_STATE_PLAYING) {
+                    mPlayPauseButtonView.setImageResource(R.drawable.ic_pause_white);
+                    mPlayPauseButtonView.setText(R.string.pip_pause);
+                } else {
+                    mPlayPauseButtonView.setImageResource(R.drawable.ic_play_arrow_white);
+                    mPlayPauseButtonView.setText(R.string.pip_play);
+                }
+            }
+
+            // Hide all the custom action buttons
+            for (int i = 0; i < mCustomButtonViews.size(); i++) {
+                mCustomButtonViews.get(i).setVisibility(View.GONE);
             }
         }
     }
@@ -203,6 +277,9 @@ public class PipControlsView extends LinearLayout {
         mCloseButtonView.reset();
         mPlayPauseButtonView.reset();
         mFullButtonView.requestFocus();
+        for (int i = 0; i < mCustomButtonViews.size(); i++) {
+            mCustomButtonViews.get(i).reset();
+        }
     }
 
     /**
@@ -213,6 +290,15 @@ public class PipControlsView extends LinearLayout {
     }
 
     /**
+     * Updates the set of activity-defined actions.
+     */
+    public void setActions(List<RemoteAction> actions) {
+        mCustomActions.clear();
+        mCustomActions.addAll(actions);
+        updateUserActions();
+    }
+
+    /**
      * Returns the focused control button view to animate focused button.
      */
     PipControlButtonView getFocusedButton() {
index f98310d..ca58080 100644 (file)
@@ -20,6 +20,7 @@ import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.StackInfo;
 import android.app.IActivityManager;
+import android.app.RemoteAction;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -124,6 +125,7 @@ public class PipManager implements BasePipManager {
     private MediaController mPipMediaController;
     private String[] mLastPackagesResourceGranted;
     private PipNotification mPipNotification;
+    private ParceledListSlice mCustomActions;
 
     private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
 
@@ -187,7 +189,14 @@ public class PipManager implements BasePipManager {
         }
 
         @Override
-        public void onActionsChanged(ParceledListSlice actions) {}
+        public void onActionsChanged(ParceledListSlice actions) {
+            mCustomActions = actions;
+            mHandler.post(() -> {
+                for (int i = mListeners.size() - 1; i >= 0; --i) {
+                    mListeners.get(i).onPipMenuActionsChanged(mCustomActions);
+                }
+            });
+        }
     }
 
     private PipManager() { }
@@ -432,6 +441,7 @@ public class PipManager implements BasePipManager {
         }
         Intent intent = new Intent(mContext, PipMenuActivity.class);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(PipMenuActivity.EXTRA_CUSTOM_ACTIONS, mCustomActions);
         mContext.startActivity(intent);
     }
 
@@ -690,6 +700,8 @@ public class PipManager implements BasePipManager {
         void onPipActivityClosed();
         /** Invoked when the PIP menu gets shown. */
         void onShowPipMenu();
+        /** Invoked when the PIP menu actions change. */
+        void onPipMenuActionsChanged(ParceledListSlice actions);
         /** Invoked when the PIPed activity is about to return back to the fullscreen. */
         void onMoveToFullscreen();
         /** Invoked when we are above to start resizing the Pip. */
index ce1bea1..82018ce 100644 (file)
@@ -19,22 +19,27 @@ package com.android.systemui.pip.tv;
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.ParceledListSlice;
 import android.os.Bundle;
 import android.view.View;
 
 import com.android.systemui.R;
 
+import java.util.Collections;
 /**
  * Activity to show the PIP menu to control PIP.
  */
 public class PipMenuActivity extends Activity implements PipManager.Listener {
     private static final String TAG = "PipMenuActivity";
 
+    static final String EXTRA_CUSTOM_ACTIONS = "custom_actions";
+
     private final PipManager mPipManager = PipManager.getInstance();
 
     private Animator mFadeInAnimation;
     private Animator mFadeOutAnimation;
-    private View mPipControlsView;
+    private PipControlsView mPipControlsView;
     private boolean mRestorePipSizeWhenClose;
 
     @Override
@@ -51,6 +56,15 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
         mFadeOutAnimation = AnimatorInflater.loadAnimator(
                 this, R.anim.tv_pip_menu_fade_out_animation);
         mFadeOutAnimation.setTarget(mPipControlsView);
+
+        onPipMenuActionsChanged(getIntent().getParcelableExtra(EXTRA_CUSTOM_ACTIONS));
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+
+        onPipMenuActionsChanged(getIntent().getParcelableExtra(EXTRA_CUSTOM_ACTIONS));
     }
 
     private void restorePipAndFinish() {
@@ -96,6 +110,12 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
     }
 
     @Override
+    public void onPipMenuActionsChanged(ParceledListSlice actions) {
+        boolean hasCustomActions = actions != null && !actions.getList().isEmpty();
+        mPipControlsView.setActions(hasCustomActions ? actions.getList() : Collections.EMPTY_LIST);
+    }
+
+    @Override
     public void onShowPipMenu() { }
 
     @Override
index c8f4185..f0745a0 100644 (file)
@@ -23,6 +23,7 @@ import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Icon;
@@ -81,6 +82,11 @@ public class PipNotification {
         }
 
         @Override
+        public void onPipMenuActionsChanged(ParceledListSlice actions) {
+            // no-op.
+        }
+
+        @Override
         public void onMoveToFullscreen() {
             dismissPipNotification();
         }
index bd59fb0..82e6a35 100644 (file)
@@ -106,6 +106,7 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
                     mPanel.setPanelScrimMinFraction((float) expandedHeight
                             / mPanel.getMaxPanelHeight());
                     mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight);
+                    mPanel.startExpandingFromPeek();
                     // This call needs to be after the expansion start otherwise we will get a
                     // flicker of one frame as it's not expanded yet.
                     mHeadsUpManager.unpinAll();
index b1d82b1..0b46c21 100644 (file)
@@ -406,6 +406,10 @@ public abstract class PanelView extends FrameLayout {
         return Math.abs(yDiff) >= Math.abs(xDiff);
     }
 
+    protected void startExpandingFromPeek() {
+        mStatusBar.handlePeekToExpandTransistion();
+    }
+
     protected void startExpandMotion(float newX, float newY, boolean startTracking,
             float expandedHeight) {
         mInitialOffsetOnTouch = expandedHeight;
index cfbdc92..74a7e51 100644 (file)
@@ -648,7 +648,7 @@ public class StatusBar extends SystemUI implements DemoMode,
 
     // Tracks notifications currently visible in mNotificationStackScroller and
     // emits visibility events via NoMan on changes.
-    private final Runnable mVisibilityReporter = new Runnable() {
+    protected final Runnable mVisibilityReporter = new Runnable() {
         private final ArraySet<NotificationVisibility> mTmpNewlyVisibleNotifications =
                 new ArraySet<>();
         private final ArraySet<NotificationVisibility> mTmpCurrentlyVisibleNotifications =
@@ -3755,6 +3755,17 @@ public class StatusBar extends SystemUI implements DemoMode,
         }
     }
 
+    void handlePeekToExpandTransistion() {
+        try {
+            // consider the transition from peek to expanded to be a panel open,
+            // but not one that clears notification effects.
+            int notificationLoad = mNotificationData.getActiveNotifications().size();
+            mBarService.onPanelRevealed(false, notificationLoad);
+        } catch (RemoteException ex) {
+            // Won't fail unless the world has ended.
+        }
+    }
+
     /**
      * The LEDs are turned off when the notification panel is shown, even just a little bit.
      * See also StatusBar.setPanelExpanded for another place where we attempt to do this.
@@ -3770,8 +3781,6 @@ public class StatusBar extends SystemUI implements DemoMode,
                 int notificationLoad = mNotificationData.getActiveNotifications().size();
                 if (pinnedHeadsUp && isPanelFullyCollapsed())  {
                     notificationLoad = 1;
-                } else {
-                    mMetricsLogger.histogram("note_load", notificationLoad);
                 }
                 mBarService.onPanelRevealed(clearNotificationEffects, notificationLoad);
             } else {
index db6647c..0e3ea7a 100644 (file)
@@ -20,37 +20,54 @@ import static android.app.NotificationManager.IMPORTANCE_HIGH;
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
+import static junit.framework.TestCase.fail;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
 
 import android.app.Notification;
 import android.metrics.LogMaker;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IPowerManager;
-import android.os.Looper;
+import android.os.Message;
 import android.os.PowerManager;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.support.test.filters.SmallTest;
 import android.support.test.metricshelper.MetricsAsserts;
 import android.support.test.runner.AndroidJUnit4;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.MessageHandler;
+import android.testing.TestableLooper.RunWithLooper;
 import android.util.DisplayMetrics;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.logging.testing.FakeMetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.keyguard.KeyguardHostView.OnDismissAction;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.NotificationData.Entry;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
@@ -58,21 +75,26 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+
 @SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
 public class StatusBarTest extends SysuiTestCase {
 
     StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     UnlockMethodCache mUnlockMethodCache;
     KeyguardIndicationController mKeyguardIndicationController;
     NotificationStackScrollLayout mStackScroller;
-    StatusBar mStatusBar;
+    TestableStatusBar mStatusBar;
     FakeMetricsLogger mMetricsLogger;
     HeadsUpManager mHeadsUpManager;
     NotificationData mNotificationData;
     PowerManager mPowerManager;
     SystemServicesProxy mSystemServicesProxy;
     NotificationPanelView mNotificationPanelView;
+    IStatusBarService mBarService;
+    ArrayList<Entry> mNotificationList;
     private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
 
     @Before
@@ -86,18 +108,20 @@ public class StatusBarTest extends SysuiTestCase {
         mNotificationData = mock(NotificationData.class);
         mSystemServicesProxy = mock(SystemServicesProxy.class);
         mNotificationPanelView = mock(NotificationPanelView.class);
+        mNotificationList = mock(ArrayList.class);
         IPowerManager powerManagerService = mock(IPowerManager.class);
         HandlerThread handlerThread = new HandlerThread("TestThread");
         handlerThread.start();
         mPowerManager = new PowerManager(mContext, powerManagerService,
                 new Handler(handlerThread.getLooper()));
         when(powerManagerService.isInteractive()).thenReturn(true);
+        mBarService = mock(IStatusBarService.class);
 
         mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
         mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, mUnlockMethodCache,
                 mKeyguardIndicationController, mStackScroller, mHeadsUpManager,
-                mNotificationData, mPowerManager, mSystemServicesProxy, mNotificationPanelView);
-
+                mNotificationData, mPowerManager, mSystemServicesProxy, mNotificationPanelView,
+                mBarService);
         doAnswer(invocation -> {
             OnDismissAction onDismissAction = (OnDismissAction) invocation.getArguments()[0];
             onDismissAction.onDismiss();
@@ -111,6 +135,15 @@ public class StatusBarTest extends SysuiTestCase {
         }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
 
         when(mStackScroller.getActivatedChild()).thenReturn(null);
+        TestableLooper.get(this).setMessageHandler(new MessageHandler() {
+            @Override
+            public boolean onMessageHandled(Message m) {
+                if (m.getCallback() == mStatusBar.mVisibilityReporter) {
+                    return false;
+                }
+                return true;
+            }
+        });
     }
 
     @Test
@@ -284,11 +317,80 @@ public class StatusBarTest extends SysuiTestCase {
         assertFalse(mStatusBar.shouldPeek(entry, sbn));
     }
 
+    @Test
+    public void testLogHidden() {
+        try {
+            mStatusBar.handleVisibleToUserChanged(false);
+            verify(mBarService, times(1)).onPanelHidden();
+            verify(mBarService, never()).onPanelRevealed(anyBoolean(), anyInt());
+        } catch (RemoteException e) {
+            fail();
+        }
+    }
+
+    @Test
+    public void testPanelOpenForPeek() {
+        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
+        when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
+        when(mNotificationList.size()).thenReturn(5);
+        when(mNotificationPanelView.isFullyCollapsed()).thenReturn(true);
+        mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+
+        try {
+            mStatusBar.handleVisibleToUserChanged(true);
+
+            verify(mBarService, never()).onPanelHidden();
+            verify(mBarService, times(1)).onPanelRevealed(false, 1);
+        } catch (RemoteException e) {
+            fail();
+        }
+        TestableLooper.get(this).processAllMessages();
+    }
+
+    @Test
+    public void testPanelOpenAndClear() {
+        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
+        when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
+        when(mNotificationList.size()).thenReturn(5);
+        when(mNotificationPanelView.isFullyCollapsed()).thenReturn(false);
+        mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+
+        try {
+            mStatusBar.handleVisibleToUserChanged(true);
+
+            verify(mBarService, never()).onPanelHidden();
+            verify(mBarService, times(1)).onPanelRevealed(true, 5);
+        } catch (RemoteException e) {
+            fail();
+        }
+        TestableLooper.get(this).processAllMessages();
+    }
+
+    @Test
+    public void testPanelOpenAndNoClear() {
+        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
+        when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
+        when(mNotificationList.size()).thenReturn(5);
+        when(mNotificationPanelView.isFullyCollapsed()).thenReturn(false);
+        mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
+
+        try {
+            mStatusBar.handleVisibleToUserChanged(true);
+
+            verify(mBarService, never()).onPanelHidden();
+            verify(mBarService, times(1)).onPanelRevealed(false, 5);
+        } catch (RemoteException e) {
+            fail();
+        }
+        TestableLooper.get(this).processAllMessages();
+    }
+
     static class TestableStatusBar extends StatusBar {
         public TestableStatusBar(StatusBarKeyguardViewManager man,
                 UnlockMethodCache unlock, KeyguardIndicationController key,
                 NotificationStackScrollLayout stack, HeadsUpManager hum, NotificationData nd,
-                PowerManager pm, SystemServicesProxy ssp, NotificationPanelView panelView) {
+                PowerManager pm, SystemServicesProxy ssp, NotificationPanelView panelView,
+                IStatusBarService barService) {
             mStatusBarKeyguardViewManager = man;
             mUnlockMethodCache = unlock;
             mKeyguardIndicationController = key;
@@ -299,11 +401,11 @@ public class StatusBarTest extends SysuiTestCase {
             mPowerManager = pm;
             mSystemServicesProxy = ssp;
             mNotificationPanel = panelView;
+            mBarService = barService;
         }
 
-        @Override
-        protected H createHandler() {
-            return null;
+        public void setBarStateForTest(int state) {
+            mState = state;
         }
     }
 }
\ No newline at end of file
index 73f1705..4810f4f 100644 (file)
@@ -47,6 +47,7 @@ import android.os.IBinder;
 import android.os.IDeviceIdleController;
 import android.os.IInterface;
 import android.os.Parcel;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -345,7 +346,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
     }
 
     private static boolean isCallerSystem() {
-        return getCallingUserId() == UserHandle.USER_SYSTEM;
+        return Binder.getCallingUid() == Process.SYSTEM_UID;
     }
 
     private ServiceConnection createServiceConnection(
index c417484..756e274 100644 (file)
@@ -81,6 +81,7 @@ import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.EventLog;
+import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -175,6 +176,9 @@ public final class ActiveServices {
         long mStartVisibleTime;
         long mEndTime;
         int mNumActive;
+
+        // Temp output of foregroundAppShownEnoughLocked
+        long mHideTime;
     }
 
     /**
@@ -622,19 +626,19 @@ public final class ActiveServices {
                             != ActivityManager.APP_START_MODE_NORMAL) {
                         if (stopping == null) {
                             stopping = new ArrayList<>();
-                            String compName = service.name.flattenToShortString();
-                            EventLogTags.writeAmStopIdleService(service.appInfo.uid, compName);
-                            StringBuilder sb = new StringBuilder(64);
-                            sb.append("Stopping service due to app idle: ");
-                            UserHandle.formatUid(sb, service.appInfo.uid);
-                            sb.append(" ");
-                            TimeUtils.formatDuration(service.createTime
-                                    - SystemClock.elapsedRealtime(), sb);
-                            sb.append(" ");
-                            sb.append(compName);
-                            Slog.w(TAG, sb.toString());
-                            stopping.add(service);
                         }
+                        String compName = service.name.flattenToShortString();
+                        EventLogTags.writeAmStopIdleService(service.appInfo.uid, compName);
+                        StringBuilder sb = new StringBuilder(64);
+                        sb.append("Stopping service due to app idle: ");
+                        UserHandle.formatUid(sb, service.appInfo.uid);
+                        sb.append(" ");
+                        TimeUtils.formatDuration(service.createTime
+                                - SystemClock.elapsedRealtime(), sb);
+                        sb.append(" ");
+                        sb.append(compName);
+                        Slog.w(TAG, sb.toString());
+                        stopping.add(service);
                     }
                 }
             }
@@ -736,50 +740,90 @@ public final class ActiveServices {
         }
     }
 
+    boolean foregroundAppShownEnoughLocked(ActiveForegroundApp aa, long nowElapsed) {
+        if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Shown enough: pkg=" + aa.mPackageName + ", uid="
+                + aa.mUid);
+        boolean canRemove = false;
+        aa.mHideTime = Long.MAX_VALUE;
+        if (aa.mShownWhileTop) {
+            // If the app was ever at the top of the screen while the foreground
+            // service was running, then we can always just immediately remove it.
+            canRemove = true;
+            if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "YES - shown while on top");
+        } else if (mScreenOn || aa.mShownWhileScreenOn) {
+            final long minTime = aa.mStartVisibleTime
+                    + (aa.mStartTime != aa.mStartVisibleTime
+                            ? mAm.mConstants.FGSERVICE_SCREEN_ON_AFTER_TIME
+                            : mAm.mConstants.FGSERVICE_MIN_SHOWN_TIME);
+            if (nowElapsed >= minTime) {
+                // If shown while the screen is on, and it has been shown for
+                // at least the minimum show time, then we can now remove it.
+                if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "YES - shown long enough with screen on");
+                canRemove = true;
+            } else {
+                // This is when we will be okay to stop telling the user.
+                long reportTime = nowElapsed + mAm.mConstants.FGSERVICE_MIN_REPORT_TIME;
+                aa.mHideTime = reportTime > minTime ? reportTime : minTime;
+                if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "NO -- wait " + (aa.mHideTime-nowElapsed)
+                        + " with screen on");
+            }
+        } else {
+            final long minTime = aa.mEndTime
+                    + mAm.mConstants.FGSERVICE_SCREEN_ON_BEFORE_TIME;
+            if (nowElapsed >= minTime) {
+                // If the foreground service has only run while the screen is
+                // off, but it has been gone now for long enough that we won't
+                // care to tell the user about it when the screen comes back on,
+                // then we can remove it now.
+                if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "YES - gone long enough with screen off");
+                canRemove = true;
+            } else {
+                // This is when we won't care about this old fg service.
+                aa.mHideTime = minTime;
+                if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "NO -- wait " + (aa.mHideTime-nowElapsed)
+                        + " with screen off");
+            }
+        }
+        return canRemove;
+    }
+
     void updateForegroundApps(ServiceMap smap) {
         // This is called from the handler without the lock held.
         ArrayList<ActiveForegroundApp> active = null;
         synchronized (mAm) {
             final long now = SystemClock.elapsedRealtime();
-            final long nowPlusMin = now + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME;
             long nextUpdateTime = Long.MAX_VALUE;
             if (smap != null) {
+                if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Updating foreground apps for user "
+                        + smap.mUserId);
                 for (int i = smap.mActiveForegroundApps.size()-1; i >= 0; i--) {
                     ActiveForegroundApp aa = smap.mActiveForegroundApps.valueAt(i);
-                    if (aa.mEndTime != 0 && (mScreenOn || aa.mShownWhileScreenOn)) {
-                        if (!aa.mShownWhileTop && aa.mEndTime < (aa.mStartVisibleTime
-                                + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME)) {
-                            // Check to see if this should still be displayed...  we continue
-                            // until it has been shown for at least the timeout duration.
-                            if (nowPlusMin >= aa.mStartVisibleTime) {
-                                // All over!
-                                smap.mActiveForegroundApps.removeAt(i);
-                                smap.mActiveForegroundAppsChanged = true;
-                                continue;
-                            } else {
-                                long hideTime = aa.mStartVisibleTime
-                                        + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME;
-                                if (hideTime < nextUpdateTime) {
-                                    nextUpdateTime = hideTime;
-                                }
-                            }
-                        } else {
+                    if (aa.mEndTime != 0) {
+                        boolean canRemove = foregroundAppShownEnoughLocked(aa, now);
+                        if (canRemove) {
                             // This was up for longer than the timeout, so just remove immediately.
                             smap.mActiveForegroundApps.removeAt(i);
                             smap.mActiveForegroundAppsChanged = true;
                             continue;
                         }
+                        if (aa.mHideTime < nextUpdateTime) {
+                            nextUpdateTime = aa.mHideTime;
+                        }
                     }
                     if (!aa.mAppOnTop) {
                         if (active == null) {
                             active = new ArrayList<>();
                         }
+                        if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Adding active: pkg="
+                                + aa.mPackageName + ", uid=" + aa.mUid);
                         active.add(aa);
                     }
                 }
                 smap.removeMessages(ServiceMap.MSG_UPDATE_FOREGROUND_APPS);
                 if (nextUpdateTime < Long.MAX_VALUE) {
-                    Message msg = smap.obtainMessage();
+                    if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Next update time in: "
+                            + (nextUpdateTime-now));
+                    Message msg = smap.obtainMessage(ServiceMap.MSG_UPDATE_FOREGROUND_APPS);
                     smap.sendMessageAtTime(msg, nextUpdateTime
                             + SystemClock.uptimeMillis() - SystemClock.elapsedRealtime());
                 }
@@ -882,15 +926,14 @@ public final class ActiveServices {
             active.mNumActive--;
             if (active.mNumActive <= 0) {
                 active.mEndTime = SystemClock.elapsedRealtime();
-                if (active.mShownWhileTop || active.mEndTime >= (active.mStartVisibleTime
-                        + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME)) {
+                if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Ended running of service");
+                if (foregroundAppShownEnoughLocked(active, active.mEndTime)) {
                     // Have been active for long enough that we will remove it immediately.
                     smap.mActiveForegroundApps.remove(r.packageName);
                     smap.mActiveForegroundAppsChanged = true;
                     requestUpdateActiveForegroundAppsLocked(smap, 0);
-                } else {
-                    requestUpdateActiveForegroundAppsLocked(smap, active.mStartVisibleTime
-                            + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME);
+                } else if (active.mHideTime < Long.MAX_VALUE){
+                    requestUpdateActiveForegroundAppsLocked(smap, active.mHideTime);
                 }
             }
         }
@@ -904,26 +947,44 @@ public final class ActiveServices {
             // services that were started while the screen was off.
             if (screenOn) {
                 final long nowElapsed = SystemClock.elapsedRealtime();
+                if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Screen turned on");
                 for (int i = mServiceMap.size()-1; i >= 0; i--) {
                     ServiceMap smap = mServiceMap.valueAt(i);
+                    long nextUpdateTime = Long.MAX_VALUE;
                     boolean changed = false;
                     for (int j = smap.mActiveForegroundApps.size()-1; j >= 0; j--) {
                         ActiveForegroundApp active = smap.mActiveForegroundApps.valueAt(j);
-                        if (!active.mShownWhileScreenOn) {
-                            changed = true;
-                            active.mShownWhileScreenOn = mScreenOn;
-                            active.mStartVisibleTime = nowElapsed;
-                            if (active.mEndTime != 0) {
-                                active.mEndTime = nowElapsed;
+                        if (active.mEndTime == 0) {
+                            if (!active.mShownWhileScreenOn) {
+                                active.mShownWhileScreenOn = true;
+                                active.mStartVisibleTime = nowElapsed;
+                            }
+                        } else {
+                            if (!active.mShownWhileScreenOn
+                                    && active.mStartVisibleTime == active.mStartTime) {
+                                // If this was never shown while the screen was on, then we will
+                                // count the time it started being visible as now, to tell the user
+                                // about it now that they have a screen to look at.
+                                active.mEndTime = active.mStartVisibleTime = nowElapsed;
+                            }
+                            if (foregroundAppShownEnoughLocked(active, nowElapsed)) {
+                                // Have been active for long enough that we will remove it
+                                // immediately.
+                                smap.mActiveForegroundApps.remove(active.mPackageName);
+                                smap.mActiveForegroundAppsChanged = true;
+                                changed = true;
+                            } else {
+                                if (active.mHideTime < nextUpdateTime) {
+                                    nextUpdateTime = active.mHideTime;
+                                }
                             }
                         }
                     }
                     if (changed) {
-                        requestUpdateActiveForegroundAppsLocked(smap,
-                                nowElapsed + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME);
-                    } else if (smap.mActiveForegroundApps.size() > 0) {
-                        // Just being paranoid.
+                        // Need to immediately update.
                         requestUpdateActiveForegroundAppsLocked(smap, 0);
+                    } else if (nextUpdateTime < Long.MAX_VALUE) {
+                        requestUpdateActiveForegroundAppsLocked(smap, nextUpdateTime);
                     }
                 }
             }
@@ -2318,7 +2379,7 @@ public final class ActiveServices {
             return true;
         }
 
-        // Is someone still bound to us keepign us running?
+        // Is someone still bound to us keeping us running?
         if (!knowConn) {
             hasConn = r.hasAutoCreateConnections();
         }
@@ -3741,6 +3802,17 @@ public final class ActiveServices {
                             pw.println();
                         }
                     }
+                    if (smap.hasMessagesOrCallbacks()) {
+                        if (needSep) {
+                            pw.println();
+                        }
+                        printedAnything = true;
+                        needSep = true;
+                        pw.print("  Handler - user ");
+                        pw.print(user);
+                        pw.println(":");
+                        smap.dumpMine(new PrintWriterPrinter(pw), "    ");
+                    }
                 }
             }
 
index 5749f31..6c3fe91 100644 (file)
@@ -35,8 +35,14 @@ final class ActivityManagerConstants extends ContentObserver {
     // Key names stored in the settings value.
     private static final String KEY_MAX_CACHED_PROCESSES = "max_cached_processes";
     private static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time";
-    private static final String KEY_FOREGROUND_SERVICE_UI_MIN_TIME
-            = "foreground_service_ui_min_time";
+    private static final String KEY_FGSERVICE_MIN_SHOWN_TIME
+            = "fgservice_min_shown_time";
+    private static final String KEY_FGSERVICE_MIN_REPORT_TIME
+            = "fgservice_min_report_time";
+    private static final String KEY_FGSERVICE_SCREEN_ON_BEFORE_TIME
+            = "fgservice_screen_on_before_time";
+    private static final String KEY_FGSERVICE_SCREEN_ON_AFTER_TIME
+            = "fgservice_screen_on_after_time";
     private static final String KEY_CONTENT_PROVIDER_RETAIN_TIME = "content_provider_retain_time";
     private static final String KEY_GC_TIMEOUT = "gc_timeout";
     private static final String KEY_GC_MIN_INTERVAL = "gc_min_interval";
@@ -58,7 +64,10 @@ final class ActivityManagerConstants extends ContentObserver {
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
     private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
-    private static final long DEFAULT_FOREGROUND_SERVICE_UI_MIN_TIME = 30*1000;
+    private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
+    private static final long DEFAULT_FGSERVICE_MIN_REPORT_TIME = 3*1000;
+    private static final long DEFAULT_FGSERVICE_SCREEN_ON_BEFORE_TIME = 1*1000;
+    private static final long DEFAULT_FGSERVICE_SCREEN_ON_AFTER_TIME = 5*1000;
     private static final long DEFAULT_CONTENT_PROVIDER_RETAIN_TIME = 20*1000;
     private static final long DEFAULT_GC_TIMEOUT = 5*1000;
     private static final long DEFAULT_GC_MIN_INTERVAL = 60*1000;
@@ -85,8 +94,26 @@ final class ActivityManagerConstants extends ContentObserver {
     // before we start restricting what it can do.
     public long BACKGROUND_SETTLE_TIME = DEFAULT_BACKGROUND_SETTLE_TIME;
 
-    // The minimum time a foreground service will be shown as running in the notification UI.
-    public long FOREGROUND_SERVICE_UI_MIN_TIME = DEFAULT_FOREGROUND_SERVICE_UI_MIN_TIME;
+    // The minimum time we allow a foreground service to run with a notification and the
+    // screen on without otherwise telling the user about it.  (If it runs for less than this,
+    // it will still be reported to the user as a running app for at least this amount of time.)
+    public long FGSERVICE_MIN_SHOWN_TIME = DEFAULT_FGSERVICE_MIN_SHOWN_TIME;
+
+    // If a foreground service is shown for less than FGSERVICE_MIN_SHOWN_TIME, we will display
+    // the background app running notification about it for at least this amount of time (if it
+    // is larger than the remaining shown time).
+    public long FGSERVICE_MIN_REPORT_TIME = DEFAULT_FGSERVICE_MIN_REPORT_TIME;
+
+    // The minimum amount of time the foreground service needs to have remain being shown
+    // before the screen goes on for us to consider it not worth showing to the user.  That is
+    // if an app has a foreground service that stops itself this amount of time or more before
+    // the user turns on the screen, we will just let it go without the user being told about it.
+    public long FGSERVICE_SCREEN_ON_BEFORE_TIME = DEFAULT_FGSERVICE_SCREEN_ON_BEFORE_TIME;
+
+    // The minimum amount of time a foreground service should remain reported to the user if
+    // it is stopped when the screen turns on.  This is the time from when the screen turns
+    // on until we will stop reporting it.
+    public long FGSERVICE_SCREEN_ON_AFTER_TIME = DEFAULT_FGSERVICE_SCREEN_ON_AFTER_TIME;
 
     // How long we will retain processes hosting content providers in the "last activity"
     // state before allowing them to drop down to the regular cached LRU list.  This is
@@ -225,8 +252,14 @@ final class ActivityManagerConstants extends ContentObserver {
                     DEFAULT_MAX_CACHED_PROCESSES);
             BACKGROUND_SETTLE_TIME = mParser.getLong(KEY_BACKGROUND_SETTLE_TIME,
                     DEFAULT_BACKGROUND_SETTLE_TIME);
-            FOREGROUND_SERVICE_UI_MIN_TIME = mParser.getLong(KEY_FOREGROUND_SERVICE_UI_MIN_TIME,
-                    DEFAULT_FOREGROUND_SERVICE_UI_MIN_TIME);
+            FGSERVICE_MIN_SHOWN_TIME = mParser.getLong(KEY_FGSERVICE_MIN_SHOWN_TIME,
+                    DEFAULT_FGSERVICE_MIN_SHOWN_TIME);
+            FGSERVICE_MIN_REPORT_TIME = mParser.getLong(KEY_FGSERVICE_MIN_REPORT_TIME,
+                    DEFAULT_FGSERVICE_MIN_REPORT_TIME);
+            FGSERVICE_SCREEN_ON_BEFORE_TIME = mParser.getLong(KEY_FGSERVICE_SCREEN_ON_BEFORE_TIME,
+                    DEFAULT_FGSERVICE_SCREEN_ON_BEFORE_TIME);
+            FGSERVICE_SCREEN_ON_AFTER_TIME = mParser.getLong(KEY_FGSERVICE_SCREEN_ON_AFTER_TIME,
+                    DEFAULT_FGSERVICE_SCREEN_ON_AFTER_TIME);
             CONTENT_PROVIDER_RETAIN_TIME = mParser.getLong(KEY_CONTENT_PROVIDER_RETAIN_TIME,
                     DEFAULT_CONTENT_PROVIDER_RETAIN_TIME);
             GC_TIMEOUT = mParser.getLong(KEY_GC_TIMEOUT,
@@ -284,8 +317,14 @@ final class ActivityManagerConstants extends ContentObserver {
         pw.println(MAX_CACHED_PROCESSES);
         pw.print("  "); pw.print(KEY_BACKGROUND_SETTLE_TIME); pw.print("=");
         pw.println(BACKGROUND_SETTLE_TIME);
-        pw.print("  "); pw.print(KEY_FOREGROUND_SERVICE_UI_MIN_TIME); pw.print("=");
-        pw.println(FOREGROUND_SERVICE_UI_MIN_TIME);
+        pw.print("  "); pw.print(KEY_FGSERVICE_MIN_SHOWN_TIME); pw.print("=");
+        pw.println(FGSERVICE_MIN_SHOWN_TIME);
+        pw.print("  "); pw.print(KEY_FGSERVICE_MIN_REPORT_TIME); pw.print("=");
+        pw.println(FGSERVICE_MIN_REPORT_TIME);
+        pw.print("  "); pw.print(KEY_FGSERVICE_SCREEN_ON_BEFORE_TIME); pw.print("=");
+        pw.println(FGSERVICE_SCREEN_ON_BEFORE_TIME);
+        pw.print("  "); pw.print(KEY_FGSERVICE_SCREEN_ON_AFTER_TIME); pw.print("=");
+        pw.println(FGSERVICE_SCREEN_ON_AFTER_TIME);
         pw.print("  "); pw.print(KEY_CONTENT_PROVIDER_RETAIN_TIME); pw.print("=");
         pw.println(CONTENT_PROVIDER_RETAIN_TIME);
         pw.print("  "); pw.print(KEY_GC_TIMEOUT); pw.print("=");
index ff5efde..f440100 100644 (file)
@@ -79,6 +79,7 @@ class ActivityManagerDebugConfig {
     static final boolean DEBUG_SAVED_STATE = DEBUG_ALL_ACTIVITIES || false;
     static final boolean DEBUG_SCREENSHOTS = DEBUG_ALL_ACTIVITIES || false;
     static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
+    static final boolean DEBUG_FOREGROUND_SERVICE = DEBUG_ALL || false;
     static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
     static final boolean DEBUG_STACK = DEBUG_ALL || false;
     static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false;
index ac68a9e..4d44b63 100644 (file)
@@ -10254,11 +10254,11 @@ public class ActivityManagerService extends IActivityManager.Stub
 
         if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
         synchronized(this) {
-            moveTaskToFrontLocked(taskId, flags, bOptions);
+            moveTaskToFrontLocked(taskId, flags, bOptions, false /* fromRecents */);
         }
     }
 
-    void moveTaskToFrontLocked(int taskId, int flags, Bundle bOptions) {
+    void moveTaskToFrontLocked(int taskId, int flags, Bundle bOptions, boolean fromRecents) {
         ActivityOptions options = ActivityOptions.fromBundle(bOptions);
 
         if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
@@ -10291,7 +10291,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                 // We are reshowing a task, use a starting window to hide the initial draw delay
                 // so the transition can start earlier.
                 topActivity.showStartingWindow(null /* prev */, false /* newTask */,
-                        true /* taskSwitch */);
+                        true /* taskSwitch */, fromRecents);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -23752,9 +23752,10 @@ public class ActivityManagerService extends IActivityManager.Stub
         }
 
         @Override
-        public void notifyAppTransitionStarting(SparseIntArray reasons) {
+        public void notifyAppTransitionStarting(SparseIntArray reasons, long timestamp) {
             synchronized (ActivityManagerService.this) {
-                mStackSupervisor.mActivityMetricsLogger.notifyTransitionStarting(reasons);
+                mStackSupervisor.mActivityMetricsLogger.notifyTransitionStarting(
+                        reasons, timestamp);
             }
         }
 
index bf7b663..98815d7 100644 (file)
@@ -230,12 +230,12 @@ class ActivityMetricsLogger {
     /**
      * Notifies the tracker that all windows of the app have been drawn.
      */
-    void notifyWindowsDrawn(int stackId) {
+    void notifyWindowsDrawn(int stackId, long timestamp) {
         final StackTransitionInfo info = mStackTransitionInfo.get(stackId);
         if (info == null || info.loggedWindowsDrawn) {
             return;
         }
-        info.windowsDrawnDelayMs = calculateCurrentDelay();
+        info.windowsDrawnDelayMs = calculateDelay(timestamp);
         info.loggedWindowsDrawn = true;
         if (allStacksWindowsDrawn() && mLoggedTransitionStarting) {
             reset(false /* abort */);
@@ -245,13 +245,13 @@ class ActivityMetricsLogger {
     /**
      * Notifies the tracker that the starting window was drawn.
      */
-    void notifyStartingWindowDrawn(int stackId) {
+    void notifyStartingWindowDrawn(int stackId, long timestamp) {
         final StackTransitionInfo info = mStackTransitionInfo.get(stackId);
         if (info == null || info.loggedStartingWindowDrawn) {
             return;
         }
         info.loggedStartingWindowDrawn = true;
-        info.startingWindowDelayMs = calculateCurrentDelay();
+        info.startingWindowDelayMs = calculateDelay(timestamp);
     }
 
     /**
@@ -260,11 +260,11 @@ class ActivityMetricsLogger {
      * @param stackIdReasons A map from stack id to a reason integer, which must be on of
      *                       ActivityManagerInternal.APP_TRANSITION_* reasons.
      */
-    void notifyTransitionStarting(SparseIntArray stackIdReasons) {
+    void notifyTransitionStarting(SparseIntArray stackIdReasons, long timestamp) {
         if (!isAnyTransitionActive() || mLoggedTransitionStarting) {
             return;
         }
-        mCurrentTransitionDelayMs = calculateCurrentDelay();
+        mCurrentTransitionDelayMs = calculateDelay(timestamp);
         mLoggedTransitionStarting = true;
         for (int index = stackIdReasons.size() - 1; index >= 0; index--) {
             final int stackId = stackIdReasons.keyAt(index);
@@ -344,6 +344,11 @@ class ActivityMetricsLogger {
         return (int) (SystemClock.uptimeMillis() - mCurrentTransitionStartTime);
     }
 
+    private int calculateDelay(long timestamp) {
+        // Shouldn't take more than 25 days to launch an app, so int is fine here.
+        return (int) (timestamp - mCurrentTransitionStartTime);
+    }
+
     private void logAppTransitionMultiEvents() {
         for (int index = mStackTransitionInfo.size() - 1; index >= 0; index--) {
             final StackTransitionInfo info = mStackTransitionInfo.valueAt(index);
index ec6a4f6..68f4d0d 100644 (file)
@@ -1928,18 +1928,19 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
     }
 
     @Override
-    public void onStartingWindowDrawn() {
+    public void onStartingWindowDrawn(long timestamp) {
         synchronized (service) {
-            mStackSupervisor.mActivityMetricsLogger.notifyStartingWindowDrawn(getStackId());
+            mStackSupervisor.mActivityMetricsLogger.notifyStartingWindowDrawn(
+                    getStackId(), timestamp);
         }
     }
 
     @Override
-    public void onWindowsDrawn() {
+    public void onWindowsDrawn(long timestamp) {
         synchronized (service) {
-            mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn(getStackId());
+            mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn(getStackId(), timestamp);
             if (displayStartTime != 0) {
-                reportLaunchTimeLocked(SystemClock.uptimeMillis());
+                reportLaunchTimeLocked(timestamp);
             }
             mStackSupervisor.sendWaitingVisibleReportLocked(this);
             startTime = 0;
@@ -2153,6 +2154,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
     }
 
     void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) {
+        showStartingWindow(prev, newTask, taskSwitch, false /* fromRecents */);
+    }
+
+    void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
+            boolean fromRecents) {
         if (mWindowContainerController == null) {
             return;
         }
@@ -2167,7 +2173,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
                 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
                 prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
                 allowTaskSnapshot(),
-                state.ordinal() >= RESUMED.ordinal() && state.ordinal() <= STOPPED.ordinal());
+                state.ordinal() >= RESUMED.ordinal() && state.ordinal() <= STOPPED.ordinal(),
+                fromRecents);
         if (shown) {
             mStartingWindowState = STARTING_WINDOW_SHOWN;
         }
index 53afe78..7de56fa 100644 (file)
@@ -5131,7 +5131,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
                     && task.getRootActivity() != null) {
                 mService.mActivityStarter.sendPowerHintForLaunchStartIfNeeded(true /* forceSend */);
                 mActivityMetricsLogger.notifyActivityLaunching();
-                mService.moveTaskToFrontLocked(task.taskId, 0, bOptions);
+                mService.moveTaskToFrontLocked(task.taskId, 0, bOptions, true /* fromRecents */);
                 mActivityMetricsLogger.notifyActivityLaunched(ActivityManager.START_TASK_TO_FRONT,
                         task.getTopActivity());
 
index 19d5f3c..61d69f9 100644 (file)
@@ -607,7 +607,7 @@ public class NotificationManagerService extends SystemService {
         @Override
         public void onPanelRevealed(boolean clearEffects, int items) {
             MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
-            MetricsLogger.histogram(getContext(), "notification_load", items);
+            MetricsLogger.histogram(getContext(), "note_load", items);
             EventLogTags.writeNotificationPanelRevealed(items);
             if (clearEffects) {
                 clearEffects();
index 4540d2d..f111db1 100644 (file)
@@ -856,8 +856,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
 
                         mResolvedInstructionSets.add(archSubDir.getName());
                         List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
-                        if (!oatFiles.isEmpty()) {
-                            mResolvedInheritedFiles.addAll(oatFiles);
+
+                        // Only add compiled files associated with the base.
+                        // Once b/62269291 is resolved, we can add all compiled files again.
+                        for (File oatFile : oatFiles) {
+                            if (oatFile.getName().equals("base.art")
+                                    || oatFile.getName().equals("base.odex")
+                                    || oatFile.getName().equals("base.vdex")) {
+                                mResolvedInheritedFiles.add(oatFile);
+                            }
                         }
                     }
                 }
index 07d548d..5f96b91 100644 (file)
@@ -19309,7 +19309,7 @@ public class PackageManagerService extends IPackageManager.Stub
         synchronized (mPackages) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
             if (ps == null || filterAppAccessLPr(ps, Binder.getCallingUid(), userId)) {
-                return true;
+                return false;
             }
             return mSettings.getBlockUninstallLPr(userId, packageName);
         }
index 8cfbf68..fe74947 100644 (file)
@@ -38,8 +38,11 @@ import android.graphics.Rect;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
 import android.os.Trace;
 import android.util.Slog;
+import android.view.DisplayInfo;
 import android.view.IApplicationToken;
 import android.view.WindowManagerPolicy.StartingSurface;
 
@@ -61,23 +64,38 @@ public class AppWindowContainerController
     private final IApplicationToken mToken;
     private final Handler mHandler;
 
-    private final Runnable mOnStartingWindowDrawn = () -> {
-        if (mListener == null) {
-            return;
+    private final class H extends Handler {
+        public static final int NOTIFY_WINDOWS_DRAWN = 1;
+        public static final int NOTIFY_STARTING_WINDOW_DRAWN = 2;
+
+        public H(Looper looper) {
+            super(looper);
         }
-        if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
-                + AppWindowContainerController.this.mToken);
-        mListener.onStartingWindowDrawn();
-    };
 
-    private final Runnable mOnWindowsDrawn = () -> {
-        if (mListener == null) {
-            return;
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case NOTIFY_WINDOWS_DRAWN:
+                    if (mListener == null) {
+                        return;
+                    }
+                    if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
+                            + AppWindowContainerController.this.mToken);
+                    mListener.onWindowsDrawn(msg.getWhen());
+                    break;
+                case NOTIFY_STARTING_WINDOW_DRAWN:
+                    if (mListener == null) {
+                        return;
+                    }
+                    if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
+                            + AppWindowContainerController.this.mToken);
+                    mListener.onStartingWindowDrawn(msg.getWhen());
+                    break;
+                default:
+                    break;
+            }
         }
-        if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
-                + AppWindowContainerController.this.mToken);
-        mListener.onWindowsDrawn();
-    };
+    }
 
     private final Runnable mOnWindowsVisible = () -> {
         if (mListener == null) {
@@ -212,7 +230,7 @@ public class AppWindowContainerController
             int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
             WindowManagerService service, Configuration overrideConfig, Rect bounds) {
         super(listener, service);
-        mHandler = new Handler(service.mH.getLooper());
+        mHandler = new H(service.mH.getLooper());
         mToken = token;
         synchronized(mWindowMap) {
             AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
@@ -481,7 +499,7 @@ public class AppWindowContainerController
     public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
             CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
             IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
-            boolean allowTaskSnapshot, boolean activityCreated) {
+            boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
         synchronized(mWindowMap) {
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
                     + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask
@@ -510,11 +528,14 @@ public class AppWindowContainerController
                 return false;
             }
 
+            final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
+                    mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
+                    false /* restoreFromDisk */, false /* reducedResolution */);
             final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
-                    allowTaskSnapshot, activityCreated);
+                    allowTaskSnapshot, activityCreated, fromRecents, snapshot);
 
             if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
-                return createSnapshot();
+                return createSnapshot(snapshot);
             }
 
             // If this is a translucent window, then don't show a starting window -- the current
@@ -582,7 +603,8 @@ public class AppWindowContainerController
     }
 
     private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
-            boolean allowTaskSnapshot, boolean activityCreated) {
+            boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
+            TaskSnapshot snapshot) {
         if (mService.mAppTransition.getAppTransition() == TRANSIT_DOCK_TASK_FROM_RECENTS) {
             // TODO(b/34099271): Remove this statement to add back the starting window and figure
             // out why it causes flickering, the starting window appears over the thumbnail while
@@ -591,7 +613,9 @@ public class AppWindowContainerController
         } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
             return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
         } else if (taskSwitch && allowTaskSnapshot) {
-            return STARTING_WINDOW_TYPE_SNAPSHOT;
+            return snapshot == null ? STARTING_WINDOW_TYPE_NONE
+                    : snapshotFillsWidth(snapshot) || fromRecents ? STARTING_WINDOW_TYPE_SNAPSHOT
+                    : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
         } else {
             return STARTING_WINDOW_TYPE_NONE;
         }
@@ -605,11 +629,7 @@ public class AppWindowContainerController
         mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
     }
 
-    private boolean createSnapshot() {
-        final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
-                mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
-                false /* restoreFromDisk */, false /* reducedResolution */);
-
+    private boolean createSnapshot(TaskSnapshot snapshot) {
         if (snapshot == null) {
             return false;
         }
@@ -620,6 +640,24 @@ public class AppWindowContainerController
         return true;
     }
 
+    private boolean snapshotFillsWidth(TaskSnapshot snapshot) {
+        if (snapshot == null) {
+            return false;
+        }
+        final Rect rect = new Rect(0, 0, snapshot.getSnapshot().getWidth(),
+                snapshot.getSnapshot().getHeight());
+        rect.inset(snapshot.getContentInsets());
+        final Rect taskBoundsWithoutInsets = new Rect();
+        mContainer.getTask().getBounds(taskBoundsWithoutInsets);
+        final DisplayInfo di = mContainer.getDisplayContent().getDisplayInfo();
+        final Rect displayBounds = new Rect(0, 0, di.logicalWidth, di.logicalHeight);
+        final Rect stableInsets = new Rect();
+        mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
+                stableInsets);
+        displayBounds.inset(stableInsets);
+        return rect.width() >= displayBounds.width();
+    }
+
     public void removeStartingWindow() {
         synchronized (mWindowMap) {
             if (mHandler.hasCallbacks(mRemoveStartingWindow)) {
@@ -740,11 +778,11 @@ public class AppWindowContainerController
     }
 
     void reportStartingWindowDrawn() {
-        mHandler.post(mOnStartingWindowDrawn);
+        mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_STARTING_WINDOW_DRAWN));
     }
 
     void reportWindowsDrawn() {
-        mHandler.post(mOnWindowsDrawn);
+        mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_WINDOWS_DRAWN));
     }
 
     void reportWindowsVisible() {
index 26537f2..8a39a74 100644 (file)
@@ -19,7 +19,7 @@ package com.android.server.wm;
 /** Interface used by the creator of the controller to listen to changes with the container. */
 public interface AppWindowContainerListener extends WindowContainerListener {
     /** Called when the windows associated app window container are drawn. */
-    void onWindowsDrawn();
+    void onWindowsDrawn(long timestamp);
     /** Called when the windows associated app window container are visible. */
     void onWindowsVisible();
     /** Called when the windows associated app window container are no longer visible. */
@@ -28,7 +28,7 @@ public interface AppWindowContainerListener extends WindowContainerListener {
     /**
      * Called when the starting window for this container is drawn.
      */
-    void onStartingWindowDrawn();
+    void onStartingWindowDrawn(long timestamp);
 
     /**
      * Called when the key dispatching to a window associated with the app window container
index 71ecaf6..bd37934 100644 (file)
@@ -394,6 +394,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
                     startingWindow.mPolicyVisibility = false;
                     startingWindow.mPolicyVisibilityAfterAnim = false;
                 }
+
+                // We are becoming visible, so better freeze the screen with the windows that are
+                // getting visible so we also wait for them.
+                forAllWindows(mService::makeWindowFreezingScreenIfNeededLocked, true);
             }
 
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setVisibility: " + this
@@ -891,8 +895,24 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
         return mPendingRelaunchCount > 0;
     }
 
+    boolean shouldFreezeBounds() {
+        final Task task = getTask();
+
+        // For freeform windows, we can't freeze the bounds at the moment because this would make
+        // the resizing unresponsive.
+        if (task == null || task.inFreeformWorkspace()) {
+            return false;
+        }
+
+        // We freeze the bounds while drag resizing to deal with the time between
+        // the divider/drag handle being released, and the handling it's new
+        // configuration. If we are relaunched outside of the drag resizing state,
+        // we need to be careful not to do this.
+        return getTask().isDragResizing();
+    }
+
     void startRelaunching() {
-        if (canFreezeBounds()) {
+        if (shouldFreezeBounds()) {
             freezeBounds();
         }
 
@@ -909,9 +929,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
     }
 
     void finishRelaunching() {
-        if (canFreezeBounds()) {
-            unfreezeBounds();
-        }
+        unfreezeBounds();
+
         if (mPendingRelaunchCount > 0) {
             mPendingRelaunchCount--;
         } else {
@@ -926,9 +945,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
         if (mPendingRelaunchCount == 0) {
             return;
         }
-        if (canFreezeBounds()) {
-            unfreezeBounds();
-        }
+        unfreezeBounds();
         mPendingRelaunchCount = 0;
     }
 
@@ -1032,14 +1049,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
         }
     }
 
-    private boolean canFreezeBounds() {
-        final Task task = getTask();
-
-        // For freeform windows, we can't freeze the bounds at the moment because this would make
-        // the resizing unresponsive.
-        return task != null && !task.inFreeformWorkspace();
-    }
-
     /**
      * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
      * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
@@ -1064,9 +1073,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
      * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
      */
     private void unfreezeBounds() {
-        if (!mFrozenBounds.isEmpty()) {
-            mFrozenBounds.remove();
+        if (mFrozenBounds.isEmpty()) {
+            return;
         }
+        mFrozenBounds.remove();
         if (!mFrozenMergedConfig.isEmpty()) {
             mFrozenMergedConfig.remove();
         }
index 551e3bf..a96d224 100644 (file)
@@ -125,6 +125,7 @@ class TaskSnapshotSurface implements StartingSurface {
     private final Paint mBackgroundPaint = new Paint();
     private final int mStatusBarColor;
     @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
+    private final int mOrientationOnCreation;
 
     static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
             TaskSnapshot snapshot) {
@@ -146,6 +147,7 @@ class TaskSnapshotSurface implements StartingSurface {
         final int sysUiVis;
         final int windowFlags;
         final int windowPrivateFlags;
+        final int currentOrientation;
         synchronized (service.mWindowMap) {
             final WindowState mainWindow = token.findMainWindow();
             if (mainWindow == null) {
@@ -183,6 +185,7 @@ class TaskSnapshotSurface implements StartingSurface {
             } else {
                 taskBounds = null;
             }
+            currentOrientation = mainWindow.getConfiguration().orientation;
         }
         try {
             final int res = session.addToDisplay(window, window.mSeq, layoutParams,
@@ -197,7 +200,8 @@ class TaskSnapshotSurface implements StartingSurface {
         }
         final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
                 surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
-                navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds);
+                navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds,
+                currentOrientation);
         window.setOuter(snapshotSurface);
         try {
             session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
@@ -215,7 +219,7 @@ class TaskSnapshotSurface implements StartingSurface {
     TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface,
             TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor,
             int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags,
-            Rect taskBounds) {
+            Rect taskBounds, int currentOrientation) {
         mService = service;
         mHandler = new Handler(mService.mH.getLooper());
         mSession = WindowManagerGlobal.getWindowSession();
@@ -228,6 +232,7 @@ class TaskSnapshotSurface implements StartingSurface {
         mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
                 windowPrivateFlags, sysUiVis, statusBarColor, navigationBarColor);
         mStatusBarColor = statusBarColor;
+        mOrientationOnCreation = currentOrientation;
     }
 
     @Override
@@ -394,6 +399,7 @@ class TaskSnapshotSurface implements StartingSurface {
     static class Window extends BaseIWindow {
 
         private TaskSnapshotSurface mOuter;
+
         public void setOuter(TaskSnapshotSurface outer) {
             mOuter = outer;
         }
@@ -403,6 +409,15 @@ class TaskSnapshotSurface implements StartingSurface {
                 Rect stableInsets, Rect outsets, boolean reportDraw,
                 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
                 boolean alwaysConsumeNavBar, int displayId) {
+            if (mergedConfiguration != null && mOuter != null
+                    && mOuter.mOrientationOnCreation
+                            != mergedConfiguration.getMergedConfiguration().orientation) {
+
+                // The orientation of the screen is changing. We better remove the snapshot ASAP as
+                // we are going to wait on the new window in any case to unfreeze the screen, and
+                // the starting window is not needed anymore.
+                sHandler.post(mOuter::remove);
+            }
             if (reportDraw) {
                 sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
             }
index aabf2be..fe5b7f2 100644 (file)
@@ -228,7 +228,10 @@ public class WindowAnimator {
             Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
         } finally {
             if (transactionOpen) {
-                mService.closeSurfaceTransaction();
+
+                // Do not hold window manager lock while closing the transaction, as this might be
+                // blocking until the next frame, which can lead to total lock starvation.
+                mService.closeSurfaceTransaction(false /* withLockHeld */);
                 if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
             }
         }
index 9e3edef..ec7ab23 100644 (file)
@@ -893,10 +893,26 @@ public class WindowManagerService extends IWindowManager.Stub
     }
 
     void closeSurfaceTransaction() {
+        closeSurfaceTransaction(true /* withLockHeld */);
+    }
+
+    /**
+     * Closes a surface transaction.
+     *
+     * @param withLockHeld Whether to acquire the window manager while doing so. In some cases
+     *                     holding the lock my lead to starvation in WM in case closeTransaction
+     *                     blocks and we call it repeatedly, like we do for animations.
+     */
+    void closeSurfaceTransaction(boolean withLockHeld) {
         synchronized (mWindowMap) {
             if (mRoot.mSurfaceTraceEnabled) {
                 mRoot.mRemoteEventTrace.closeSurfaceTransaction();
             }
+            if (withLockHeld) {
+                SurfaceControl.closeTransaction();
+            }
+        }
+        if (!withLockHeld) {
             SurfaceControl.closeTransaction();
         }
     }
@@ -1270,14 +1286,6 @@ public class WindowManagerService extends IWindowManager.Stub
                           + token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_APP_EXITING;
                 }
-                if (rootType == TYPE_APPLICATION_STARTING
-                        && (attrs.privateFlags & PRIVATE_FLAG_TASK_SNAPSHOT) == 0
-                        && atoken.firstWindowDrawn) {
-                    // No need for this guy!
-                    if (DEBUG_STARTING_WINDOW || localLOGV) Slog.v(
-                            TAG_WM, "**** NO NEED TO START: " + attrs.getTitle());
-                    return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
-                }
             } else if (rootType == TYPE_INPUT_METHOD) {
                 if (token.windowType != TYPE_INPUT_METHOD) {
                     Slog.w(TAG_WM, "Attempted to add input method window with bad token "
@@ -5150,7 +5158,8 @@ public class WindowManagerService extends IWindowManager.Stub
                 }
                 break;
                 case NOTIFY_APP_TRANSITION_STARTING: {
-                    mAmInternal.notifyAppTransitionStarting((SparseIntArray) msg.obj);
+                    mAmInternal.notifyAppTransitionStarting((SparseIntArray) msg.obj,
+                            msg.getWhen());
                 }
                 break;
                 case NOTIFY_APP_TRANSITION_CANCELLED: {
index 73f8d27..33cb908 100644 (file)
@@ -1524,7 +1524,10 @@ class WindowStateAnimator {
     void prepareSurfaceLocked(final boolean recoveringMemory) {
         final WindowState w = mWin;
         if (!hasSurface()) {
-            if (w.mOrientationChanging) {
+
+            // There is no need to wait for an animation change if our window is gone for layout
+            // already as we'll never be visible.
+            if (w.mOrientationChanging && w.isGoneForLayoutLw()) {
                 if (DEBUG_ORIENTATION) {
                     Slog.v(TAG, "Orientation change skips hidden " + w);
                 }
@@ -1557,13 +1560,11 @@ class WindowStateAnimator {
             hide("prepareSurfaceLocked");
             mWallpaperControllerLocked.hideWallpapers(w);
 
-            // If we are waiting for this window to handle an
-            // orientation change, well, it is hidden, so
-            // doesn't really matter.  Note that this does
-            // introduce a potential glitch if the window
-            // becomes unhidden before it has drawn for the
-            // new orientation.
-            if (w.mOrientationChanging) {
+            // If we are waiting for this window to handle an orientation change. If this window is
+            // really hidden (gone for layout), there is no point in still waiting for it.
+            // Note that this does introduce a potential glitch if the window becomes unhidden
+            // before it has drawn for the new orientation.
+            if (w.mOrientationChanging && w.isGoneForLayoutLw()) {
                 w.mOrientationChanging = false;
                 if (DEBUG_ORIENTATION) Slog.v(TAG,
                         "Orientation change skips hidden " + w);
@@ -1630,18 +1631,19 @@ class WindowStateAnimator {
             displayed = true;
         }
 
-        if (displayed) {
-            if (w.mOrientationChanging) {
-                if (!w.isDrawnLw()) {
-                    mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
-                    mAnimator.mLastWindowFreezeSource = w;
-                    if (DEBUG_ORIENTATION) Slog.v(TAG,
-                            "Orientation continue waiting for draw in " + w);
-                } else {
-                    w.mOrientationChanging = false;
-                    if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation change complete in " + w);
-                }
+        if (w.mOrientationChanging) {
+            if (!w.isDrawnLw()) {
+                mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
+                mAnimator.mLastWindowFreezeSource = w;
+                if (DEBUG_ORIENTATION) Slog.v(TAG,
+                        "Orientation continue waiting for draw in " + w);
+            } else {
+                w.mOrientationChanging = false;
+                if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation change complete in " + w);
             }
+        }
+
+        if (displayed) {
             w.mToken.hasVisible = true;
         }
     }
index 65a5632..6060881 100644 (file)
@@ -107,7 +107,7 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
                 createAppWindowController();
         controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
-                false);
+                false, false);
         waitUntilHandlersIdle();
         final AppWindowToken atoken = controller.getAppWindowToken(mDisplayContent);
         assertHasStartingWindow(atoken);
@@ -125,7 +125,7 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
                     createAppWindowController();
             controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                     android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
-                    false);
+                    false, false);
             controller.removeStartingWindow();
             waitUntilHandlersIdle();
             assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent));
@@ -140,11 +140,11 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
                 createAppWindowController();
         controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
-                false);
+                false, false);
         waitUntilHandlersIdle();
         controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(),
-                true, true, false, true, false);
+                true, true, false, true, false, false);
         waitUntilHandlersIdle();
         assertNoStartingWindow(controller1.getAppWindowToken(mDisplayContent));
         assertHasStartingWindow(controller2.getAppWindowToken(mDisplayContent));
@@ -161,11 +161,11 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
             // Surprise, ...! Transfer window in the middle of the creation flow.
             controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                     android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(),
-                    true, true, false, true, false);
+                    true, true, false, true, false, false);
         });
         controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
-                false);
+                false, false);
         waitUntilHandlersIdle();
         assertNoStartingWindow(controller1.getAppWindowToken(mDisplayContent));
         assertHasStartingWindow(controller2.getAppWindowToken(mDisplayContent));
index e2868d7..4288eac 100644 (file)
@@ -62,7 +62,8 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
         final TaskSnapshot snapshot = new TaskSnapshot(buffer,
                 ORIENTATION_PORTRAIT, contentInsets, false, 1.0f);
         mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test",
-                Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds);
+                Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds,
+                ORIENTATION_PORTRAIT);
     }
 
     private void setupSurface(int width, int height) {
index 272653f..4d2f97f 100644 (file)
@@ -664,7 +664,8 @@ public class AppLaunch extends InstrumentationTestCase {
                     if (lineCount == 2 && line.contains(SUCCESS_MESSAGE)) {
                         launchSuccess = true;
                     }
-                    if (launchSuccess && lineCount == 4) {
+                    // Parse TotalTime which is the launch time
+                    if (launchSuccess && lineCount == 5) {
                         String launchSplit[] = line.split(":");
                         launchTime = launchSplit[1].trim();
                     }