Fix crash on rotation

Load app/channel data early so that any open dialogs can be properly
reconstructed. Never call done on an entityheadercontroller with
an activity that's not yet started.

Test: robotests
Change-Id: Ib2b9f8f1985ef038959062204aaceff686f4ebcf
Fixes: 74114917
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e87951b..af565d6 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2743,6 +2743,7 @@
 
         <!-- Show channel-level notification settings (channel passed in as extras) -->
         <activity android:name="Settings$ChannelNotificationSettingsActivity"
+                  android:label="@string/notification_channel_title"
                   android:exported="true">
             <intent-filter android:priority="1">
                 <action android:name="android.settings.CHANNEL_NOTIFICATION_SETTINGS" />
diff --git a/res/xml/app_notification_settings.xml b/res/xml/app_notification_settings.xml
index 2d5dc57..3ddfac5 100644
--- a/res/xml/app_notification_settings.xml
+++ b/res/xml/app_notification_settings.xml
@@ -31,15 +31,32 @@
 
     <!-- Channels/Channel groups added here -->
 
+    <!-- Importance toggle -->
+    <com.android.settingslib.RestrictedSwitchPreference
+        android:key="allow_sound"
+        android:title="@string/allow_interruption"
+        android:summary="@string/allow_interruption_summary" />
+
+    <!-- Visibility Override -->
+    <com.android.settings.RestrictedListPreference
+        android:key="visibility_override"
+        android:title="@string/app_notification_visibility_override_title"/>
+
     <!-- Show badge -->
     <com.android.settingslib.RestrictedSwitchPreference
         android:key="badge"
         android:title="@string/notification_badge_title"
         android:order="501"
         settings:useAdditionalSummary="true"
-        settings:allowDividerAbove="true"
         settings:restrictedSwitchSummary="@string/enabled_by_admin" />
 
+    <!-- Bypass DND -->
+    <com.android.settingslib.RestrictedSwitchPreference
+        android:key="bypass_dnd"
+        android:title="@string/app_notification_override_dnd_title"
+        android:summary="@string/app_notification_override_dnd_summary"
+        settings:useAdditionalSummary="true"/>
+
     <Preference
         android:key="app_link"
         android:title="@string/app_settings_link"
diff --git a/res/xml/channel_notification_settings.xml b/res/xml/channel_notification_settings.xml
index 9d0398d..01001fa 100644
--- a/res/xml/channel_notification_settings.xml
+++ b/res/xml/channel_notification_settings.xml
@@ -14,9 +14,12 @@
      limitations under the License.
 -->
 
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:settings="http://schemas.android.com/apk/res-auto"
-        settings:initialExpandedChildrenCount="3">
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:key="channel_settings"
+    android:title="@string/notification_channel_title"
+    settings:initialExpandedChildrenCount="3" >
 
     <com.android.settings.applications.LayoutPreference
         android:key="pref_app_header"
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index 6776931..2bc2489 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -68,10 +68,7 @@
             mDynamicPreferences.clear();
         }
 
-        if (mShowLegacyChannelConfig) {
-            addPreferencesFromResource(R.xml.channel_notification_settings);
-        } else {
-            addPreferencesFromResource(R.xml.app_notification_settings);
+        if (!mShowLegacyChannelConfig) {
             // Load channel settings
             new AsyncTask<Void, Void, Void>() {
                 @Override
@@ -106,7 +103,7 @@
 
     @Override
     protected int getPreferenceScreenResId() {
-        return R.xml.notification_settings;
+        return R.xml.app_notification_settings;
     }
 
     @Override
diff --git a/src/com/android/settings/notification/HeaderPreferenceController.java b/src/com/android/settings/notification/HeaderPreferenceController.java
index d5e289b..c6f6a80 100644
--- a/src/com/android/settings/notification/HeaderPreferenceController.java
+++ b/src/com/android/settings/notification/HeaderPreferenceController.java
@@ -18,6 +18,8 @@
 
 import static com.android.settings.widget.EntityHeaderController.PREF_KEY_APP_HEADER;
 
+import android.arch.lifecycle.LifecycleObserver;
+import android.arch.lifecycle.OnLifecycleEvent;
 import android.content.Context;
 import android.support.v14.preference.PreferenceFragment;
 import android.support.v7.preference.Preference;
@@ -30,13 +32,16 @@
 import com.android.settings.applications.LayoutPreference;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.events.OnStart;
 
 import java.util.Objects;
 
 public class HeaderPreferenceController extends NotificationPreferenceController
-        implements PreferenceControllerMixin {
+        implements PreferenceControllerMixin, LifecycleObserver {
 
     private final PreferenceFragment mFragment;
+    private EntityHeaderController mHeaderController;
 
     public HeaderPreferenceController(Context context, PreferenceFragment fragment) {
         super(context, null);
@@ -57,10 +62,9 @@
     public void updateState(Preference preference) {
         if (mAppRow != null && mFragment != null) {
             LayoutPreference pref = (LayoutPreference) preference;
-            EntityHeaderController controller = EntityHeaderController
-                    .newInstance(mFragment.getActivity(), mFragment,
-                            pref.findViewById(R.id.entity_header));
-            pref = controller.setIcon(mAppRow.icon)
+            mHeaderController = EntityHeaderController.newInstance(
+                    mFragment.getActivity(), mFragment, pref.findViewById(R.id.entity_header));
+            pref = mHeaderController.setIcon(mAppRow.icon)
                     .setLabel(getLabel())
                     .setSummary(getSummary())
                     .setPackageName(mAppRow.pkg)
@@ -68,7 +72,7 @@
                     .setButtonActions(EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE,
                             EntityHeaderController.ActionType.ACTION_NONE)
                     .setHasAppInfoLink(true)
-                    .done(mFragment.getActivity(), mContext);
+                    .done(null, mContext);
             pref.findViewById(R.id.entity_header).setVisibility(View.VISIBLE);
         }
     }
@@ -101,4 +105,11 @@
             return "";
         }
     }
+
+    @OnLifecycleEvent(Lifecycle.Event.ON_START)
+    public void onStart() {
+        if (mHeaderController != null) {
+            mHeaderController.styleActionBar(mFragment.getActivity());
+        }
+    }
 }
diff --git a/src/com/android/settings/notification/NotificationPreferenceController.java b/src/com/android/settings/notification/NotificationPreferenceController.java
index 1a65351..1e477c4 100644
--- a/src/com/android/settings/notification/NotificationPreferenceController.java
+++ b/src/com/android/settings/notification/NotificationPreferenceController.java
@@ -96,7 +96,7 @@
             if (preference != null) {
                 mPreference = preference;
             }
-            if (this instanceof Preference.OnPreferenceChangeListener) {
+            if (mPreference != null && this instanceof Preference.OnPreferenceChangeListener) {
                 mPreference.setOnPreferenceChangeListener(
                         (Preference.OnPreferenceChangeListener) this);
             }
diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java
index 7eb0ba4..faf6fb3 100644
--- a/src/com/android/settings/notification/NotificationSettingsBase.java
+++ b/src/com/android/settings/notification/NotificationSettingsBase.java
@@ -20,6 +20,7 @@
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 
+import android.app.Activity;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
@@ -81,28 +82,25 @@
     protected List<Preference> mDynamicPreferences = new ArrayList<>();
     protected ImportanceListener mImportanceListener = new ImportanceListener();
 
+    protected Intent mIntent;
+    protected Bundle mArgs;
+
     @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+    public void onAttach(Context context) {
+        super.onAttach(context);
         mContext = getActivity();
-        Intent intent = getActivity().getIntent();
-        Bundle args = getArguments();
-        if (DEBUG) Log.d(TAG, "onCreate getIntent()=" + intent);
-        if (intent == null && args == null) {
-            Log.w(TAG, "No intent");
-            toastAndFinish();
-            return;
-        }
+        mIntent = getActivity().getIntent();
+        mArgs = getArguments();
 
         mPm = getPackageManager();
         mNm = NotificationManager.from(mContext);
 
-        mPkg = args != null && args.containsKey(AppInfoBase.ARG_PACKAGE_NAME)
-                ? args.getString(AppInfoBase.ARG_PACKAGE_NAME)
-                : intent.getStringExtra(Settings.EXTRA_APP_PACKAGE);
-        mUid = args != null && args.containsKey(AppInfoBase.ARG_PACKAGE_UID)
-                ? args.getInt(AppInfoBase.ARG_PACKAGE_UID)
-                : intent.getIntExtra(Settings.EXTRA_APP_UID, -1);
+        mPkg = mArgs != null && mArgs.containsKey(AppInfoBase.ARG_PACKAGE_NAME)
+                ? mArgs.getString(AppInfoBase.ARG_PACKAGE_NAME)
+                : mIntent.getStringExtra(Settings.EXTRA_APP_PACKAGE);
+        mUid = mArgs != null && mArgs.containsKey(AppInfoBase.ARG_PACKAGE_UID)
+                ? mArgs.getInt(AppInfoBase.ARG_PACKAGE_UID)
+                : mIntent.getIntExtra(Settings.EXTRA_APP_UID, -1);
 
         if (mUid < 0) {
             try {
@@ -113,13 +111,38 @@
 
         mPkgInfo = findPackageInfo(mPkg, mUid);
 
+        mUserId = UserHandle.getUserId(mUid);
+        mSuspendedAppsAdmin = RestrictedLockUtils.checkIfApplicationIsSuspended(
+                mContext, mPkg, mUserId);
+
+        loadChannel();
+        loadAppRow();
+        loadChannelGroup();
+        collectConfigActivities();
+
+        getLifecycle().addObserver(use(HeaderPreferenceController.class));
+
+        for (NotificationPreferenceController controller : mControllers) {
+            controller.onResume(mAppRow, mChannel, mChannelGroup, mSuspendedAppsAdmin);
+        }
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (mIntent == null && mArgs == null) {
+            Log.w(TAG, "No intent");
+            toastAndFinish();
+            return;
+        }
+
         if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null) {
             Log.w(TAG, "Missing package or uid or packageinfo");
             toastAndFinish();
             return;
         }
 
-        mUserId = UserHandle.getUserId(mUid);
         startListeningToPackageRemove();
     }
 
@@ -132,18 +155,26 @@
     @Override
     public void onResume() {
         super.onResume();
-        if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null) {
+        if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null || mAppRow == null) {
             Log.w(TAG, "Missing package or uid or packageinfo");
             finish();
             return;
         }
-        mAppRow = mBackend.loadAppRow(mContext, mPm, mPkgInfo);
+        // Reload app, channel, etc onResume in case they've changed. A little wasteful if we've
+        // just done onAttach but better than making every preference controller reload all
+        // the data
+        loadAppRow();
         if (mAppRow == null) {
             Log.w(TAG, "Can't load package");
             finish();
             return;
         }
+        loadChannel();
+        loadChannelGroup();
         collectConfigActivities();
+    }
+
+    private void loadChannel() {
         Intent intent = getActivity().getIntent();
         String channelId = intent != null ? intent.getStringExtra(Settings.EXTRA_CHANNEL_ID) : null;
         if (channelId == null && intent != null) {
@@ -151,12 +182,13 @@
             channelId = args != null ? args.getString(Settings.EXTRA_CHANNEL_ID) : null;
         }
         mChannel = mBackend.getChannel(mPkg, mUid, channelId);
+    }
 
-        NotificationChannelGroup group = null;
+    private void loadAppRow() {
+        mAppRow = mBackend.loadAppRow(mContext, mPm, mPkgInfo);
+    }
 
-        mSuspendedAppsAdmin = RestrictedLockUtils.checkIfApplicationIsSuspended(
-                mContext, mPkg, mUserId);
-
+    private void loadChannelGroup() {
         mShowLegacyChannelConfig = mBackend.onlyHasDefaultChannel(mAppRow.pkg, mAppRow.uid)
                 || (mChannel != null
                 && NotificationChannel.DEFAULT_CHANNEL_ID.equals(mChannel.getId()));
@@ -166,7 +198,7 @@
                     mAppRow.pkg, mAppRow.uid, NotificationChannel.DEFAULT_CHANNEL_ID);
         }
         if (mChannel != null && !TextUtils.isEmpty(mChannel.getGroup())) {
-            group = mBackend.getGroup(mPkg, mUid, mChannel.getGroup());
+            NotificationChannelGroup group = mBackend.getGroup(mPkg, mUid, mChannel.getGroup());
             if (group != null) {
                 mChannelGroup = group;
             }