Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit de50fff3 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Update "Open networks available" toggle to instead open notification...

Merge "Update "Open networks available" toggle to instead open notification channel preferences." into oc-dev
parents 12c9f41c 2c4b42c0
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -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"
+64 −0
Original line number Diff line number Diff line
/*
 * 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();
        }
    }
}
+9 −6
Original line number Diff line number Diff line
@@ -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.NetworkScorerPickerPreferenceController;
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 @@ public class ConfigureWifiSettings extends DashboardFragment {
    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));
+63 −75
Original line number Diff line number Diff line
@@ -16,61 +16,56 @@

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) {
        super(context);
        lifecycle.addObserver(this);
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        mSettingObserver = new SettingObserver(screen.findPreference(KEY_NOTIFY_OPEN_NETWORKS));
    }
    private NetworkScoreManagerWrapper mNetworkScoreManager;
    private NotificationChannelHelper mNotificationChannelHelper;
    private PackageManager mPackageManager;

    @Override
    public void onResume() {
        if (mSettingObserver != null) {
            mSettingObserver.register(mContext.getContentResolver(), true /* register */);
        }
    public NotifyOpenNetworksPreferenceController(
            Context context,
            NetworkScoreManagerWrapper networkScoreManager,
            NotificationChannelHelper notificationChannelHelper,
            PackageManager packageManager) {
        super(context);
        mNetworkScoreManager = networkScoreManager;
        mNotificationChannelHelper = notificationChannelHelper;
        mPackageManager = packageManager;
    }

    @Override
    public void onPause() {
        if (mSettingObserver != null) {
            mSettingObserver.register(mContext.getContentResolver(), false /* register */);
        }
    public String getPreferenceKey() {
        return KEY_NOTIFY_OPEN_NETWORKS;
    }

    @Override
    public boolean isAvailable() {
        return true;
        return getNotificationChannel() != null;
    }

    @Override
@@ -78,57 +73,50 @@ public class NotifyOpenNetworksPreferenceController extends PreferenceController
        if (!TextUtils.equals(preference.getKey(), KEY_NOTIFY_OPEN_NETWORKS)) {
            return false;
        }
        if (!(preference instanceof SwitchPreference)) {
        NetworkScorerAppData scorer = mNetworkScoreManager.getActiveScorer();
        if (scorer == null) {
            return false;
        }
        Settings.Global.putInt(mContext.getContentResolver(),
                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
                ((SwitchPreference) preference).isChecked() ? 1 : 0);
        return true;
    }

    @Override
    public String getPreferenceKey() {
        return KEY_NOTIFY_OPEN_NETWORKS;
        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 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);
    }

    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;
        }

        public void register(ContentResolver cr, boolean register) {
            if (register) {
                cr.registerContentObserver(NETWORK_RECOMMENDATIONS_ENABLED_URI, false, this);
        NotificationChannelWrapper channel = getNotificationChannel();
        if (channel == null) {
            preference.setSummary(null);
        } else {
                cr.unregisterContentObserver(this);
            }
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
            super.onChange(selfChange, uri);
            if (NETWORK_RECOMMENDATIONS_ENABLED_URI.equals(uri)) {
                updateState(mPreference);
            }
            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;
        }
    }
}
+94 −39
Original line number Diff line number Diff line
@@ -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 @@ import org.robolectric.annotation.Config;
@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_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_shouldAlwaysReturnTrue() {
    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);

        mController.updateState(preference);
    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);

        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);

        mController.updateState(preference);
    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);

        verify(preference).setChecked(false);
        verify(preference).setEnabled(false);
        assertThat(pref.getSummary()).isEqualTo(
                mContext.getString(R.string.notification_toggle_off));
    }

}