Merge "Don't tear down notification channels." into oc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ef3871c..9aa9a79 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -58,7 +58,7 @@
 
         <!--  Preserve original launcher activity from Nougat. -->
         <activity-alias
-            android:name=".Launcher"
+            android:name=".LauncherActivity"
             android:targetActivity=".files.LauncherActivity"
             android:label="@string/launcher_label"
             android:icon="@drawable/launcher_icon" >
diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java
index 9d91f46..367c76c 100644
--- a/src/com/android/documentsui/BaseActivity.java
+++ b/src/com/android/documentsui/BaseActivity.java
@@ -244,6 +244,7 @@
     protected void onDestroy() {
         mRootsMonitor.stop();
         mPreferencesMonitor.stop();
+        mSortController.destroy();
         super.onDestroy();
     }
 
diff --git a/src/com/android/documentsui/sorting/DropdownSortWidgetController.java b/src/com/android/documentsui/sorting/DropdownSortWidgetController.java
index 21c182c..489e184 100644
--- a/src/com/android/documentsui/sorting/DropdownSortWidgetController.java
+++ b/src/com/android/documentsui/sorting/DropdownSortWidgetController.java
@@ -44,6 +44,7 @@
     private final TextView mDimensionButton;
     private final PopupMenu mMenu;
     private final ImageView mArrow;
+    private final SortModel.UpdateListener mListener;
 
     public DropdownSortWidgetController(SortModel model, View widget) {
         mModel = model;
@@ -61,7 +62,8 @@
         populateMenuItems();
         onModelUpdate(mModel, SortModel.UPDATE_TYPE_UNSPECIFIED);
 
-        mModel.addListener(this::onModelUpdate);
+        mListener = this::onModelUpdate;
+        mModel.addListener(mListener);
     }
 
     @Override
@@ -69,6 +71,11 @@
         mWidget.setVisibility(visibility);
     }
 
+    @Override
+    public void destroy() {
+        mModel.removeListener(mListener);
+    }
+
     private void populateMenuItems() {
         Menu menu = mMenu.getMenu();
         menu.clear();
diff --git a/src/com/android/documentsui/sorting/SortController.java b/src/com/android/documentsui/sorting/SortController.java
index 927ff7e..1425e50 100644
--- a/src/com/android/documentsui/sorting/SortController.java
+++ b/src/com/android/documentsui/sorting/SortController.java
@@ -65,6 +65,13 @@
         }
     }
 
+    public void destroy() {
+        mDropdownController.destroy();
+        if (mTableHeaderController != null) {
+            mTableHeaderController.destroy();
+        }
+    }
+
     public static SortController create(
             Activity activity,
             @ViewMode int initialMode,
@@ -98,5 +105,6 @@
 
     public interface WidgetController {
         void setVisibility(int visibility);
+        void destroy();
     }
 }
diff --git a/src/com/android/documentsui/sorting/TableHeaderController.java b/src/com/android/documentsui/sorting/TableHeaderController.java
index da82a6e..b7074bd 100644
--- a/src/com/android/documentsui/sorting/TableHeaderController.java
+++ b/src/com/android/documentsui/sorting/TableHeaderController.java
@@ -37,6 +37,7 @@
     // We assign this here porque each method reference creates a new object
     // instance (which is wasteful).
     private final View.OnClickListener mOnCellClickListener = this::onCellClicked;
+    private final SortModel.UpdateListener mModelListener = this::onModelUpdate;
 
     private final SortModel mModel;
 
@@ -54,7 +55,7 @@
 
         onModelUpdate(mModel, SortModel.UPDATE_TYPE_UNSPECIFIED);
 
-        mModel.addListener(this::onModelUpdate);
+        mModel.addListener(mModelListener);
     }
 
     private void onModelUpdate(SortModel model, int updateTypeUnspecified) {
@@ -69,6 +70,11 @@
         mTableHeader.setVisibility(visibility);
     }
 
+    @Override
+    public void destroy() {
+        mModel.removeListener(mModelListener);
+    }
+
     private void bindCell(HeaderCell cell, @SortDimensionId int id) {
         assert(cell != null);
         SortDimension dimension = mModel.getDimensionById(id);
diff --git a/tests/unit/com/android/documentsui/sorting/SortControllerTest.java b/tests/unit/com/android/documentsui/sorting/SortControllerTest.java
index 32ac3dc..9c2cc64 100644
--- a/tests/unit/com/android/documentsui/sorting/SortControllerTest.java
+++ b/tests/unit/com/android/documentsui/sorting/SortControllerTest.java
@@ -32,37 +32,64 @@
 @SmallTest
 public class SortControllerTest {
 
-    // only created when in horizontal tablet layout.
-    private final TestWidget mTableHeader = null;
+    private TestWidget mTableHeader;
     private TestWidget mDropHeader;
     private SortController mController;
 
-    @Before
-    public void setUp() {
-        mDropHeader = new TestWidget();
-        mController = new SortController(mDropHeader, mTableHeader);
+    @Test
+    public void testGridMode_ShowsDrop() {
+        createWidget(true);
+        mController.onViewModeChanged(State.MODE_GRID);
+        mDropHeader.assertVisible();
+        mTableHeader.assertGone();
     }
 
     @Test
-    public void testGridMode_ShowsDrop() {
-        mController.onViewModeChanged(State.MODE_GRID);
+    public void testListMode_ShowsDrop_NoHeader() {
+        createWidget(false);
+        mController.onViewModeChanged(State.MODE_LIST);
         mDropHeader.assertVisible();
     }
 
     @Test
     public void testListMode_ShowsTable() {
+        createWidget(true);
         mController.onViewModeChanged(State.MODE_LIST);
-        mDropHeader.assertVisible();
+        mDropHeader.assertGone();
+        mTableHeader.assertVisible();
+    }
+
+    @Test
+    public void testDestroysWidgets() {
+        createWidget(true);
+        mController.destroy();
+
+        mDropHeader.assertDestroyed();
+        mTableHeader.assertDestroyed();
+    }
+
+    private void createWidget(boolean hasTableHeader) {
+        mDropHeader = new TestWidget();
+        if (hasTableHeader) {
+            mTableHeader = new TestWidget();
+        }
+        mController = new SortController(mDropHeader, mTableHeader);
     }
 
     static class TestWidget implements SortController.WidgetController {
         private int mVisibility;
+        private boolean mDestroyed;
 
         @Override
         public void setVisibility(int visibility) {
             mVisibility = visibility;
         }
 
+        @Override
+        public void destroy() {
+            mDestroyed = true;
+        }
+
         void assertVisible() {
             assertTrue(
                     "Expected mode VISIBLE, but was " + mVisibility,
@@ -74,5 +101,9 @@
                     "Expected mode GONE, but was " + mVisibility,
                     mVisibility == View.GONE);
         }
+
+        void assertDestroyed() {
+            assertTrue("Widget is not destroyed.", mDestroyed);
+        }
     }
 }