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

Commit e4c2e427 authored by George Chang's avatar George Chang
Browse files

Fix NFC state switched off every time user entered connection preferences page

NfcAirplaneModeObserver added a scenario that
switched NFC off every time  a user entered connection
preferences page if airplane mode was on.
Even when a user manually switched on NFC, the observer would still
turn NFC off when re-entering connection preferences page.

GSAM TS.27 certification requires NFC state to be consistent
under AirplaneMode before and after reboot the device.
NfcAirplaneModeObserver breaks the requirement
because it would always switch NFC off under airplane mode
when a user checked the NFC state in settings page.

Fix it by removing NfcAirplaneModeObserver.
Keep the NFC state consistent.


Bug:128384879
Test: make RunSettingsRoboTests / Check Nfc on/off Status
Merged-In: If4c8e47c2509b09e8bc1a464e1ab329b945e3d20
Change-Id: If4c8e47c2509b09e8bc1a464e1ab329b945e3d20
parent f58cd0fb
Loading
Loading
Loading
Loading
+0 −83
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.nfc;

import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.nfc.NfcAdapter;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;

import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;

/**
 * NfcAirplaneModeObserver is a helper to manage the Nfc on/off when airplane mode status
 * is changed.
 */
public class NfcAirplaneModeObserver extends ContentObserver {

    private final Context mContext;
    private final NfcAdapter mNfcAdapter;
    private final Preference mPreference;
    private int mAirplaneMode;

    @VisibleForTesting
    final static Uri AIRPLANE_MODE_URI =
            Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);

    public NfcAirplaneModeObserver(Context context, NfcAdapter nfcAdapter, Preference preference) {
        super(new Handler(Looper.getMainLooper()));
        mContext = context;
        mNfcAdapter = nfcAdapter;
        mPreference = preference;
        updateNfcPreference();
    }

    public void register() {
        mContext.getContentResolver().registerContentObserver(AIRPLANE_MODE_URI, false, this);
    }

    public void unregister() {
        mContext.getContentResolver().unregisterContentObserver(this);
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {
        super.onChange(selfChange, uri);
        updateNfcPreference();
    }

    private void updateNfcPreference() {
        final int airplaneMode = Settings.Global.getInt(
                mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, mAirplaneMode);
        if (airplaneMode == mAirplaneMode) {
            return;
        }

        mAirplaneMode = airplaneMode;
        if (mAirplaneMode == 1) {
            // airplane mode is on, need to turn off NFC, and check if user can toggle it
            mNfcAdapter.disable();
            mPreference.setEnabled(NfcPreferenceController.isToggleableInAirplaneMode(mContext));
        } else {
            // airplane mode is off, no restriction
            mPreference.setEnabled(true);
        }
    }
}
+0 −13
Original line number Diff line number Diff line
@@ -41,8 +41,6 @@ public class NfcPreferenceController extends TogglePreferenceController
    public static final String KEY_TOGGLE_NFC = "toggle_nfc";
    private final NfcAdapter mNfcAdapter;
    private NfcEnabler mNfcEnabler;
    @VisibleForTesting
    NfcAirplaneModeObserver mAirplaneModeObserver;

    public NfcPreferenceController(Context context, String key) {
        super(context, key);
@@ -61,11 +59,6 @@ public class NfcPreferenceController extends TogglePreferenceController

        mNfcEnabler = new NfcEnabler(mContext, switchPreference);

        // Listen to airplane mode updates if NFC should be turned off when airplane mode is on
        if (shouldTurnOffNFCInAirplaneMode(mContext) || isToggleableInAirplaneMode(mContext)) {
            mAirplaneModeObserver =
                    new NfcAirplaneModeObserver(mContext, mNfcAdapter, switchPreference);
        }
    }

    @Override
@@ -108,9 +101,6 @@ public class NfcPreferenceController extends TogglePreferenceController

    @Override
    public void onResume() {
        if (mAirplaneModeObserver != null) {
            mAirplaneModeObserver.register();
        }
        if (mNfcEnabler != null) {
            mNfcEnabler.resume();
        }
@@ -118,9 +108,6 @@ public class NfcPreferenceController extends TogglePreferenceController

    @Override
    public void onPause() {
        if (mAirplaneModeObserver != null) {
            mAirplaneModeObserver.unregister();
        }
        if (mNfcEnabler != null) {
            mNfcEnabler.pause();
        }
+0 −117
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.nfc;

import static com.google.common.truth.Truth.assertThat;

import android.content.ContentResolver;
import android.content.Context;
import android.nfc.NfcAdapter;
import android.provider.Settings;
import android.provider.Settings.Global;

import androidx.preference.SwitchPreference;

import com.android.settings.testutils.shadow.ShadowNfcAdapter;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowNfcAdapter.class})
public class NfcAirplaneModeObserverTest {

    private Context mContext;
    private NfcAdapter mNfcAdapter;
    private SwitchPreference mNfcPreference;
    private NfcAirplaneModeObserver mNfcAirplaneModeObserver;

    @Before
    public void setUp() {
        mContext = RuntimeEnvironment.application;
        mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext);

        mNfcPreference = new SwitchPreference(mContext);

        mNfcAirplaneModeObserver =
                new NfcAirplaneModeObserver(mContext, mNfcAdapter, mNfcPreference);
    }

    @Test
    public void NfcAirplaneModeObserver_airplaneOn_shouldDisableNfc() {
        ReflectionHelpers.setField(mNfcAirplaneModeObserver,
                "mAirplaneMode", 0);
        Settings.Global.putInt(mContext.getContentResolver(),
                Settings.Global.AIRPLANE_MODE_ON, 1);

        mNfcAirplaneModeObserver.onChange(false,
                NfcAirplaneModeObserver.AIRPLANE_MODE_URI);

        assertThat(mNfcAdapter.isEnabled()).isFalse();
    }

    @Test
    public void NfcAirplaneModeObserver_airplaneModeOnNfcToggleable_shouldEnablePreference() {
        ReflectionHelpers.setField(mNfcAirplaneModeObserver, "mAirplaneMode", 0);
        final ContentResolver contentResolver = mContext.getContentResolver();
        Settings.Global.putInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 1);
        Settings.Global.putString(contentResolver,
                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, Settings.Global.RADIO_NFC);

        mNfcAirplaneModeObserver.onChange(false, NfcAirplaneModeObserver.AIRPLANE_MODE_URI);

        assertThat(mNfcPreference.isEnabled()).isTrue();
    }

    @Test
    public void NfcAirplaneModeObserver_airplaneModeOnNfcNotToggleable_shouldDisablePreference() {
        ReflectionHelpers.setField(mNfcAirplaneModeObserver, "mAirplaneMode", 0);
        final ContentResolver contentResolver = mContext.getContentResolver();
        Settings.Global.putInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 1);
        Settings.Global.putString(contentResolver,
                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, Global.RADIO_WIFI);

        mNfcAirplaneModeObserver.onChange(false, NfcAirplaneModeObserver.AIRPLANE_MODE_URI);

        assertThat(mNfcPreference.isEnabled()).isFalse();
    }

    @Test
    public void NfcAirplaneModeObserver_airplaneModeOff_shouldEnablePreference() {
        ReflectionHelpers.setField(mNfcAirplaneModeObserver, "mAirplaneMode", 1);
        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);

        mNfcAirplaneModeObserver.onChange(false, NfcAirplaneModeObserver.AIRPLANE_MODE_URI);

        assertThat(mNfcPreference.isEnabled()).isTrue();
    }

    @Test
    public void NfcAirplaneModeObserver_airplaneModeOff_shouldNotEnableNfcAutomatically() {
        ReflectionHelpers.setField(mNfcAirplaneModeObserver, "mAirplaneMode", 1);
        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);

        mNfcAirplaneModeObserver.onChange(false, NfcAirplaneModeObserver.AIRPLANE_MODE_URI);

        assertThat(mNfcAdapter.isEnabled()).isFalse();
    }
}
+0 −32
Original line number Diff line number Diff line
@@ -222,38 +222,6 @@ public class NfcPreferenceControllerTest {
        assertThat(NfcPreferenceController.shouldTurnOffNFCInAirplaneMode(mContext)).isFalse();
    }

    @Test
    public void displayPreference_airplaneModeRadiosContainsNfc_shouldCreateAirplaneModeObserver() {
        Settings.Global.putString(mContext.getContentResolver(),
            Settings.Global.AIRPLANE_MODE_RADIOS, Settings.Global.RADIO_NFC);

        mNfcController.displayPreference(mScreen);

        assertThat(mNfcController.mAirplaneModeObserver).isNotNull();
    }

    @Test
    public void displayPreference_nfcToggleableInAirplaneMode_shouldCreateAirplaneModeObserver() {
        Settings.Global.putString(mContext.getContentResolver(),
            Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, Settings.Global.RADIO_NFC);

        mNfcController.displayPreference(mScreen);

        assertThat(mNfcController.mAirplaneModeObserver).isNotNull();
    }

    @Test
    public void displayPreference_nfcNotAffectByAirplaneMode_shouldNotCreateAirplaneModeObserver() {
        Settings.Global.putString(mContext.getContentResolver(),
            Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, "");
        Settings.Global.putString(mContext.getContentResolver(),
            Settings.Global.AIRPLANE_MODE_RADIOS, "");

        mNfcController.displayPreference(mScreen);

        assertThat(mNfcController.mAirplaneModeObserver).isNull();
    }

    @Test
    public void ncfSliceWorker_nfcBroadcast_noExtra_sliceDoesntUpdate() {
        final NfcSliceWorker worker = spy(new NfcSliceWorker(mContext, getDummyUri()));