Merge "Update "Open networks available" toggle to instead open notification channel preferences." into oc-dev
am: de50fff3c2

Change-Id: I500d13e65b8aa63b62e5eacb750ed2a6a1ffc163
diff --git a/res/xml/wifi_configure_settings.xml b/res/xml/wifi_configure_settings.xml
index fa5239d..b1625cc 100644
--- a/res/xml/wifi_configure_settings.xml
+++ b/res/xml/wifi_configure_settings.xml
@@ -31,11 +31,10 @@
         android:title="@string/use_open_wifi_automatically_title"
         android:summary="@string/use_open_wifi_automatically_summary" />
 
-    <SwitchPreference
+    <Preference
             android:key="notify_open_networks"
             android:title="@string/wifi_notify_open_networks"
-            android:icon="@drawable/ic_settings_notifications"
-            android:summary="@string/wifi_notify_open_networks_summary" />
+            android:icon="@drawable/ic_settings_notifications"/>
 
     <SwitchPreference
         android:key="wifi_cellular_data_fallback"
diff --git a/src/com/android/settings/utils/NotificationChannelHelper.java b/src/com/android/settings/utils/NotificationChannelHelper.java
new file mode 100644
index 0000000..bf008dc
--- /dev/null
+++ b/src/com/android/settings/utils/NotificationChannelHelper.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package com.android.settings.utils;
+
+import android.app.INotificationManager;
+import android.app.NotificationChannel;
+import android.os.RemoteException;
+
+/**
+ * Wrappers around methods in {@link INotificationManager} and {@link NotificationChannel} to
+ * facilitate unit testing.
+ *
+ * TODO: delete this class once robolectric supports Android O
+ */
+public class NotificationChannelHelper {
+    private INotificationManager mNotificationManager;
+
+    public NotificationChannelHelper(
+            INotificationManager notificationManager) {
+        mNotificationManager = notificationManager;
+    }
+
+    /**
+     * Returns the notification channel settings for a app given its package name, user id, and
+     * channel id.
+     */
+    public NotificationChannelWrapper getNotificationChannelForPackage(String pkg, int uid,
+            String channelId, boolean includeDeleted) throws RemoteException {
+        NotificationChannel channel = mNotificationManager.getNotificationChannelForPackage(
+                pkg, uid, channelId, includeDeleted);
+        return channel == null ? null : new NotificationChannelWrapper(channel);
+    }
+
+    /**
+     * Wrapper around {@link NotificationChannel} to facilitate unit testing.
+     *
+     * TODO: delete this class once robolectric supports Android O
+     */
+    public class NotificationChannelWrapper {
+        private NotificationChannel mChannel;
+
+        public NotificationChannelWrapper(NotificationChannel channel) {
+            mChannel = channel;
+        }
+
+        public int getImportance() {
+            return mChannel.getImportance();
+        }
+    }
+}
diff --git a/src/com/android/settings/wifi/ConfigureWifiSettings.java b/src/com/android/settings/wifi/ConfigureWifiSettings.java
index af80fd4..24d62ad 100644
--- a/src/com/android/settings/wifi/ConfigureWifiSettings.java
+++ b/src/com/android/settings/wifi/ConfigureWifiSettings.java
@@ -15,15 +15,13 @@
  */
 package com.android.settings.wifi;
 
-import static android.content.Context.NETWORK_SCORE_SERVICE;
-import static android.content.Context.WIFI_SERVICE;
-
+import android.app.INotificationManager;
 import android.content.Context;
 import android.content.Intent;
 import android.net.NetworkScoreManager;
 import android.net.wifi.WifiManager;
+import android.os.ServiceManager;
 import android.provider.SearchIndexableResource;
-
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
@@ -34,6 +32,7 @@
 import com.android.settings.network.WifiCallingPreferenceController;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
+import com.android.settings.utils.NotificationChannelHelper;
 import com.android.settings.wifi.p2p.WifiP2pPreferenceController;
 
 import java.util.ArrayList;
@@ -73,14 +72,18 @@
     protected List<PreferenceController> getPreferenceControllers(Context context) {
         final NetworkScoreManagerWrapper networkScoreManagerWrapper =
                 new NetworkScoreManagerWrapper(context.getSystemService(NetworkScoreManager.class));
+        final NotificationChannelHelper notificationChannelHelper =
+                new NotificationChannelHelper(INotificationManager.Stub.asInterface(
+                        ServiceManager.getService(Context.NOTIFICATION_SERVICE)));
+        final WifiManager wifiManager = context.getSystemService(WifiManager.class);
         mUseOpenWifiPreferenceController = new UseOpenWifiPreferenceController(context, this,
                 networkScoreManagerWrapper, getLifecycle());
-        final WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
         final List<PreferenceController> controllers = new ArrayList<>();
         controllers.add(new WifiWakeupPreferenceController(context, getLifecycle()));
         controllers.add(new NetworkScorerPickerPreferenceController(context,
                 networkScoreManagerWrapper));
-        controllers.add(new NotifyOpenNetworksPreferenceController(context, getLifecycle()));
+        controllers.add(new NotifyOpenNetworksPreferenceController(context,
+                networkScoreManagerWrapper, notificationChannelHelper, getPackageManager()));
         controllers.add(mUseOpenWifiPreferenceController);
         controllers.add(new WifiSleepPolicyPreferenceController(context));
         controllers.add(new WifiInfoPreferenceController(context, getLifecycle(), wifiManager));
diff --git a/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceController.java b/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceController.java
index 8771da4..a85a266 100644
--- a/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceController.java
+++ b/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceController.java
@@ -16,75 +16,46 @@
 
 package com.android.settings.wifi;
 
-import android.content.ContentResolver;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
 import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.NetworkScorerAppData;
+import android.os.RemoteException;
 import android.provider.Settings;
-import android.support.v14.preference.SwitchPreference;
+import android.support.annotation.Nullable;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
 import android.text.TextUtils;
-
+import android.util.Log;
+import com.android.settings.R;
 import com.android.settings.core.PreferenceController;
-import com.android.settings.core.lifecycle.Lifecycle;
-import com.android.settings.core.lifecycle.LifecycleObserver;
-import com.android.settings.core.lifecycle.events.OnPause;
-import com.android.settings.core.lifecycle.events.OnResume;
+import com.android.settings.network.NetworkScoreManagerWrapper;
+import com.android.settings.utils.NotificationChannelHelper;
+import com.android.settings.utils.NotificationChannelHelper.NotificationChannelWrapper;
 
 /**
- * {@link PreferenceController} that controls whether we should notify user when open network is
- * available.
+ * {@link PreferenceController} that shows whether we should notify user when open network is
+ * available. The preference links to {@link NotificationChannel} settings.
  */
-public class NotifyOpenNetworksPreferenceController extends PreferenceController implements
-        LifecycleObserver, OnResume, OnPause {
+public class NotifyOpenNetworksPreferenceController extends PreferenceController {
 
+    private static final String TAG = "OpenNetworks";
     private static final String KEY_NOTIFY_OPEN_NETWORKS = "notify_open_networks";
-    private SettingObserver mSettingObserver;
 
-    public NotifyOpenNetworksPreferenceController(Context context, Lifecycle lifecycle) {
+    private NetworkScoreManagerWrapper mNetworkScoreManager;
+    private NotificationChannelHelper mNotificationChannelHelper;
+    private PackageManager mPackageManager;
+
+    public NotifyOpenNetworksPreferenceController(
+            Context context,
+            NetworkScoreManagerWrapper networkScoreManager,
+            NotificationChannelHelper notificationChannelHelper,
+            PackageManager packageManager) {
         super(context);
-        lifecycle.addObserver(this);
-    }
-
-    @Override
-    public void displayPreference(PreferenceScreen screen) {
-        super.displayPreference(screen);
-        mSettingObserver = new SettingObserver(screen.findPreference(KEY_NOTIFY_OPEN_NETWORKS));
-    }
-
-    @Override
-    public void onResume() {
-        if (mSettingObserver != null) {
-            mSettingObserver.register(mContext.getContentResolver(), true /* register */);
-        }
-    }
-
-    @Override
-    public void onPause() {
-        if (mSettingObserver != null) {
-            mSettingObserver.register(mContext.getContentResolver(), false /* register */);
-        }
-    }
-
-    @Override
-    public boolean isAvailable() {
-        return true;
-    }
-
-    @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        if (!TextUtils.equals(preference.getKey(), KEY_NOTIFY_OPEN_NETWORKS)) {
-            return false;
-        }
-        if (!(preference instanceof SwitchPreference)) {
-            return false;
-        }
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
-                ((SwitchPreference) preference).isChecked() ? 1 : 0);
-        return true;
+        mNetworkScoreManager = networkScoreManager;
+        mNotificationChannelHelper = notificationChannelHelper;
+        mPackageManager = packageManager;
     }
 
     @Override
@@ -93,42 +64,59 @@
     }
 
     @Override
-    public void updateState(Preference preference) {
-        if (!(preference instanceof SwitchPreference)) {
-            return;
-        }
-        final SwitchPreference notifyOpenNetworks = (SwitchPreference) preference;
-        notifyOpenNetworks.setChecked(Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
-        notifyOpenNetworks.setEnabled(Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0) == 1);
+    public boolean isAvailable() {
+        return getNotificationChannel() != null;
     }
 
-    class SettingObserver extends ContentObserver {
-        private final Uri NETWORK_RECOMMENDATIONS_ENABLED_URI =
-                Settings.Global.getUriFor(Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED);
-
-        private final Preference mPreference;
-
-        public SettingObserver(Preference preference) {
-            super(new Handler());
-            mPreference = preference;
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), KEY_NOTIFY_OPEN_NETWORKS)) {
+            return false;
+        }
+        NetworkScorerAppData scorer = mNetworkScoreManager.getActiveScorer();
+        if (scorer == null) {
+            return false;
         }
 
-        public void register(ContentResolver cr, boolean register) {
-            if (register) {
-                cr.registerContentObserver(NETWORK_RECOMMENDATIONS_ENABLED_URI, false, this);
-            } else {
-                cr.unregisterContentObserver(this);
-            }
-        }
+        Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
+        intent.putExtra(Settings.EXTRA_CHANNEL_ID,
+                scorer.getNetworkAvailableNotificationChannelId());
+        intent.putExtra(Settings.EXTRA_APP_PACKAGE, scorer.getRecommendationServicePackageName());
+        mContext.startActivity(intent);
+        return true;
+    }
 
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            super.onChange(selfChange, uri);
-            if (NETWORK_RECOMMENDATIONS_ENABLED_URI.equals(uri)) {
-                updateState(mPreference);
-            }
+    @Override
+    public void updateState(Preference preference) {
+        NotificationChannelWrapper channel = getNotificationChannel();
+        if (channel == null) {
+            preference.setSummary(null);
+        } else {
+            preference.setSummary(channel.getImportance() != NotificationManager.IMPORTANCE_NONE ?
+                    R.string.notification_toggle_on : R.string.notification_toggle_off);
+        }
+    }
+
+    @Nullable
+    private NotificationChannelWrapper getNotificationChannel() {
+        NetworkScorerAppData scorer = mNetworkScoreManager.getActiveScorer();
+        if (scorer == null) {
+            return null;
+        }
+        String packageName = scorer.getRecommendationServicePackageName();
+        String channelId = scorer.getNetworkAvailableNotificationChannelId();
+        if (packageName == null || channelId == null) {
+            return null;
+        }
+        try {
+            return mNotificationChannelHelper.getNotificationChannelForPackage(
+                    packageName,
+                    mPackageManager.getPackageUid(packageName, 0 /* flags */),
+                    channelId,
+                    false /* includeDeleted */ );
+        } catch (RemoteException | PackageManager.NameNotFoundException e) {
+            Log.d(TAG, "Failed to get notification channel.", e);
+            return null;
         }
     }
 }
diff --git a/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworkPreferenceControllerTest.java
index 3afa7fb..78dbcbd 100644
--- a/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworkPreferenceControllerTest.java
@@ -16,26 +16,29 @@
 
 package com.android.settings.wifi;
 
-import static android.provider.Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED;
-import static android.provider.Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON;
-
 import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.when;
 
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
+import android.app.NotificationManager;
+import android.content.ComponentName;
 import android.content.Context;
-import android.provider.Settings;
-import android.support.v14.preference.SwitchPreference;
+import android.content.pm.PackageManager;
+import android.net.NetworkScorerAppData;
+import android.os.RemoteException;
 import android.support.v7.preference.Preference;
-
+import com.android.settings.R;
 import com.android.settings.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
-import com.android.settings.core.lifecycle.Lifecycle;
-
+import com.android.settings.network.NetworkScoreManagerWrapper;
+import com.android.settings.utils.NotificationChannelHelper;
+import com.android.settings.utils.NotificationChannelHelper.NotificationChannelWrapper;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
@@ -44,71 +47,123 @@
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class NotifyOpenNetworkPreferenceControllerTest {
 
+    private static final String TEST_SCORER_PACKAGE = "Test Package";
+    private static final String TEST_SCORER_CLASS = "Test Class";
+    private static final String TEST_SCORER_LABEL = "Test Label";
+    private static final String NOTIFICATION_ID = "Notification Id";
+    private static final CharSequence NOTIFICATION_NAME = "Notification Name";
+
     private Context mContext;
     private NotifyOpenNetworksPreferenceController mController;
+    @Mock private NetworkScoreManagerWrapper mNetworkScorer;
+    @Mock private NotificationChannelHelper mNotificationChannelHelper;
+    @Mock private PackageManager mPackageManager;
+    @Mock private NotificationChannelWrapper mChannel;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
-        mController = new NotifyOpenNetworksPreferenceController(mContext, mock(Lifecycle.class));
+        mController = new NotifyOpenNetworksPreferenceController(
+                mContext, mNetworkScorer, mNotificationChannelHelper, mPackageManager);
+        ComponentName scorer = new ComponentName(TEST_SCORER_PACKAGE, TEST_SCORER_CLASS);
+
+        NetworkScorerAppData scorerAppData = new NetworkScorerAppData(
+                0, scorer, TEST_SCORER_LABEL, null /* enableUseOpenWifiActivity */,
+                NOTIFICATION_ID);
+        when(mNetworkScorer.getActiveScorer()).thenReturn(scorerAppData);
     }
 
     @Test
-    public void testIsAvailable_shouldAlwaysReturnTrue() {
+    public void testIsAvailable_shouldReturnFalseWhenScorerDoesNotExist()
+            throws RemoteException {
+        when(mNetworkScorer.getActiveScorer()).thenReturn(null);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void testIsAvailable_shouldReturnFalseWhenNotificationChannelIdDoesNotExist()
+            throws RemoteException {
+        ComponentName scorer = new ComponentName(TEST_SCORER_PACKAGE, TEST_SCORER_CLASS);
+        NetworkScorerAppData scorerAppData = new NetworkScorerAppData(
+                0, scorer, TEST_SCORER_LABEL, null /* enableUseOpenWifiActivity */,
+                null /* networkAvailableNotificationChannelId */);
+        when(mNetworkScorer.getActiveScorer()).thenReturn(scorerAppData);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void testIsAvailable_shouldReturnFalseWhenNotificationChannelDoesNotExist()
+            throws RemoteException {
+        when(mNotificationChannelHelper.getNotificationChannelForPackage(
+                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(null);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void testIsAvailable_shouldReturnTrueWhenNotificationChannelExists()
+            throws RemoteException {
+        when(mNotificationChannelHelper.getNotificationChannelForPackage(
+                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(mChannel);
+
         assertThat(mController.isAvailable()).isTrue();
     }
 
     @Test
     public void handlePreferenceTreeClick_nonMatchingKey_shouldDoNothing() {
-        final SwitchPreference pref = new SwitchPreference(mContext);
+        final Preference pref = new Preference(mContext);
 
         assertThat(mController.handlePreferenceTreeClick(pref)).isFalse();
     }
 
     @Test
-    public void handlePreferenceTreeClick_nonMatchingType_shouldDoNothing() {
+    public void handlePreferenceTreeClick_nullScorer_shouldDoNothing() {
         final Preference pref = new Preference(mContext);
         pref.setKey(mController.getPreferenceKey());
+        when(mNetworkScorer.getActiveScorer()).thenReturn(null);
 
         assertThat(mController.handlePreferenceTreeClick(pref)).isFalse();
     }
 
     @Test
-    public void handlePreferenceTreeClick_matchingKeyAndType_shouldUpdateSetting() {
-        final SwitchPreference pref = new SwitchPreference(mContext);
-        pref.setChecked(true);
+    public void handlePreferenceTreeClick_matchingKeyAndScorerExists_shouldLaunchActivity()
+            throws RemoteException {
+        final Preference pref = new Preference(mContext);
         pref.setKey(mController.getPreferenceKey());
+        when(mNotificationChannelHelper.getNotificationChannelForPackage(
+                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(mChannel);
 
         assertThat(mController.handlePreferenceTreeClick(pref)).isTrue();
-        assertThat(Settings.Global.getInt(mContext.getContentResolver(),
-                WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0))
-                .isEqualTo(1);
     }
 
     @Test
-    public void updateState_preferenceSetCheckedAndSetEnabledWhenSettingsAreEnabled() {
-        final SwitchPreference preference = mock(SwitchPreference.class);
-        Settings.System.putInt(mContext.getContentResolver(), NETWORK_RECOMMENDATIONS_ENABLED, 1);
-        Settings.System.putInt(mContext.getContentResolver(),
-                WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1);
+    public void updateState_notificationsEnabled_shouldShowEnabledSummary() throws RemoteException {
+        final Preference pref = new Preference(mContext);
+        pref.setKey(mController.getPreferenceKey());
+        when(mNotificationChannelHelper.getNotificationChannelForPackage(
+                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(mChannel);
+        when(mChannel.getImportance()).thenReturn(NotificationManager.IMPORTANCE_DEFAULT);
+        mController.updateState(pref);
 
-        mController.updateState(preference);
-
-        verify(preference).setChecked(true);
-        verify(preference).setEnabled(true);
+        assertThat(pref.getSummary()).isEqualTo(
+                mContext.getString(R.string.notification_toggle_on));
     }
 
     @Test
-    public void updateState_preferenceSetCheckedAndSetEnabledWhenSettingsAreDisabled() {
-        final SwitchPreference preference = mock(SwitchPreference.class);
-        Settings.System.putInt(mContext.getContentResolver(), NETWORK_RECOMMENDATIONS_ENABLED, 0);
-        Settings.System.putInt(mContext.getContentResolver(),
-                WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0);
+    public void updateState_notificationsEnabled_shouldShowDisabledSummary()
+            throws RemoteException {
+        final Preference pref = new Preference(mContext);
+        pref.setKey(mController.getPreferenceKey());
+        when(mNotificationChannelHelper.getNotificationChannelForPackage(
+                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(mChannel);
+        when(mChannel.getImportance()).thenReturn(NotificationManager.IMPORTANCE_NONE);
+        mController.updateState(pref);
 
-        mController.updateState(preference);
-
-        verify(preference).setChecked(false);
-        verify(preference).setEnabled(false);
+        assertThat(pref.getSummary()).isEqualTo(
+                mContext.getString(R.string.notification_toggle_off));
     }
+
 }