diff --git a/res/xml/system_dashboard_fragment.xml b/res/xml/system_dashboard_fragment.xml index 9de28b4aaa5..36ae6f1833c 100644 --- a/res/xml/system_dashboard_fragment.xml +++ b/res/xml/system_dashboard_fragment.xml @@ -25,4 +25,13 @@ + + + + \ No newline at end of file diff --git a/src/com/android/settings/DeviceInfoSettings.java b/src/com/android/settings/DeviceInfoSettings.java index d82adbdfbdb..a9b170ca435 100644 --- a/src/com/android/settings/DeviceInfoSettings.java +++ b/src/com/android/settings/DeviceInfoSettings.java @@ -21,7 +21,6 @@ import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; -import android.os.PersistableBundle; import android.os.SELinux; import android.os.SystemClock; import android.os.SystemProperties; @@ -31,13 +30,15 @@ import android.provider.SearchIndexableResource; import android.provider.Settings; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceGroup; -import android.telephony.CarrierConfigManager; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.SummaryLoader; +import com.android.settings.deviceinfo.SystemUpdatePreferenceController; +import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Index; import com.android.settings.search.Indexable; @@ -56,7 +57,6 @@ public class DeviceInfoSettings extends SettingsPreferenceFragment implements In private static final String KEY_MANUAL = "manual"; private static final String KEY_REGULATORY_INFO = "regulatory_info"; - private static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings"; private static final String PROPERTY_URL_SAFETYLEGAL = "ro.url.safetylegal"; private static final String PROPERTY_SELINUX_STATUS = "ro.build.selinux"; private static final String KEY_KERNEL_VERSION = "kernel_version"; @@ -66,7 +66,6 @@ public class DeviceInfoSettings extends SettingsPreferenceFragment implements In private static final String KEY_BASEBAND_VERSION = "baseband_version"; private static final String KEY_FIRMWARE_VERSION = "firmware_version"; private static final String KEY_SECURITY_PATCH = "security_patch"; - private static final String KEY_UPDATE_SETTING = "additional_system_update_settings"; private static final String KEY_EQUIPMENT_ID = "fcc_equipment_id"; private static final String PROPERTY_EQUIPMENT_ID = "ro.ril.fccid"; private static final String KEY_DEVICE_FEEDBACK = "device_feedback"; @@ -77,6 +76,8 @@ public class DeviceInfoSettings extends SettingsPreferenceFragment implements In long[] mHits = new long[3]; int mDevHitCountdown; Toast mDevHitToast; + private SystemUpdatePreferenceController mSystemUpdatePreferenceController; + private DashboardFeatureProvider mDashboardFeatureProvider; private UserManager mUm; @@ -98,7 +99,11 @@ public class DeviceInfoSettings extends SettingsPreferenceFragment implements In @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - mUm = UserManager.get(getActivity()); + final Activity activity = getActivity(); + mUm = UserManager.get(activity); + mSystemUpdatePreferenceController = new SystemUpdatePreferenceController(activity, mUm); + mDashboardFeatureProvider = FeatureFactory.getFactory(activity) + .getDashboardFeatureProvider(activity); addPreferencesFromResource(R.xml.device_info_settings); @@ -153,23 +158,7 @@ public class DeviceInfoSettings extends SettingsPreferenceFragment implements In * Settings is a generic app and should not contain any device-specific * info. */ - final Activity act = getActivity(); - - // These are contained by the root preference screen - PreferenceGroup parentPreference = getPreferenceScreen(); - - if (mUm.isAdminUser()) { - Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference, - KEY_SYSTEM_UPDATE_SETTINGS, - Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY); - } else { - // Remove for secondary users - removePreference(KEY_SYSTEM_UPDATE_SETTINGS); - } - - // Read platform settings for additional system update setting - removePreferenceIfBoolFalse(KEY_UPDATE_SETTING, - R.bool.config_additional_system_update_setting_enable); + mSystemUpdatePreferenceController.displayPreference(getPreferenceScreen()); // Remove manual entry if none present. removePreferenceIfBoolFalse(KEY_MANUAL, R.bool.config_show_manual); @@ -278,38 +267,11 @@ public class DeviceInfoSettings extends SettingsPreferenceFragment implements In } } else if (preference.getKey().equals(KEY_DEVICE_FEEDBACK)) { sendFeedback(); - } else if(preference.getKey().equals(KEY_SYSTEM_UPDATE_SETTINGS)) { - CarrierConfigManager configManager = - (CarrierConfigManager) getSystemService(Context.CARRIER_CONFIG_SERVICE); - PersistableBundle b = configManager.getConfig(); - if (b != null && b.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) { - ciActionOnSysUpdate(b); - } } + mSystemUpdatePreferenceController.handlePreferenceTreeClick(preference); return super.onPreferenceTreeClick(preference); } - /** - * Trigger client initiated action (send intent) on system update - */ - private void ciActionOnSysUpdate(PersistableBundle b) { - String intentStr = b.getString(CarrierConfigManager. - KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING); - if (!TextUtils.isEmpty(intentStr)) { - String extra = b.getString(CarrierConfigManager. - KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING); - String extraVal = b.getString(CarrierConfigManager. - KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING); - - Intent intent = new Intent(intentStr); - if (!TextUtils.isEmpty(extra)) { - intent.putExtra(extra, extraVal); - } - Log.d(LOG_TAG, "ciActionOnSysUpdate: broadcasting intent " + intentStr + - " with extra " + extra + ", " + extraVal); - getActivity().getApplicationContext().sendBroadcast(intent); - } - } private void removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup, String preference, String property ) { @@ -434,15 +396,8 @@ public class DeviceInfoSettings extends SettingsPreferenceFragment implements In if (TextUtils.isEmpty(DeviceInfoUtils.getFeedbackReporterPackage(context))) { keys.add(KEY_DEVICE_FEEDBACK); } - final UserManager um = UserManager.get(context); - // TODO: system update needs to be fixed for non-owner user b/22760654 - if (!um.isAdminUser()) { - keys.add(KEY_SYSTEM_UPDATE_SETTINGS); - } - if (!context.getResources().getBoolean( - R.bool.config_additional_system_update_setting_enable)) { - keys.add(KEY_UPDATE_SETTING); - } + new SystemUpdatePreferenceController(context, UserManager.get(context)) + .updateNonIndexableKeys(keys); return keys; } diff --git a/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java b/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java new file mode 100644 index 00000000000..406750f5df1 --- /dev/null +++ b/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2016 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.deviceinfo; + +import android.content.Context; +import android.content.Intent; +import android.os.PersistableBundle; +import android.os.UserManager; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.telephony.CarrierConfigManager; +import android.text.TextUtils; +import android.util.Log; + +import com.android.settings.R; +import com.android.settings.Utils; + +import java.util.List; + +import static android.content.Context.CARRIER_CONFIG_SERVICE; + +public class SystemUpdatePreferenceController { + + private static final String TAG = "SysUpdatePrefContr"; + + static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings"; + static final String KEY_UPDATE_SETTING = "additional_system_update_settings"; + + private final Context mContext; + private final UserManager mUm; + + public SystemUpdatePreferenceController(Context context, UserManager um) { + mContext = context; + mUm = um; + } + + /** + * Displays preference in this controller. + */ + public void displayPreference(PreferenceScreen screen) { + if (isAvailable(mContext, KEY_SYSTEM_UPDATE_SETTINGS)) { + Utils.updatePreferenceToSpecificActivityOrRemove(mContext, screen, + KEY_SYSTEM_UPDATE_SETTINGS, + Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY); + } else { + removePreference(screen, KEY_SYSTEM_UPDATE_SETTINGS); + } + + if (!isAvailable(mContext, KEY_UPDATE_SETTING)) { + removePreference(screen, KEY_UPDATE_SETTING); + } + } + + /** + * Updates non-indexable keys for search provider. + * + * Called by SearchIndexProvider#getNonIndexableKeys + */ + public void updateNonIndexableKeys(List keys) { + // TODO: system update needs to be fixed for non-owner user b/22760654 + if (!isAvailable(mContext, KEY_SYSTEM_UPDATE_SETTINGS)) { + keys.add(KEY_SYSTEM_UPDATE_SETTINGS); + } + if (!isAvailable(mContext, KEY_UPDATE_SETTING)) { + keys.add(KEY_UPDATE_SETTING); + } + } + + /** + * Handles preference tree click + * + * @param preference the preference being clicked + * @return true if click is handled + */ + public boolean handlePreferenceTreeClick(Preference preference) { + if (KEY_SYSTEM_UPDATE_SETTINGS.equals(preference.getKey())) { + CarrierConfigManager configManager = + (CarrierConfigManager) mContext.getSystemService(CARRIER_CONFIG_SERVICE); + PersistableBundle b = configManager.getConfig(); + if (b != null && b.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) { + ciActionOnSysUpdate(b); + } + } + // always return false here because this handler does not want to block other handlers. + return false; + } + + /** + * Whether a preference should be available on screen. + */ + private boolean isAvailable(Context context, String key) { + switch (key) { + case KEY_SYSTEM_UPDATE_SETTINGS: + return mUm.isAdminUser(); + case KEY_UPDATE_SETTING: + return context.getResources().getBoolean( + R.bool.config_additional_system_update_setting_enable); + default: + return false; + } + } + + /** + * Removes preference from screen. + */ + private void removePreference(PreferenceScreen screen, String key) { + Preference pref = screen.findPreference(key); + if (pref != null) { + screen.removePreference(pref); + } + } + + /** + * Trigger client initiated action (send intent) on system update + */ + private void ciActionOnSysUpdate(PersistableBundle b) { + String intentStr = b.getString(CarrierConfigManager. + KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING); + if (!TextUtils.isEmpty(intentStr)) { + String extra = b.getString(CarrierConfigManager. + KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING); + String extraVal = b.getString(CarrierConfigManager. + KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING); + + Intent intent = new Intent(intentStr); + if (!TextUtils.isEmpty(extra)) { + intent.putExtra(extra, extraVal); + } + Log.d(TAG, "ciActionOnSysUpdate: broadcasting intent " + intentStr + + " with extra " + extra + ", " + extraVal); + mContext.getApplicationContext().sendBroadcast(intent); + } + } +} diff --git a/src/com/android/settings/system/SystemDashboardFragment.java b/src/com/android/settings/system/SystemDashboardFragment.java index ca56255dd4e..ab8cc8d80dc 100644 --- a/src/com/android/settings/system/SystemDashboardFragment.java +++ b/src/com/android/settings/system/SystemDashboardFragment.java @@ -17,6 +17,7 @@ package com.android.settings.system; import android.content.Context; import android.os.Bundle; +import android.os.UserManager; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; @@ -24,16 +25,17 @@ import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.DashboardTilePreference; +import com.android.settings.deviceinfo.SystemUpdatePreferenceController; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; import java.util.List; -public class SystemDashboardFragment extends SettingsPreferenceFragment implements - Preference.OnPreferenceClickListener { +public class SystemDashboardFragment extends SettingsPreferenceFragment { private DashboardFeatureProvider mDashboardFeatureProvider; + private SystemUpdatePreferenceController mSystemUpdatePreferenceController; @Override public int getMetricsCategory() { @@ -45,19 +47,23 @@ public class SystemDashboardFragment extends SettingsPreferenceFragment implemen super.onAttach(context); mDashboardFeatureProvider = FeatureFactory.getFactory(context).getDashboardFeatureProvider(context); + mSystemUpdatePreferenceController = + new SystemUpdatePreferenceController(context, UserManager.get(context)); } @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { super.onCreatePreferences(savedInstanceState, rootKey); addPreferencesFromResource(R.xml.system_dashboard_fragment); + mSystemUpdatePreferenceController.displayPreference(getPreferenceScreen()); addDashboardCategoryAsPreference(); } @Override - public boolean onPreferenceClick(Preference preference) { - // Needed to enable preference click ripple - return false; + public boolean onPreferenceTreeClick(Preference preference) { + final boolean handled = + mSystemUpdatePreferenceController.handlePreferenceTreeClick(preference); + return handled || super.onPreferenceTreeClick(preference); } /** diff --git a/tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java new file mode 100644 index 00000000000..24bb8fe7b26 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2016 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.deviceinfo; + +import android.content.Context; +import android.os.UserManager; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.TestConfig; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; +import java.util.List; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Answers.RETURNS_DEEP_STUBS; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SystemUpdatePreferenceControllerTest { + + @Mock(answer = RETURNS_DEEP_STUBS) + private Context mContext; + @Mock + private UserManager mUserManager; + @Mock(answer = RETURNS_DEEP_STUBS) + private PreferenceScreen mScreen; + + private SystemUpdatePreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mController = new SystemUpdatePreferenceController(mContext, mUserManager); + } + + @Test + public void updateNonIndexable_bothAvailable_shouldNotUpdate() { + final List keys = new ArrayList<>(); + when(mUserManager.isAdminUser()).thenReturn(true); + when(mContext.getResources().getBoolean( + R.bool.config_additional_system_update_setting_enable)) + .thenReturn(true); + + mController.updateNonIndexableKeys(keys); + + assertThat(keys).isEmpty(); + } + + @Test + public void updateNonIndexable_nothingAvailable_shouldUpdateWith2Prefs() { + final List keys = new ArrayList<>(); + + mController.updateNonIndexableKeys(keys); + + assertThat(keys.size()).isEqualTo(2); + } + + @Test + public void displayPrefs_nothingAvailable_shouldNotDisplay() { + mController.displayPreference(mScreen); + + verify(mScreen, times(2)).removePreference(any(Preference.class)); + } + + @Test + public void displayPrefs_oneAvailable_shouldDisplayOne() { + when(mContext.getResources().getBoolean( + R.bool.config_additional_system_update_setting_enable)) + .thenReturn(true); + + mController.displayPreference(mScreen); + + verify(mScreen).removePreference(any(Preference.class)); + } +}