Merge "Set panel launch mode to singleInstance and fix animation" into qt-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8e4d6a4..8e62c45 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3114,7 +3114,7 @@
         <activity android:name=".panel.SettingsPanelActivity"
             android:label="@string/settings_panel_title"
             android:theme="@style/Theme.Panel"
-            android:documentLaunchMode="always"
+            android:launchMode="singleInstance"
             android:excludeFromRecents="true"
             android:exported="true">
                  <intent-filter>
diff --git a/src/com/android/settings/media/MediaOutputIndicatorSlice.java b/src/com/android/settings/media/MediaOutputIndicatorSlice.java
index fe59d75..dec50bc 100644
--- a/src/com/android/settings/media/MediaOutputIndicatorSlice.java
+++ b/src/com/android/settings/media/MediaOutputIndicatorSlice.java
@@ -90,7 +90,7 @@
     private Intent getMediaOutputSliceIntent() {
         final Intent intent = new Intent()
                 .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         return intent;
     }
 
diff --git a/src/com/android/settings/panel/InternetConnectivityPanel.java b/src/com/android/settings/panel/InternetConnectivityPanel.java
index 4e4fc0c..ae72427 100644
--- a/src/com/android/settings/panel/InternetConnectivityPanel.java
+++ b/src/com/android/settings/panel/InternetConnectivityPanel.java
@@ -63,7 +63,8 @@
 
     @Override
     public Intent getSeeMoreIntent() {
-        return new Intent(Settings.ACTION_WIRELESS_SETTINGS);
+        return new Intent(Settings.ACTION_WIRELESS_SETTINGS)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     }
 
     @Override
diff --git a/src/com/android/settings/panel/NfcPanel.java b/src/com/android/settings/panel/NfcPanel.java
index 6a9c74d..c1e15e8 100644
--- a/src/com/android/settings/panel/NfcPanel.java
+++ b/src/com/android/settings/panel/NfcPanel.java
@@ -64,6 +64,7 @@
                 screenTitle,
                 SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY);
         intent.setClassName(mContext.getPackageName(), SubSettings.class.getName());
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         return intent;
     }
 
diff --git a/src/com/android/settings/panel/PanelFragment.java b/src/com/android/settings/panel/PanelFragment.java
index 173461c..e9eeb8d 100644
--- a/src/com/android/settings/panel/PanelFragment.java
+++ b/src/com/android/settings/panel/PanelFragment.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.panel;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
@@ -29,7 +31,6 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
 import android.widget.Button;
 import android.widget.TextView;
 
@@ -59,9 +60,14 @@
     private static final String TAG = "PanelFragment";
 
     /**
-     * Duration of the animation entering or exiting the screen, in milliseconds.
+     * Duration of the animation entering the screen, in milliseconds.
      */
-    private static final int DURATION_ANIMATE_PANEL_MS = 250;
+    private static final int DURATION_ANIMATE_PANEL_EXPAND_MS = 250;
+
+    /**
+     * Duration of the animation exiting the screen, in milliseconds.
+     */
+    private static final int DURATION_ANIMATE_PANEL_COLLAPSE_MS = 200;
 
     /**
      * Duration of timeout waiting for Slice data to bind, in milliseconds.
@@ -104,15 +110,53 @@
     @Override
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
             @Nullable Bundle savedInstanceState) {
-        final FragmentActivity activity = getActivity();
-
         mLayoutView = inflater.inflate(R.layout.panel_layout, container, false);
+        createPanelContent();
+        return mLayoutView;
+    }
+
+    /**
+     * Animate the old panel out from the screen, then update the panel with new content once the
+     * animation is done.
+     * <p>
+     *     Takes the entire panel and animates out from behind the navigation bar.
+     * <p>
+     *     Call createPanelContent() once animation end.
+     */
+    void updatePanelWithAnimation() {
+        final View panelContent = mLayoutView.findViewById(R.id.panel_container);
+        final AnimatorSet animatorSet = buildAnimatorSet(mLayoutView,
+                0.0f /* startY */, panelContent.getHeight() /* endY */,
+                1.0f /* startAlpha */, 0.0f /* endAlpha */,
+                DURATION_ANIMATE_PANEL_COLLAPSE_MS);
+
+        final ValueAnimator animator = new ValueAnimator();
+        animator.setFloatValues(0.0f, 1.0f);
+        animatorSet.play(animator);
+        animatorSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                createPanelContent();
+            }
+        });
+        animatorSet.start();
+    }
+
+    private void createPanelContent() {
+        final FragmentActivity activity = getActivity();
+        if (mLayoutView == null) {
+            activity.finish();
+        }
 
         mPanelSlices = mLayoutView.findViewById(R.id.panel_parent_layout);
         mSeeMoreButton = mLayoutView.findViewById(R.id.see_more);
         mDoneButton = mLayoutView.findViewById(R.id.done);
         mTitleView = mLayoutView.findViewById(R.id.panel_title);
 
+        // Make the panel layout gone here, to avoid janky animation when updating from old panel.
+        // We will make it visible once the panel is ready to load.
+        mPanelSlices.setVisibility(View.GONE);
+
         final Bundle arguments = getArguments();
         final String panelType =
                 arguments.getString(SettingsPanelActivity.KEY_PANEL_TYPE_ARGUMENT);
@@ -152,8 +196,6 @@
                 mPanel.getMetricsCategory(),
                 callingPackageName,
                 0 /* value */);
-
-        return mLayoutView;
     }
 
     private void loadAllSlices() {
@@ -220,6 +262,7 @@
             mPanelSlices.setAdapter(mAdapter);
             mPanelSlices.getViewTreeObserver()
                     .addOnGlobalLayoutListener(mOnGlobalLayoutListener);
+            mPanelSlices.setVisibility(View.VISIBLE);
 
             DividerItemDecoration itemDecoration = new DividerItemDecoration(getActivity());
             itemDecoration
@@ -237,8 +280,10 @@
      */
     private void animateIn() {
         final View panelContent = mLayoutView.findViewById(R.id.panel_container);
-        final AnimatorSet animatorSet = buildAnimatorSet(mLayoutView, panelContent.getHeight(),
-                0.0f, new DecelerateInterpolator());
+        final AnimatorSet animatorSet = buildAnimatorSet(mLayoutView,
+                panelContent.getHeight() /* startY */, 0.0f /* endY */,
+                0.0f /* startAlpha */, 1.0f /* endAlpha */,
+                DURATION_ANIMATE_PANEL_EXPAND_MS);
         final ValueAnimator animator = new ValueAnimator();
         animator.setFloatValues(0.0f, 1.0f);
         animatorSet.play(animator);
@@ -248,18 +293,21 @@
     }
 
     /**
-     * Build an {@link AnimatorSet} to bring the Panel, {@param parentView}in our out of the screen,
-     * based on the positional parameters {@param startY}, {@param endY} and at the rate set by the
-     * {@param interpolator}.
+     * Build an {@link AnimatorSet} to animate the Panel, {@param parentView} in or out of the
+     * screen, based on the positional parameters {@param startY}, {@param endY}, the parameters
+     * for alpha changes {@param startAlpha}, {@param endAlpha}, and the {@param duration} in
+     * milliseconds.
      */
     @NonNull
     private static AnimatorSet buildAnimatorSet(@NonNull View parentView, float startY, float endY,
-            @NonNull Interpolator interpolator) {
+            float startAlpha, float endAlpha, int duration) {
         final View sheet = parentView.findViewById(R.id.panel_container);
         final AnimatorSet animatorSet = new AnimatorSet();
-        animatorSet.setDuration(DURATION_ANIMATE_PANEL_MS);
-        animatorSet.setInterpolator(interpolator);
-        animatorSet.playTogether(ObjectAnimator.ofFloat(sheet, View.TRANSLATION_Y, startY, endY));
+        animatorSet.setDuration(duration);
+        animatorSet.setInterpolator(new DecelerateInterpolator());
+        animatorSet.playTogether(
+                ObjectAnimator.ofFloat(sheet, View.TRANSLATION_Y, startY, endY),
+                ObjectAnimator.ofFloat(sheet, View.ALPHA, startAlpha,endAlpha));
         return animatorSet;
     }
 
diff --git a/src/com/android/settings/panel/SettingsPanelActivity.java b/src/com/android/settings/panel/SettingsPanelActivity.java
index eabd715..a2cb277 100644
--- a/src/com/android/settings/panel/SettingsPanelActivity.java
+++ b/src/com/android/settings/panel/SettingsPanelActivity.java
@@ -21,6 +21,7 @@
 import android.app.settings.SettingsEnums;
 import android.content.Intent;
 import android.os.Bundle;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.MotionEvent;
@@ -65,7 +66,17 @@
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        showOrUpdatePanel();
+    }
 
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        setIntent(intent);
+        showOrUpdatePanel();
+    }
+
+    private void showOrUpdatePanel() {
         final Intent callingIntent = getIntent();
         if (callingIntent == null) {
             Log.e(TAG, "Null intent, closing Panel Activity");
@@ -76,24 +87,28 @@
         // We will use it once media output switch panel support remote device.
         final String mediaPackageName = callingIntent.getStringExtra(EXTRA_PACKAGE_NAME);
 
-        setContentView(R.layout.settings_panel);
-
-        // Move the window to the bottom of screen, and make it take up the entire screen width.
-        final Window window = getWindow();
-        window.setGravity(Gravity.BOTTOM);
-        window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.WRAP_CONTENT);
-
         mBundle.putString(KEY_PANEL_TYPE_ARGUMENT, callingIntent.getAction());
         mBundle.putString(KEY_CALLING_PACKAGE_NAME, getCallingPackage());
         mBundle.putString(KEY_MEDIA_PACKAGE_NAME, mediaPackageName);
 
-        final PanelFragment panelFragment = new PanelFragment();
-        panelFragment.setArguments(mBundle);
-
         final FragmentManager fragmentManager = getSupportFragmentManager();
         final Fragment fragment = fragmentManager.findFragmentById(R.id.main_content);
-        if (fragment == null) {
+
+        // If fragment already exists, we will need to update panel with animation.
+        if (fragment != null && fragment instanceof PanelFragment) {
+            final PanelFragment panelFragment = (PanelFragment) fragment;
+            panelFragment.setArguments(mBundle);
+            ((PanelFragment) fragment).updatePanelWithAnimation();
+        } else {
+            setContentView(R.layout.settings_panel);
+
+            // Move the window to the bottom of screen, and make it take up the entire screen width.
+            final Window window = getWindow();
+            window.setGravity(Gravity.BOTTOM);
+            window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
+                    WindowManager.LayoutParams.WRAP_CONTENT);
+            final PanelFragment panelFragment = new PanelFragment();
+            panelFragment.setArguments(mBundle);
             fragmentManager.beginTransaction().add(R.id.main_content, panelFragment).commit();
         }
     }
diff --git a/src/com/android/settings/panel/VolumePanel.java b/src/com/android/settings/panel/VolumePanel.java
index 2cbf729..1a166ba 100644
--- a/src/com/android/settings/panel/VolumePanel.java
+++ b/src/com/android/settings/panel/VolumePanel.java
@@ -68,7 +68,7 @@
 
     @Override
     public Intent getSeeMoreIntent() {
-        return new Intent(Settings.ACTION_SOUND_SETTINGS);
+        return new Intent(Settings.ACTION_SOUND_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     }
 
     @Override
diff --git a/src/com/android/settings/panel/WifiPanel.java b/src/com/android/settings/panel/WifiPanel.java
index f9be081c..36ee117 100644
--- a/src/com/android/settings/panel/WifiPanel.java
+++ b/src/com/android/settings/panel/WifiPanel.java
@@ -67,6 +67,7 @@
                 screenTitle,
                 SettingsEnums.WIFI);
         intent.setClassName(mContext.getPackageName(), SubSettings.class.getName());
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         return intent;
     }