diff --git a/res/layout/dashboard.xml b/res/layout/dashboard.xml
index ccb50ae10ed..8031028d8c6 100644
--- a/res/layout/dashboard.xml
+++ b/res/layout/dashboard.xml
@@ -26,5 +26,4 @@
android:paddingEnd="@dimen/dashboard_padding_end"
android:paddingTop="@dimen/dashboard_padding_top"
android:paddingBottom="@dimen/dashboard_padding_bottom"
- android:scrollbars="vertical"/>
-
+ android:scrollbars="vertical"/>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5bdd578e959..53abd544d50 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -10071,4 +10071,11 @@
Devices
+
+
+ High Frequency Panel
+
+
+ Enable Virtual High Frequency Panel
+
diff --git a/res/xml/app_and_notification.xml b/res/xml/app_and_notification.xml
index 5a55ba5dab0..c15df75afdc 100644
--- a/res/xml/app_and_notification.xml
+++ b/res/xml/app_and_notification.xml
@@ -34,18 +34,18 @@
android:title="@string/applications_settings"
android:key="all_app_info"
android:fragment="com.android.settings.applications.manageapplications.ManageApplications"
- android:order="20" />
+ android:order="20"/>
+ android:order="-190"/>
+ android:order="10"/>
-
+
+ android:targetClass="com.android.cellbroadcastreceiver.CellBroadcastSettings"/>
+ settings:controller="com.android.settings.applications.SpecialAppAccessPreferenceController"/>
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index a46ff2f9611..8cc8001088b 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -359,6 +359,11 @@
android:entries="@array/overlay_display_devices_entries"
android:entryValues="@array/overlay_display_devices_values" />
+
+
diff --git a/res/xml/network_and_internet.xml b/res/xml/network_and_internet.xml
index 0d130e06b81..8e36e919220 100644
--- a/res/xml/network_and_internet.xml
+++ b/res/xml/network_and_internet.xml
@@ -42,10 +42,6 @@
settings:keywords="@string/keywords_more_mobile_networks"
settings:userRestriction="no_config_mobile_networks"
settings:useAdminDisabledSummary="true">
-
createPreferenceControllers(Context context) {
final Activity activity = getActivity();
@@ -77,7 +83,6 @@ public class AppAndNotificationDashboardFragment extends DashboardFragment {
final List controllers = new ArrayList<>();
controllers.add(new EmergencyBroadcastPreferenceController(context,
"app_and_notif_cell_broadcast_settings"));
- controllers.add(new SpecialAppAccessPreferenceController(context));
controllers.add(new RecentAppsPreferenceController(context, app, host));
return controllers;
}
diff --git a/src/com/android/settings/applications/AppStateBaseBridge.java b/src/com/android/settings/applications/AppStateBaseBridge.java
index 2329b4469e6..1a39483af9a 100644
--- a/src/com/android/settings/applications/AppStateBaseBridge.java
+++ b/src/com/android/settings/applications/AppStateBaseBridge.java
@@ -45,7 +45,7 @@ public abstract class AppStateBaseBridge implements ApplicationsState.Callbacks
// the same time as us as well.
mHandler = new BackgroundHandler(mAppState != null ? mAppState.getBackgroundLooper()
: Looper.getMainLooper());
- mMainHandler = new MainHandler();
+ mMainHandler = new MainHandler(Looper.getMainLooper());
}
public void resume() {
@@ -106,11 +106,16 @@ public abstract class AppStateBaseBridge implements ApplicationsState.Callbacks
}
protected abstract void loadAllExtraInfo();
+
protected abstract void updateExtraInfo(AppEntry app, String pkg, int uid);
private class MainHandler extends Handler {
private static final int MSG_INFO_UPDATED = 1;
+ public MainHandler(Looper looper) {
+ super(looper);
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
diff --git a/src/com/android/settings/applications/SpecialAppAccessPreferenceController.java b/src/com/android/settings/applications/SpecialAppAccessPreferenceController.java
index 16a6cab5d98..a395f9833f0 100644
--- a/src/com/android/settings/applications/SpecialAppAccessPreferenceController.java
+++ b/src/com/android/settings/applications/SpecialAppAccessPreferenceController.java
@@ -13,43 +13,140 @@
*/
package com.android.settings.applications;
+import android.app.Application;
import android.content.Context;
-import com.android.settings.R;
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.datausage.DataSaverBackend;
-import com.android.settingslib.core.AbstractPreferenceController;
-
+import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
-public class SpecialAppAccessPreferenceController extends AbstractPreferenceController
- implements PreferenceControllerMixin {
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.datausage.AppStateDataUsageBridge;
+import com.android.settings.datausage.DataSaverBackend;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnDestroy;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
- private static final String KEY_SPECIAL_ACCESS = "special_access";
+import java.util.ArrayList;
- private DataSaverBackend mDataSaverBackend;
+public class SpecialAppAccessPreferenceController extends BasePreferenceController implements
+ AppStateBaseBridge.Callback, ApplicationsState.Callbacks, LifecycleObserver, OnStart,
+ OnStop, OnDestroy {
- public SpecialAppAccessPreferenceController(Context context) {
- super(context);
+ @VisibleForTesting
+ ApplicationsState.Session mSession;
+
+ private final ApplicationsState mApplicationsState;
+ private final AppStateDataUsageBridge mDataUsageBridge;
+ private final DataSaverBackend mDataSaverBackend;
+
+ private Preference mPreference;
+ private boolean mExtraLoaded;
+
+
+ public SpecialAppAccessPreferenceController(Context context, String key) {
+ super(context, key);
+ mApplicationsState = ApplicationsState.getInstance(
+ (Application) context.getApplicationContext());
+ mDataSaverBackend = new DataSaverBackend(context);
+ mDataUsageBridge = new AppStateDataUsageBridge(mApplicationsState, this, mDataSaverBackend);
+ }
+
+ public void setSession(Lifecycle lifecycle) {
+ mSession = mApplicationsState.newSession(this, lifecycle);
}
@Override
- public boolean isAvailable() {
- return true;
+ public int getAvailabilityStatus() {
+ return AVAILABLE_UNSEARCHABLE;
}
@Override
- public String getPreferenceKey() {
- return KEY_SPECIAL_ACCESS;
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
+ public void onStart() {
+ mDataUsageBridge.resume();
+ }
+
+ @Override
+ public void onStop() {
+ mDataUsageBridge.pause();
+ }
+
+ @Override
+ public void onDestroy() {
+ mDataUsageBridge.release();
}
@Override
public void updateState(Preference preference) {
- if (mDataSaverBackend == null) {
- mDataSaverBackend = new DataSaverBackend(mContext);
- }
- final int count = mDataSaverBackend.getWhitelistedCount();
- preference.setSummary(mContext.getResources().getQuantityString(
- R.plurals.special_access_summary, count, count));
+ updateSummary();
}
+
+ @Override
+ public void onExtraInfoUpdated() {
+ mExtraLoaded = true;
+ updateSummary();
+ }
+
+ private void updateSummary() {
+ if (!mExtraLoaded || mPreference == null) {
+ return;
+ }
+
+ final ArrayList allApps = mSession.getAllApps();
+ int count = 0;
+ for (ApplicationsState.AppEntry entry : allApps) {
+ if (!ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(entry)) {
+ continue;
+ }
+ if (entry.extraInfo != null && ((AppStateDataUsageBridge.DataUsageState)
+ entry.extraInfo).isDataSaverWhitelisted) {
+ count++;
+ }
+ }
+ mPreference.setSummary(mContext.getResources().getQuantityString(
+ R.plurals.special_access_summary, count, count));
+ }
+
+ @Override
+ public void onRunningStateChanged(boolean running) {
+ }
+
+ @Override
+ public void onPackageListChanged() {
+ }
+
+ @Override
+ public void onRebuildComplete(ArrayList apps) {
+ }
+
+ @Override
+ public void onPackageIconChanged() {
+ }
+
+ @Override
+ public void onPackageSizeChanged(String packageName) {
+ }
+
+ @Override
+ public void onAllSizesComputed() {
+ }
+
+ @Override
+ public void onLauncherInfoChanged() {
+ }
+
+ @Override
+ public void onLoadEntriesCompleted() {
+ }
+
}
diff --git a/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceController.java b/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceController.java
index 872f5a34d80..9fbde3e25b8 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceController.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceController.java
@@ -105,7 +105,7 @@ public class DefaultHomePreferenceController extends DefaultAppPreferenceControl
Intent intent = new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
.setPackage(packageName)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- return mPackageManager.queryIntentActivities(intent, 0).size() == 1 ? intent : null;
+ return intent.resolveActivity(mPackageManager) != null ? intent : null;
}
public static boolean hasHomePreference(String pkg, Context context) {
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index cd452817d0e..20e702a3eee 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -98,11 +98,11 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
BluetoothDevice device = mCachedDevice.getDevice();
profilePref.setEnabled(!mCachedDevice.isBusy());
if (profile instanceof MapProfile) {
- profilePref.setChecked(mCachedDevice.getMessagePermissionChoice()
- == CachedBluetoothDevice.ACCESS_ALLOWED);
+ profilePref.setChecked(device.getMessageAccessPermission()
+ == BluetoothDevice.ACCESS_ALLOWED);
} else if (profile instanceof PbapServerProfile) {
- profilePref.setChecked(mCachedDevice.getPhonebookPermissionChoice()
- == CachedBluetoothDevice.ACCESS_ALLOWED);
+ profilePref.setChecked(device.getPhonebookAccessPermission()
+ == BluetoothDevice.ACCESS_ALLOWED);
} else if (profile instanceof PanProfile) {
profilePref.setChecked(profile.getConnectionStatus(device) ==
BluetoothProfile.STATE_CONNECTED);
@@ -130,31 +130,31 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
/**
* Helper method to enable a profile for a device.
*/
- private void enableProfile(LocalBluetoothProfile profile, BluetoothDevice device,
- SwitchPreference profilePref) {
+ private void enableProfile(LocalBluetoothProfile profile) {
+ final BluetoothDevice bluetoothDevice = mCachedDevice.getDevice();
if (profile instanceof PbapServerProfile) {
- mCachedDevice.setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_ALLOWED);
+ bluetoothDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
// We don't need to do the additional steps below for this profile.
return;
}
if (profile instanceof MapProfile) {
- mCachedDevice.setMessagePermissionChoice(BluetoothDevice.ACCESS_ALLOWED);
+ bluetoothDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
}
- profile.setPreferred(device, true);
+ profile.setPreferred(bluetoothDevice, true);
mCachedDevice.connectProfile(profile);
}
/**
* Helper method to disable a profile for a device
*/
- private void disableProfile(LocalBluetoothProfile profile, BluetoothDevice device,
- SwitchPreference profilePref) {
+ private void disableProfile(LocalBluetoothProfile profile) {
+ final BluetoothDevice bluetoothDevice = mCachedDevice.getDevice();
mCachedDevice.disconnect(profile);
- profile.setPreferred(device, false);
+ profile.setPreferred(bluetoothDevice, false);
if (profile instanceof MapProfile) {
- mCachedDevice.setMessagePermissionChoice(BluetoothDevice.ACCESS_REJECTED);
+ bluetoothDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED);
} else if (profile instanceof PbapServerProfile) {
- mCachedDevice.setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_REJECTED);
+ bluetoothDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
}
}
@@ -175,11 +175,10 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
}
}
SwitchPreference profilePref = (SwitchPreference) preference;
- BluetoothDevice device = mCachedDevice.getDevice();
if (profilePref.isChecked()) {
- enableProfile(profile, device, profilePref);
+ enableProfile(profile);
} else {
- disableProfile(profile, device, profilePref);
+ disableProfile(profile);
}
refreshProfilePreference(profilePref, profile);
return true;
@@ -191,17 +190,18 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
*/
private List getProfiles() {
List result = mCachedDevice.getConnectableProfiles();
+ final BluetoothDevice device = mCachedDevice.getDevice();
- final int pbapPermission = mCachedDevice.getPhonebookPermissionChoice();
+ final int pbapPermission = device.getPhonebookAccessPermission();
// Only provide PBAP cabability if the client device has requested PBAP.
- if (pbapPermission != CachedBluetoothDevice.ACCESS_UNKNOWN) {
+ if (pbapPermission != BluetoothDevice.ACCESS_UNKNOWN) {
final PbapServerProfile psp = mManager.getProfileManager().getPbapProfile();
result.add(psp);
}
final MapProfile mapProfile = mManager.getProfileManager().getMapProfile();
- final int mapPermission = mCachedDevice.getMessagePermissionChoice();
- if (mapPermission != CachedBluetoothDevice.ACCESS_UNKNOWN) {
+ final int mapPermission = device.getMessageAccessPermission();
+ if (mapPermission != BluetoothDevice.ACCESS_UNKNOWN) {
result.add(mapProfile);
}
diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
index c452957bc14..c5f62b8b4d6 100644
--- a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
+++ b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
@@ -237,42 +237,42 @@ public final class BluetoothPermissionRequest extends BroadcastReceiver {
String intentName = BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY;
if (mRequestType == BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS) {
- int phonebookPermission = cachedDevice.getPhonebookPermissionChoice();
+ int phonebookPermission = mDevice.getPhonebookAccessPermission();
- if (phonebookPermission == CachedBluetoothDevice.ACCESS_UNKNOWN) {
+ if (phonebookPermission == BluetoothDevice.ACCESS_UNKNOWN) {
// Leave 'processed' as false.
- } else if (phonebookPermission == CachedBluetoothDevice.ACCESS_ALLOWED) {
+ } else if (phonebookPermission == BluetoothDevice.ACCESS_ALLOWED) {
sendReplyIntentToReceiver(true);
processed = true;
- } else if (phonebookPermission == CachedBluetoothDevice.ACCESS_REJECTED) {
+ } else if (phonebookPermission == BluetoothDevice.ACCESS_REJECTED) {
sendReplyIntentToReceiver(false);
processed = true;
} else {
Log.e(TAG, "Bad phonebookPermission: " + phonebookPermission);
}
} else if (mRequestType == BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS) {
- int messagePermission = cachedDevice.getMessagePermissionChoice();
+ int messagePermission = mDevice.getMessageAccessPermission();
- if (messagePermission == CachedBluetoothDevice.ACCESS_UNKNOWN) {
+ if (messagePermission == BluetoothDevice.ACCESS_UNKNOWN) {
// Leave 'processed' as false.
- } else if (messagePermission == CachedBluetoothDevice.ACCESS_ALLOWED) {
+ } else if (messagePermission == BluetoothDevice.ACCESS_ALLOWED) {
sendReplyIntentToReceiver(true);
processed = true;
- } else if (messagePermission == CachedBluetoothDevice.ACCESS_REJECTED) {
+ } else if (messagePermission == BluetoothDevice.ACCESS_REJECTED) {
sendReplyIntentToReceiver(false);
processed = true;
} else {
Log.e(TAG, "Bad messagePermission: " + messagePermission);
}
} else if(mRequestType == BluetoothDevice.REQUEST_TYPE_SIM_ACCESS) {
- int simPermission = cachedDevice.getSimPermissionChoice();
+ int simPermission = mDevice.getSimAccessPermission();
- if (simPermission == CachedBluetoothDevice.ACCESS_UNKNOWN) {
+ if (simPermission == BluetoothDevice.ACCESS_UNKNOWN) {
// Leave 'processed' as false.
- } else if (simPermission == CachedBluetoothDevice.ACCESS_ALLOWED) {
+ } else if (simPermission == BluetoothDevice.ACCESS_ALLOWED) {
sendReplyIntentToReceiver(true);
processed = true;
- } else if (simPermission == CachedBluetoothDevice.ACCESS_REJECTED) {
+ } else if (simPermission == BluetoothDevice.ACCESS_REJECTED) {
sendReplyIntentToReceiver(false);
processed = true;
} else {
diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java
index c6b9d836828..08b4e82e9ca 100644
--- a/src/com/android/settings/core/FeatureFlags.java
+++ b/src/com/android/settings/core/FeatureFlags.java
@@ -25,4 +25,5 @@ public class FeatureFlags {
public static final String AUDIO_SWITCHER_SETTINGS = "settings_audio_switcher";
public static final String DYNAMIC_HOMEPAGE = "settings_dynamic_homepage";
public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
+ public static final String MOBILE_NETWORK_V2 = "settings_mobile_network_v2";
}
diff --git a/src/com/android/settings/datausage/DataSaverBackend.java b/src/com/android/settings/datausage/DataSaverBackend.java
index b59da9d7ff8..ed2e6c9195c 100644
--- a/src/com/android/settings/datausage/DataSaverBackend.java
+++ b/src/com/android/settings/datausage/DataSaverBackend.java
@@ -95,19 +95,10 @@ public class DataSaverBackend {
return mUidPolicies.get(uid, POLICY_NONE) == POLICY_ALLOW_METERED_BACKGROUND;
}
- public int getWhitelistedCount() {
- int count = 0;
- loadWhitelist();
- for (int i = 0; i < mUidPolicies.size(); i++) {
- if (mUidPolicies.valueAt(i) == POLICY_ALLOW_METERED_BACKGROUND) {
- count++;
- }
- }
- return count;
- }
-
private void loadWhitelist() {
- if (mWhitelistInitialized) return;
+ if (mWhitelistInitialized) {
+ return;
+ }
for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_ALLOW_METERED_BACKGROUND)) {
mUidPolicies.put(uid, POLICY_ALLOW_METERED_BACKGROUND);
@@ -135,7 +126,9 @@ public class DataSaverBackend {
}
private void loadBlacklist() {
- if (mBlacklistInitialized) return;
+ if (mBlacklistInitialized) {
+ return;
+ }
for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) {
mUidPolicies.put(uid, POLICY_REJECT_METERED_BACKGROUND);
}
@@ -212,7 +205,9 @@ public class DataSaverBackend {
public interface Listener {
void onDataSaverChanged(boolean isDataSaving);
+
void onWhitelistStatusChanged(int uid, boolean isWhitelisted);
+
void onBlacklistStatusChanged(int uid, boolean isBlacklisted);
}
}
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 5be381a04c9..54ca6ef776f 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -439,6 +439,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new TransitionAnimationScalePreferenceController(context));
controllers.add(new AnimatorDurationScalePreferenceController(context));
controllers.add(new SecondaryDisplayPreferenceController(context));
+ controllers.add(new HighFrequencyDisplayPreferenceController(context));
controllers.add(new GpuViewUpdatesPreferenceController(context));
controllers.add(new HardwareLayersUpdatesPreferenceController(context));
controllers.add(new DebugGpuOverdrawPreferenceController(context));
diff --git a/src/com/android/settings/development/HighFrequencyDisplayPreferenceController.java b/src/com/android/settings/development/HighFrequencyDisplayPreferenceController.java
new file mode 100644
index 00000000000..cbb8d4ce6d0
--- /dev/null
+++ b/src/com/android/settings/development/HighFrequencyDisplayPreferenceController.java
@@ -0,0 +1,129 @@
+/*
+ * 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.development;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.text.TextUtils;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+public class HighFrequencyDisplayPreferenceController extends DeveloperOptionsPreferenceController
+ implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+ private static final String HIGH_FREQUENCY_DISPLAY_KEY = "high_frequency_display_device";
+
+ private static final String SURFACE_FLINGER_SERVICE_KEY = "SurfaceFlinger";
+ private static final String SURFACE_COMPOSER_INTERFACE_KEY = "android.ui.ISurfaceComposer";
+ private static final int SURFACE_FLINGER_HIGH_FREQUENCY_DISPLAY_CODE = 1029;
+
+ private final IBinder mSurfaceFlingerBinder;
+
+ public HighFrequencyDisplayPreferenceController(Context context) {
+ super(context);
+ mSurfaceFlingerBinder = ServiceManager.getService(SURFACE_FLINGER_SERVICE_KEY);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return HIGH_FREQUENCY_DISPLAY_KEY;
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ Boolean isEnabled = (Boolean) newValue;
+ writeHighFrequencyDisplaySetting(isEnabled);
+ ((SwitchPreference) preference).setChecked(isEnabled);
+ return true;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ boolean enableHighFrequencyPanel = readHighFrequencyDisplaySetting();
+ ((SwitchPreference) preference).setChecked(enableHighFrequencyPanel);
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchDisabled() {
+ super.onDeveloperOptionsSwitchDisabled();
+ writeHighFrequencyDisplaySetting(false);
+ ((SwitchPreference) mPreference).setChecked(false);
+ }
+
+ @VisibleForTesting
+ boolean readHighFrequencyDisplaySetting() {
+ boolean isEnabled = false;
+ try {
+ if (mSurfaceFlingerBinder != null) {
+ final Parcel data = Parcel.obtain();
+ final Parcel result = Parcel.obtain();
+ data.writeInterfaceToken(SURFACE_COMPOSER_INTERFACE_KEY);
+ data.writeInt(0);
+ data.writeInt(0);
+ mSurfaceFlingerBinder.transact(
+ SURFACE_FLINGER_HIGH_FREQUENCY_DISPLAY_CODE,
+ data, result, 0);
+
+ if (result.readInt() != 1 || result.readInt() != 1) {
+ isEnabled = true;
+ }
+ }
+ } catch (RemoteException ex) {
+ // intentional no-op
+ }
+ return isEnabled;
+ }
+
+ @VisibleForTesting
+ void writeHighFrequencyDisplaySetting(boolean isEnabled) {
+ int multiplier;
+ int divisor;
+
+ if (isEnabled) {
+ // 60Hz * 3/2 = 90Hz
+ multiplier = 2;
+ divisor = 3;
+ } else {
+ multiplier = 1;
+ divisor = 1;
+ }
+
+ try {
+ if (mSurfaceFlingerBinder != null) {
+ final Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(SURFACE_COMPOSER_INTERFACE_KEY);
+ data.writeInt(multiplier);
+ data.writeInt(divisor);
+ mSurfaceFlingerBinder.transact(
+ SURFACE_FLINGER_HIGH_FREQUENCY_DISPLAY_CODE,
+ data, null, 0);
+ }
+ } catch (RemoteException ex) {
+ // intentional no-op
+ }
+ }
+}
diff --git a/src/com/android/settings/development/autofill/AutofillLoggingLevelPreferenceController.java b/src/com/android/settings/development/autofill/AutofillLoggingLevelPreferenceController.java
index a22295c557f..8618bc542c8 100644
--- a/src/com/android/settings/development/autofill/AutofillLoggingLevelPreferenceController.java
+++ b/src/com/android/settings/development/autofill/AutofillLoggingLevelPreferenceController.java
@@ -19,6 +19,7 @@ package com.android.settings.development.autofill;
import android.content.Context;
import android.content.res.Resources;
import android.provider.Settings;
+import android.util.Log;
import android.view.autofill.AutofillManager;
import com.android.settings.R;
@@ -32,6 +33,7 @@ public final class AutofillLoggingLevelPreferenceController
extends DeveloperOptionsPreferenceController
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
+ private static final String TAG = "AutofillLoggingLevelPreferenceController";
private static final String AUTOFILL_LOGGING_LEVEL_KEY = "autofill_logging_level";
private final String[] mListValues;
@@ -73,6 +75,12 @@ public final class AutofillLoggingLevelPreferenceController
}
private void updateOptions() {
+ if (mPreference == null) {
+ // TODO: there should be a hook on AbstractPreferenceController where we could
+ // unregister mObserver and avoid this check
+ Log.v(TAG, "ignoring Settings update because UI is gone");
+ return;
+ }
final int level = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.AUTOFILL_LOGGING_LEVEL, AutofillManager.DEFAULT_LOGGING_LEVEL);
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
index e09e89d92ba..c3d034f5e40 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
@@ -59,7 +59,6 @@ public class StorageWizardFormatConfirm extends InstrumentedDialogFragment {
final StorageWizardFormatConfirm fragment = new StorageWizardFormatConfirm();
fragment.setArguments(args);
- // TODO (b/111150236) : Need to check it again.
fragment.show(activity.getSupportFragmentManager(), TAG_FORMAT_WARNING);
}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
index 287cc3f0ec6..2d94597c622 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
@@ -59,7 +59,6 @@ public class StorageWizardFormatProgress extends StorageWizardBase {
setHeaderText(R.string.storage_wizard_format_progress_title, getDiskShortDescription());
setBodyText(R.string.storage_wizard_format_progress_body, getDiskDescription());
- // TODO (b/111151113) : Need to check it again.
mTask = (PartitionTask) getLastCustomNonConfigurationInstance();
if (mTask == null) {
mTask = new PartitionTask();
@@ -69,7 +68,7 @@ public class StorageWizardFormatProgress extends StorageWizardBase {
mTask.setActivity(this);
}
}
- // TODO (b/111151113) : Need to check it again.
+
@Override
public Object onRetainCustomNonConfigurationInstance() {
return mTask;
diff --git a/src/com/android/settings/homepage/CardContentLoader.java b/src/com/android/settings/homepage/CardContentLoader.java
new file mode 100644
index 00000000000..4e1e33ef891
--- /dev/null
+++ b/src/com/android/settings/homepage/CardContentLoader.java
@@ -0,0 +1,62 @@
+/*
+ * 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.homepage;
+
+import android.content.Context;
+
+import androidx.annotation.Nullable;
+
+import com.android.settingslib.utils.AsyncLoaderCompat;
+
+import java.util.List;
+
+//TODO(b/112521307): Implement this to make it work with the card database.
+public class CardContentLoader {
+
+ private static final String TAG = "CardContentLoader";
+
+ private CardContentLoaderListener mListener;
+
+ public interface CardContentLoaderListener {
+ void onFinishCardLoading(List homepageCards);
+ }
+
+ public CardContentLoader() {
+ }
+
+ void setListener(CardContentLoaderListener listener) {
+ mListener = listener;
+ }
+
+ private static class CardLoader extends AsyncLoaderCompat> {
+
+ public CardLoader(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onDiscardResult(List result) {
+
+ }
+
+ @Nullable
+ @Override
+ public List loadInBackground() {
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/settings/homepage/ControllerRendererPool.java b/src/com/android/settings/homepage/ControllerRendererPool.java
new file mode 100644
index 00000000000..b2ac9ecde9f
--- /dev/null
+++ b/src/com/android/settings/homepage/ControllerRendererPool.java
@@ -0,0 +1,99 @@
+/*
+ * 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.homepage;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.collection.ArraySet;
+
+import java.util.Set;
+
+/**
+ * This is a fragment scoped singleton holding a set of {@link HomepageCardController} and
+ * {@link HomepageCardRenderer}.
+ */
+public class ControllerRendererPool {
+
+ private static final String TAG = "ControllerRendererPool";
+
+ private final Set mControllers;
+ private final Set mRenderers;
+
+ public ControllerRendererPool() {
+ mControllers = new ArraySet<>();
+ mRenderers = new ArraySet<>();
+ }
+
+ public T getController(Context context,
+ @HomepageCard.CardType int cardType) {
+ final Class extends HomepageCardController> clz =
+ HomepageCardLookupTable.getCardControllerClass(cardType);
+ for (HomepageCardController controller : mControllers) {
+ if (controller.getClass() == clz) {
+ Log.d(TAG, "Controller is already there.");
+ return (T) controller;
+ }
+ }
+
+ final HomepageCardController controller = createCardController(context, clz);
+ if (controller != null) {
+ mControllers.add(controller);
+ }
+ return (T) controller;
+ }
+
+ public Set getControllers() {
+ return mControllers;
+ }
+
+ public HomepageCardRenderer getRenderer(Context context, @HomepageCard.CardType int cardType) {
+ final Class extends HomepageCardRenderer> clz =
+ HomepageCardLookupTable.getCardRendererClasses(cardType);
+ for (HomepageCardRenderer renderer : mRenderers) {
+ if (renderer.getClass() == clz) {
+ Log.d(TAG, "Renderer is already there.");
+ return renderer;
+ }
+ }
+
+ final HomepageCardRenderer renderer = createCardRenderer(context, clz);
+ if (renderer != null) {
+ mRenderers.add(renderer);
+ }
+ return renderer;
+ }
+
+ private HomepageCardController createCardController(Context context,
+ Class extends HomepageCardController> clz) {
+ /*
+ if (ConditionHomepageCardController.class == clz) {
+ return new ConditionHomepageCardController(context);
+ }
+ */
+ return null;
+ }
+
+ private HomepageCardRenderer createCardRenderer(Context context, Class> clz) {
+ //if (ConditionHomepageCardRenderer.class == clz) {
+ // return new ConditionHomepageCardRenderer(context, this /*controllerRendererPool*/);
+ //}
+
+ return null;
+ }
+
+}
diff --git a/src/com/android/settings/homepage/HomepageAdapter.java b/src/com/android/settings/homepage/HomepageAdapter.java
new file mode 100644
index 00000000000..b44288337d4
--- /dev/null
+++ b/src/com/android/settings/homepage/HomepageAdapter.java
@@ -0,0 +1,96 @@
+/*
+ * 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.homepage;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class HomepageAdapter extends RecyclerView.Adapter implements
+ HomepageCardUpdateListener {
+
+ private static final String TAG = "HomepageAdapter";
+
+ private final Context mContext;
+ private final ControllerRendererPool mControllerRendererPool;
+
+ private List mHomepageCards;
+ private RecyclerView mRecyclerView;
+
+ public HomepageAdapter(Context context, HomepageManager manager) {
+ mContext = context;
+ mHomepageCards = new ArrayList<>();
+ mControllerRendererPool = manager.getControllerRendererPool();
+ setHasStableIds(true);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mHomepageCards.get(position).hashCode();
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return mHomepageCards.get(position).getCardType();
+ }
+
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int cardType) {
+ final HomepageCardRenderer renderer = mControllerRendererPool.getRenderer(mContext, cardType);
+ final int viewType = renderer.getViewType();
+ final View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
+
+ return renderer.createViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ final int cardType = mHomepageCards.get(position).getCardType();
+ final HomepageCardRenderer renderer = mControllerRendererPool.getRenderer(mContext, cardType);
+
+ renderer.bindView(holder, mHomepageCards.get(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return mHomepageCards.size();
+ }
+
+ @Override
+ public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+ super.onAttachedToRecyclerView(recyclerView);
+ mRecyclerView = recyclerView;
+ }
+
+ @Override
+ public void onHomepageCardUpdated(int cardType, List homepageCards) {
+ //TODO(b/112245748): Should implement a DiffCallback so we can use notifyItemChanged()
+ // instead.
+ if (homepageCards == null) {
+ mHomepageCards.clear();
+ } else {
+ mHomepageCards = homepageCards;
+ }
+ notifyDataSetChanged();
+ }
+}
diff --git a/src/com/android/settings/homepage/HomepageCard.java b/src/com/android/settings/homepage/HomepageCard.java
new file mode 100644
index 00000000000..1719f57869a
--- /dev/null
+++ b/src/com/android/settings/homepage/HomepageCard.java
@@ -0,0 +1,296 @@
+/*
+ * 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.homepage;
+
+import android.annotation.IntDef;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.text.TextUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Data class representing a {@link HomepageCard}.
+ */
+public class HomepageCard {
+
+ /**
+ * Flags indicating the type of the HomepageCard.
+ */
+ @IntDef({CardType.INVALID, CardType.SLICE, CardType.SUGGESTION, CardType.CONDITIONAL})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CardType {
+ int INVALID = -1;
+ int SLICE = 1;
+ int SUGGESTION = 2;
+ int CONDITIONAL = 3;
+ }
+
+ private final String mName;
+ @CardType
+ private final int mCardType;
+ private final double mScore;
+ private final String mSliceUri;
+ private final int mCategory;
+ private final String mLocalizedToLocale;
+ private final String mPackageName;
+ private final String mAppVersion;
+ private final String mTitleResName;
+ private final String mTitleText;
+ private final String mSummaryResName;
+ private final String mSummaryText;
+ private final String mIconResName;
+ private final int mIconResId;
+ private final String mCardAction;
+ private final long mExpireTimeMS;
+ private final Drawable mDrawable;
+ private final boolean mSupportHalfWidth;
+
+ String getName() {
+ return mName;
+ }
+
+ int getCardType() {
+ return mCardType;
+ }
+
+ double getScore() {
+ return mScore;
+ }
+
+ String getTextSliceUri() {
+ return mSliceUri;
+ }
+
+ Uri getSliceUri() {
+ return Uri.parse(mSliceUri);
+ }
+
+ int getCategory() {
+ return mCategory;
+ }
+
+ String getLocalizedToLocale() {
+ return mLocalizedToLocale;
+ }
+
+ String getPackageName() {
+ return mPackageName;
+ }
+
+ String getAppVersion() {
+ return mAppVersion;
+ }
+
+ String getTitleResName() {
+ return mTitleResName;
+ }
+
+ String getTitleText() {
+ return mTitleText;
+ }
+
+ String getSummaryResName() {
+ return mSummaryResName;
+ }
+
+ String getSummaryText() {
+ return mSummaryText;
+ }
+
+ String getIconResName() {
+ return mIconResName;
+ }
+
+ int getIconResId() {
+ return mIconResId;
+ }
+
+ String getCardAction() {
+ return mCardAction;
+ }
+
+ long getExpireTimeMS() {
+ return mExpireTimeMS;
+ }
+
+ Drawable getDrawable() {
+ return mDrawable;
+ }
+
+ boolean getSupportHalfWidth() {
+ return mSupportHalfWidth;
+ }
+
+ HomepageCard(Builder builder) {
+ mName = builder.mName;
+ mCardType = builder.mCardType;
+ mScore = builder.mScore;
+ mSliceUri = builder.mSliceUri;
+ mCategory = builder.mCategory;
+ mLocalizedToLocale = builder.mLocalizedToLocale;
+ mPackageName = builder.mPackageName;
+ mAppVersion = builder.mAppVersion;
+ mTitleResName = builder.mTitleResName;
+ mTitleText = builder.mTitleText;
+ mSummaryResName = builder.mSummaryResName;
+ mSummaryText = builder.mSummaryText;
+ mIconResName = builder.mIconResName;
+ mIconResId = builder.mIconResId;
+ mCardAction = builder.mCardAction;
+ mExpireTimeMS = builder.mExpireTimeMS;
+ mDrawable = builder.mDrawable;
+ mSupportHalfWidth = builder.mSupportHalfWidth;
+ }
+
+ @Override
+ public int hashCode() {
+ return mName.hashCode();
+ }
+
+ /**
+ * Note that {@link #mName} is treated as a primary key for this class and determines equality.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof HomepageCard)) {
+ return false;
+ }
+ final HomepageCard that = (HomepageCard) obj;
+
+ return TextUtils.equals(mName, that.mName);
+ }
+
+ static class Builder {
+ private String mName;
+ private int mCardType;
+ private double mScore;
+ private String mSliceUri;
+ private int mCategory;
+ private String mLocalizedToLocale;
+ private String mPackageName;
+ private String mAppVersion;
+ private String mTitleResName;
+ private String mTitleText;
+ private String mSummaryResName;
+ private String mSummaryText;
+ private String mIconResName;
+ private int mIconResId;
+ private String mCardAction;
+ private long mExpireTimeMS;
+ private Drawable mDrawable;
+ private boolean mSupportHalfWidth;
+
+ public Builder setName(String name) {
+ mName = name;
+ return this;
+ }
+
+ public Builder setCardType(int cardType) {
+ mCardType = cardType;
+ return this;
+ }
+
+ public Builder setScore(double score) {
+ mScore = score;
+ return this;
+ }
+
+ public Builder setSliceUri(String sliceUri) {
+ mSliceUri = sliceUri;
+ return this;
+ }
+
+ public Builder setCategory(int category) {
+ mCategory = category;
+ return this;
+ }
+
+ public Builder setLocalizedToLocale(String localizedToLocale) {
+ mLocalizedToLocale = localizedToLocale;
+ return this;
+ }
+
+ public Builder setPackageName(String packageName) {
+ mPackageName = packageName;
+ return this;
+ }
+
+ public Builder setAppVersion(String appVersion) {
+ mAppVersion = appVersion;
+ return this;
+ }
+
+ public Builder setTitleResName(String titleResName) {
+ mTitleResName = titleResName;
+ return this;
+ }
+
+ public Builder setTitleText(String titleText) {
+ mTitleText = titleText;
+ return this;
+ }
+
+ public Builder setSummaryResName(String summaryResName) {
+ mSummaryResName = summaryResName;
+ return this;
+ }
+
+ public Builder setSummaryText(String summaryText) {
+ mSummaryText = summaryText;
+ return this;
+ }
+
+ public Builder setIconResName(String iconResName) {
+ mIconResName = iconResName;
+ return this;
+ }
+
+ public Builder setIconResId(int iconResId) {
+ mIconResId = iconResId;
+ return this;
+ }
+
+ public Builder setCardAction(String cardAction) {
+ mCardAction = cardAction;
+ return this;
+ }
+
+ public Builder setExpireTimeMS(long expireTimeMS) {
+ mExpireTimeMS = expireTimeMS;
+ return this;
+ }
+
+ public Builder setDrawable(Drawable drawable) {
+ mDrawable = drawable;
+ return this;
+ }
+
+ public Builder setSupportHalfWidth(boolean supportHalfWidth) {
+ mSupportHalfWidth = supportHalfWidth;
+ return this;
+ }
+
+ public HomepageCard build() {
+ return new HomepageCard(this);
+ }
+ }
+}
diff --git a/src/com/android/settings/homepage/HomepageCardController.java b/src/com/android/settings/homepage/HomepageCardController.java
new file mode 100644
index 00000000000..c35c3c80c61
--- /dev/null
+++ b/src/com/android/settings/homepage/HomepageCardController.java
@@ -0,0 +1,45 @@
+/*
+ * 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.homepage;
+
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import java.util.List;
+
+//TODO(b/111821137): add test cases
+/**
+ * Data controller for {@link HomepageCard}.
+ */
+public interface HomepageCardController {
+
+ @HomepageCard.CardType
+ int getCardType();
+
+ /**
+ * When data is updated or changed, the new data should be passed to HomepageManager for list
+ * updating.
+ */
+ void onDataUpdated(List cardList);
+
+ void onPrimaryClick(HomepageCard card);
+
+ void onActionClick(HomepageCard card);
+
+ void setLifecycle(Lifecycle lifecycle);
+
+ void setHomepageCardUpdateListener(HomepageCardUpdateListener listener);
+}
diff --git a/src/com/android/settings/homepage/HomepageCardLookupTable.java b/src/com/android/settings/homepage/HomepageCardLookupTable.java
new file mode 100644
index 00000000000..9e941e9dd3f
--- /dev/null
+++ b/src/com/android/settings/homepage/HomepageCardLookupTable.java
@@ -0,0 +1,73 @@
+/*
+ * 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.homepage;
+
+import com.android.settings.homepage.HomepageCard.CardType;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+public class HomepageCardLookupTable {
+
+ static class HomepageMapping implements Comparable {
+ @CardType
+ private final int mCardType;
+ private final Class extends HomepageCardController> mControllerClass;
+ private final Class extends HomepageCardRenderer> mRendererClass;
+
+ private HomepageMapping(@CardType int cardType,
+ Class extends HomepageCardController> controllerClass,
+ Class extends HomepageCardRenderer> rendererClass) {
+ mCardType = cardType;
+ mControllerClass = controllerClass;
+ mRendererClass = rendererClass;
+ }
+
+ @Override
+ public int compareTo(HomepageMapping other) {
+ return Integer.compare(this.mCardType, other.mCardType);
+ }
+ }
+
+ private static final Set LOOKUP_TABLE = new TreeSet() {
+ {
+ //add(new HomepageMapping(CardType.CONDITIONAL, ConditionHomepageCardController.class,
+ // ConditionHomepageCardRenderer.class));
+ }
+ };
+
+ public static Class extends HomepageCardController> getCardControllerClass(
+ @CardType int cardType) {
+ for (HomepageMapping mapping : LOOKUP_TABLE) {
+ if (mapping.mCardType == cardType) {
+ return mapping.mControllerClass;
+ }
+ }
+ return null;
+ }
+
+ //TODO(b/112578070): Implement multi renderer cases.
+ public static Class extends HomepageCardRenderer> getCardRendererClasses(
+ @CardType int cardType) {
+ for (HomepageMapping mapping : LOOKUP_TABLE) {
+ if (mapping.mCardType == cardType) {
+ return mapping.mRendererClass;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/settings/homepage/HomepageCardRenderer.java b/src/com/android/settings/homepage/HomepageCardRenderer.java
new file mode 100644
index 00000000000..ffa54e36a69
--- /dev/null
+++ b/src/com/android/settings/homepage/HomepageCardRenderer.java
@@ -0,0 +1,46 @@
+/*
+ * 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.homepage;
+
+import android.view.View;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * UI renderer for {@link HomepageCard}.
+ */
+public interface HomepageCardRenderer {
+
+ /**
+ * The layout type of the controller.
+ */
+ int getViewType();
+
+ /**
+ * When {@link HomepageAdapter} calls {@link HomepageAdapter#onCreateViewHolder(ViewGroup,
+ * int)}, this method will be called to retrieve the corresponding
+ * {@link androidx.recyclerview.widget.RecyclerView.ViewHolder}.
+ */
+ RecyclerView.ViewHolder createViewHolder(View view);
+
+ /**
+ * When {@link HomepageAdapter} calls {@link HomepageAdapter#onBindViewHolder(RecyclerView
+ * .ViewHolder, int)}, this method will be called to bind data to the
+ * {@link androidx.recyclerview.widget.RecyclerView.ViewHolder}.
+ */
+ void bindView(RecyclerView.ViewHolder holder, HomepageCard card);
+}
\ No newline at end of file
diff --git a/src/com/android/settings/homepage/HomepageCardUpdateListener.java b/src/com/android/settings/homepage/HomepageCardUpdateListener.java
new file mode 100644
index 00000000000..a44ba2be6e3
--- /dev/null
+++ b/src/com/android/settings/homepage/HomepageCardUpdateListener.java
@@ -0,0 +1,31 @@
+/*
+ * 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.homepage;
+
+import java.util.List;
+
+/**
+ * When {@link HomepageCardController} detects changes, it will notify the listeners registered. In
+ * our case, {@link HomepageManager} gets noticed.
+ *
+ * After the list of {@link HomepageCard} gets updated in{@link HomepageManager},
+ * {@link HomepageManager} will notify the listeners registered, {@link HomepageAdapter} in this
+ * case.
+ */
+interface HomepageCardUpdateListener {
+ void onHomepageCardUpdated(int cardType, List updateList);
+}
\ No newline at end of file
diff --git a/src/com/android/settings/homepage/HomepageFragment.java b/src/com/android/settings/homepage/HomepageFragment.java
index dc6a91fe27d..402725ebc90 100644
--- a/src/com/android/settings/homepage/HomepageFragment.java
+++ b/src/com/android/settings/homepage/HomepageFragment.java
@@ -48,6 +48,7 @@ public class HomepageFragment extends InstrumentedFragment {
private static final String SAVE_BOTTOM_FRAGMENT_LOADED = "bottom_fragment_loaded";
private RecyclerView mCardsContainer;
+ private HomepageAdapter mHomepageAdapter;
private LinearLayoutManager mLayoutManager;
private FloatingActionButton mSearchButton;
@@ -55,6 +56,14 @@ public class HomepageFragment extends InstrumentedFragment {
private View mBottomBar;
private View mSearchBar;
private boolean mBottomFragmentLoaded;
+ private HomepageManager mHomepageManager;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mHomepageManager = new HomepageManager(getContext(), getSettingsLifecycle());
+ mHomepageManager.startCardContentLoading();
+ }
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -65,6 +74,9 @@ public class HomepageFragment extends InstrumentedFragment {
//TODO(b/111822407): May have to swap to GridLayoutManager
mLayoutManager = new LinearLayoutManager(getActivity());
mCardsContainer.setLayoutManager(mLayoutManager);
+ mHomepageAdapter = new HomepageAdapter(getContext(), mHomepageManager);
+ mCardsContainer.setAdapter(mHomepageAdapter);
+ mHomepageManager.setListener(mHomepageAdapter);
return rootView;
}
diff --git a/src/com/android/settings/homepage/HomepageManager.java b/src/com/android/settings/homepage/HomepageManager.java
new file mode 100644
index 00000000000..cbd5841d2cf
--- /dev/null
+++ b/src/com/android/settings/homepage/HomepageManager.java
@@ -0,0 +1,135 @@
+/*
+ * 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.homepage;
+
+import android.content.Context;
+import android.widget.BaseAdapter;
+
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This is a centralized manager of multiple {@link HomepageCardController}.
+ *
+ * {@link HomepageManager} first loads data from {@link CardContentLoader} and gets back a list of
+ * {@link HomepageCard}. All subclasses of {@link HomepageCardController} are loaded here, which
+ * will then trigger the {@link HomepageCardController} to load its data and listen to
+ * corresponding changes. When every single {@link HomepageCardController} updates its data, the
+ * data will be passed here, then going through some sorting mechanisms. The
+ * {@link HomepageCardController} will end up building a list of {@link HomepageCard} for {@link
+ * HomepageAdapter} and {@link BaseAdapter#notifyDataSetChanged()} will be called to get the page
+ * refreshed.
+ */
+public class HomepageManager implements CardContentLoader.CardContentLoaderListener,
+ HomepageCardUpdateListener {
+
+ private static final String TAG = "HomepageManager";
+ //The list for Settings Custom Card
+ @HomepageCard.CardType
+ private static final int[] SETTINGS_CARDS = {HomepageCard.CardType.CONDITIONAL};
+
+ private final Context mContext;
+ private final ControllerRendererPool mControllerRendererPool;
+ private final Lifecycle mLifecycle;
+
+ private List mHomepageCards;
+ private HomepageCardUpdateListener mListener;
+
+
+ public HomepageManager(Context context, Lifecycle lifecycle) {
+ mContext = context;
+ mLifecycle = lifecycle;
+ mHomepageCards = new ArrayList<>();
+ mControllerRendererPool = new ControllerRendererPool();
+ }
+
+ void startCardContentLoading() {
+ final CardContentLoader cardContentLoader = new CardContentLoader();
+ cardContentLoader.setListener(this);
+ }
+
+ private void loadCardControllers() {
+ if (mHomepageCards != null) {
+ for (HomepageCard card : mHomepageCards) {
+ setupController(card.getCardType());
+ }
+ }
+
+ //for data provided by Settings
+ for (int cardType : SETTINGS_CARDS) {
+ setupController(cardType);
+ }
+ }
+
+ private void setupController(int cardType) {
+ final HomepageCardController controller = mControllerRendererPool.getController(mContext,
+ cardType);
+ if (controller != null) {
+ controller.setHomepageCardUpdateListener(this);
+ controller.setLifecycle(mLifecycle);
+ }
+ }
+
+ //TODO(b/111822376): implement sorting mechanism.
+ private void sortCards() {
+ //take mHomepageCards as the source and do the ranking based on the rule.
+ }
+
+ @Override
+ public void onHomepageCardUpdated(int cardType, List updateList) {
+ //TODO(b/112245748): Should implement a DiffCallback.
+ //Keep the old list for comparison.
+ final List prevCards = mHomepageCards;
+
+ //Remove the existing data that matches the certain cardType so as to insert the new data.
+ for (int i = mHomepageCards.size() - 1; i >= 0; i--) {
+ if (mHomepageCards.get(i).getCardType() == cardType) {
+ mHomepageCards.remove(i);
+ }
+ }
+
+ //Append the new data
+ mHomepageCards.addAll(updateList);
+
+ sortCards();
+
+ if (mListener != null) {
+ mListener.onHomepageCardUpdated(HomepageCard.CardType.INVALID, mHomepageCards);
+ }
+ }
+
+ @Override
+ public void onFinishCardLoading(List homepageCards) {
+ mHomepageCards = homepageCards;
+
+ //Force card sorting here in case CardControllers of custom view have nothing to update
+ // for the first launch.
+ sortCards();
+
+ loadCardControllers();
+ }
+
+ void setListener(HomepageCardUpdateListener listener) {
+ mListener = listener;
+ }
+
+ public ControllerRendererPool getControllerRendererPool() {
+ return mControllerRendererPool;
+ }
+}
diff --git a/src/com/android/settings/homepage/conditional/BackgroundDataConditionController.java b/src/com/android/settings/homepage/conditional/BackgroundDataConditionController.java
index d7c06987e74..0dc3cf124f9 100644
--- a/src/com/android/settings/homepage/conditional/BackgroundDataConditionController.java
+++ b/src/com/android/settings/homepage/conditional/BackgroundDataConditionController.java
@@ -28,9 +28,14 @@ public class BackgroundDataConditionController implements ConditionalCardControl
static final int ID = Objects.hash("BackgroundDataConditionController");
private final Context mAppContext;
+ private final ConditionManager mConditionManager;
+ private final NetworkPolicyManager mNetworkPolicyManager;
- public BackgroundDataConditionController(Context appContext) {
+ public BackgroundDataConditionController(Context appContext, ConditionManager manager) {
mAppContext = appContext;
+ mConditionManager = manager;
+ mNetworkPolicyManager =
+ (NetworkPolicyManager) appContext.getSystemService(Context.NETWORK_POLICY_SERVICE);
}
@Override
@@ -40,7 +45,7 @@ public class BackgroundDataConditionController implements ConditionalCardControl
@Override
public boolean isDisplayable() {
- return NetworkPolicyManager.from(mAppContext).getRestrictBackground();
+ return mNetworkPolicyManager.getRestrictBackground();
}
@Override
@@ -50,7 +55,8 @@ public class BackgroundDataConditionController implements ConditionalCardControl
@Override
public void onActionClick() {
- NetworkPolicyManager.from(mAppContext).setRestrictBackground(false);
+ mNetworkPolicyManager.setRestrictBackground(false);
+ mConditionManager.onConditionChanged();
}
@Override
diff --git a/src/com/android/settings/homepage/conditional/ConditionManager.java b/src/com/android/settings/homepage/conditional/ConditionManager.java
index d6e50123a52..d1c9a27771c 100644
--- a/src/com/android/settings/homepage/conditional/ConditionManager.java
+++ b/src/com/android/settings/homepage/conditional/ConditionManager.java
@@ -100,7 +100,6 @@ public class ConditionManager {
*/
public void onActionClick(long id) {
getController(id).onActionClick();
- onConditionChanged();
}
/**
@@ -155,15 +154,16 @@ public class ConditionManager {
private void initCandidates() {
// Initialize controllers first.
mCardControllers.add(new AirplaneModeConditionController(mAppContext, this /* manager */));
- mCardControllers.add(new BackgroundDataConditionController(mAppContext));
+ mCardControllers.add(
+ new BackgroundDataConditionController(mAppContext, this /* manager */));
mCardControllers.add(new BatterySaverConditionController(mAppContext, this /* manager */));
mCardControllers.add(new CellularDataConditionController(mAppContext, this /* manager */));
mCardControllers.add(new DndConditionCardController(mAppContext, this /* manager */));
mCardControllers.add(new HotspotConditionController(mAppContext, this /* manager */));
- mCardControllers.add(new NightDisplayConditionController(mAppContext));
+ mCardControllers.add(new NightDisplayConditionController(mAppContext, this /* manager */));
mCardControllers.add(new RingerVibrateConditionController(mAppContext, this /* manager */));
mCardControllers.add(new RingerMutedConditionController(mAppContext, this /* manager */));
- mCardControllers.add(new WorkModeConditionController(mAppContext));
+ mCardControllers.add(new WorkModeConditionController(mAppContext, this /* manager */));
// Initialize ui model later. UI model depends on controller.
mCandidates.add(new AirplaneModeConditionCard(mAppContext));
diff --git a/src/com/android/settings/homepage/conditional/NightDisplayConditionController.java b/src/com/android/settings/homepage/conditional/NightDisplayConditionController.java
index 428fe488989..b4816f15a05 100644
--- a/src/com/android/settings/homepage/conditional/NightDisplayConditionController.java
+++ b/src/com/android/settings/homepage/conditional/NightDisplayConditionController.java
@@ -30,10 +30,12 @@ public class NightDisplayConditionController implements ConditionalCardControlle
ColorDisplayController.Callback {
static final int ID = Objects.hash("NightDisplayConditionController");
+ private final ConditionManager mConditionManager;
private final ColorDisplayController mController;
- public NightDisplayConditionController(Context appContext) {
+ public NightDisplayConditionController(Context appContext, ConditionManager manager) {
mController = new ColorDisplayController(appContext);
+ mConditionManager = manager;
}
@Override
@@ -69,4 +71,9 @@ public class NightDisplayConditionController implements ConditionalCardControlle
public void stopMonitoringStateChange() {
mController.setListener(null);
}
+
+ @Override
+ public void onActivated(boolean activated) {
+ mConditionManager.onConditionChanged();
+ }
}
diff --git a/src/com/android/settings/homepage/conditional/WorkModeConditionController.java b/src/com/android/settings/homepage/conditional/WorkModeConditionController.java
index 1bd227a0912..033a6a86070 100644
--- a/src/com/android/settings/homepage/conditional/WorkModeConditionController.java
+++ b/src/com/android/settings/homepage/conditional/WorkModeConditionController.java
@@ -16,11 +16,14 @@
package com.android.settings.homepage.conditional;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
+import android.text.TextUtils;
import com.android.settings.Settings;
@@ -31,13 +34,25 @@ public class WorkModeConditionController implements ConditionalCardController {
static final int ID = Objects.hash("WorkModeConditionController");
+ private static final IntentFilter FILTER = new IntentFilter();
+
+ static {
+ FILTER.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ FILTER.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ }
+
private final Context mAppContext;
private final UserManager mUm;
+ private final ConditionManager mConditionManager;
+ private final Receiver mReceiver;
+
private UserHandle mUserHandle;
- public WorkModeConditionController(Context appContext) {
+ public WorkModeConditionController(Context appContext, ConditionManager manager) {
mAppContext = appContext;
mUm = mAppContext.getSystemService(UserManager.class);
+ mConditionManager = manager;
+ mReceiver = new Receiver();
}
@Override
@@ -66,12 +81,12 @@ public class WorkModeConditionController implements ConditionalCardController {
@Override
public void startMonitoringStateChange() {
-
+ mAppContext.registerReceiver(mReceiver, FILTER);
}
@Override
public void stopMonitoringStateChange() {
-
+ mAppContext.unregisterReceiver(mReceiver);
}
private void updateUserHandle() {
@@ -87,4 +102,15 @@ public class WorkModeConditionController implements ConditionalCardController {
}
}
}
+
+ public class Receiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (TextUtils.equals(action, Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
+ || TextUtils.equals(action, Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
+ mConditionManager.onConditionChanged();
+ }
+ }
+ }
}
diff --git a/src/com/android/settings/network/MobileNetworkPreferenceController.java b/src/com/android/settings/network/MobileNetworkPreferenceController.java
index 16d382c4264..06d3f87016c 100644
--- a/src/com/android/settings/network/MobileNetworkPreferenceController.java
+++ b/src/com/android/settings/network/MobileNetworkPreferenceController.java
@@ -19,6 +19,7 @@ import static android.os.UserHandle.myUserId;
import static android.os.UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -27,7 +28,9 @@ import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
+import android.util.FeatureFlagUtils;
+import com.android.settings.core.FeatureFlags;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedPreference;
@@ -44,7 +47,12 @@ import androidx.preference.PreferenceScreen;
public class MobileNetworkPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop {
- private static final String KEY_MOBILE_NETWORK_SETTINGS = "mobile_network_settings";
+ @VisibleForTesting
+ static final String KEY_MOBILE_NETWORK_SETTINGS = "mobile_network_settings";
+ @VisibleForTesting
+ static final String MOBILE_NETWORK_PACKAGE = "com.android.phone";
+ @VisibleForTesting
+ static final String MOBILE_NETWORK_CLASS = "com.android.phone.MobileNetworkSettings";
private final boolean mIsSecondaryUser;
private final TelephonyManager mTelephonyManager;
@@ -134,6 +142,22 @@ public class MobileNetworkPreferenceController extends AbstractPreferenceControl
mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 0);
}
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (KEY_MOBILE_NETWORK_SETTINGS.equals(preference.getKey())) {
+ if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.MOBILE_NETWORK_V2)) {
+ //TODO(b/110260193): go to the mobile network page existed in settings
+ } else {
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setComponent(
+ new ComponentName(MOBILE_NETWORK_PACKAGE, MOBILE_NETWORK_CLASS));
+ mContext.startActivity(intent);
+ }
+ return true;
+ }
+ return false;
+ }
+
@Override
public CharSequence getSummary() {
return mTelephonyManager.getNetworkOperatorName();
diff --git a/src/com/android/settings/widget/ValidatedEditTextPreference.java b/src/com/android/settings/widget/ValidatedEditTextPreference.java
index 76d8bcceb94..3204ab3894a 100644
--- a/src/com/android/settings/widget/ValidatedEditTextPreference.java
+++ b/src/com/android/settings/widget/ValidatedEditTextPreference.java
@@ -93,7 +93,8 @@ public class ValidatedEditTextPreference extends CustomEditTextPreferenceCompat
textView.setInputType(
InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
} else {
- textView.setInputType(InputType.TYPE_CLASS_TEXT);
+ textView.setInputType(
+ InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
}
}
diff --git a/tests/robotests/src/com/android/settings/applications/AppAndNotificationDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/applications/AppAndNotificationDashboardFragmentTest.java
deleted file mode 100644
index c332c064da3..00000000000
--- a/tests/robotests/src/com/android/settings/applications/AppAndNotificationDashboardFragmentTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.applications;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.UserManager;
-
-import com.android.settings.notification.EmergencyBroadcastPreferenceController;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-import java.util.List;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-public class AppAndNotificationDashboardFragmentTest {
-
- @Test
- @Config(shadows = {ShadowEmergencyBroadcastPreferenceController.class})
- public void getNonIndexableKeys_shouldIncludeSpecialAppAccess() {
- final Context context = spy(RuntimeEnvironment.application);
- UserManager manager = mock(UserManager.class);
- when(manager.isAdminUser()).thenReturn(true);
- when(context.getSystemService(Context.USER_SERVICE)).thenReturn(manager);
- final List niks = AppAndNotificationDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
- .getNonIndexableKeys(context);
-
- assertThat(niks).contains(
- new SpecialAppAccessPreferenceController(context).getPreferenceKey());
- }
-
- @Implements(EmergencyBroadcastPreferenceController.class)
- public static class ShadowEmergencyBroadcastPreferenceController {
-
- @Implementation
- public boolean isAvailable() {
- return true;
- }
- }
-}
diff --git a/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java
index 224a8f9561b..b6429151b67 100644
--- a/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java
@@ -16,15 +16,25 @@
package com.android.settings.applications;
+import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
+
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.verify;
+
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
import com.android.settings.R;
-import com.android.settings.datausage.DataSaverBackend;
+import com.android.settings.datausage.AppStateDataUsageBridge;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.ShadowApplicationsState;
+import com.android.settings.testutils.shadow.ShadowUserManager;
+import com.android.settingslib.applications.ApplicationsState;
import org.junit.Before;
import org.junit.Test;
@@ -32,48 +42,56 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.util.ReflectionHelpers;
+import org.robolectric.annotation.Config;
-import androidx.preference.Preference;
+import java.util.ArrayList;
@RunWith(SettingsRobolectricTestRunner.class)
+@Config(shadows = {ShadowUserManager.class, ShadowApplicationsState.class})
public class SpecialAppAccessPreferenceControllerTest {
private Context mContext;
@Mock
- private DataSaverBackend mBackend;
+ private ApplicationsState.Session mSession;
@Mock
- private Preference mPreference;
+ private PreferenceScreen mScreen;
private SpecialAppAccessPreferenceController mController;
+ private Preference mPreference;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
- mController = new SpecialAppAccessPreferenceController(mContext);
- ReflectionHelpers.setField(mController, "mDataSaverBackend", mBackend);
+ ShadowUserManager.getShadow().setProfileIdsWithDisabled(new int[]{0});
+ mController = new SpecialAppAccessPreferenceController(mContext, "test_key");
+ mPreference = new Preference(mContext);
+ when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+
+ mController.mSession = mSession;
}
@Test
- public void isAvailable_shouldAlwaysReturnTrue() {
- assertThat(mController.isAvailable()).isTrue();
+ public void getAvailabilityState_unsearchable() {
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE);
}
@Test
public void updateState_shouldSetSummary() {
- when(mBackend.getWhitelistedCount()).thenReturn(0);
+ final ArrayList apps = new ArrayList<>();
+ final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class);
+ entry.hasLauncherEntry = true;
+ entry.info = new ApplicationInfo();
+ entry.extraInfo = new AppStateDataUsageBridge.DataUsageState(
+ true /* whitelisted */, false /* blacklisted */);
+ apps.add(entry);
+ when(mSession.getAllApps()).thenReturn(apps);
- mController.updateState(mPreference);
+ mController.displayPreference(mScreen);
+ mController.onExtraInfoUpdated();
- verify(mPreference).setSummary(mContext.getResources()
- .getQuantityString(R.plurals.special_access_summary, 0, 0));
-
- when(mBackend.getWhitelistedCount()).thenReturn(1);
-
- mController.updateState(mPreference);
-
- verify(mPreference).setSummary(mContext.getResources()
- .getQuantityString(R.plurals.special_access_summary, 1, 1));
+ assertThat(mPreference.getSummary())
+ .isEqualTo(mContext.getResources().getQuantityString(
+ R.plurals.special_access_summary, 1, 1));
}
}
diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceControllerTest.java
index ce9fe2a837e..1f623211391 100644
--- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceControllerTest.java
@@ -17,8 +17,8 @@
package com.android.settings.applications.defaultapps;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyList;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
@@ -29,6 +29,8 @@ import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.UserManager;
@@ -45,14 +47,14 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
-import java.util.Arrays;
-import java.util.Collections;
-
import androidx.preference.Preference;
@RunWith(SettingsRobolectricTestRunner.class)
public class DefaultHomePreferenceControllerTest {
+ private static final String TEST_PACKAGE = "test.pkg";
+ private static final String TEST_CLASS = "class";
+
@Mock
private UserManager mUserManager;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
@@ -107,14 +109,14 @@ public class DefaultHomePreferenceControllerTest {
@Test
public void testIsHomeDefault_noDefaultSet_shouldReturnTrue() {
when(mPackageManager.getHomeActivities(anyList())).thenReturn(null);
- assertThat(DefaultHomePreferenceController.isHomeDefault("test.pkg", mPackageManager))
+ assertThat(DefaultHomePreferenceController.isHomeDefault(TEST_PACKAGE, mPackageManager))
.isTrue();
}
@Test
public void testIsHomeDefault_defaultSetToPkg_shouldReturnTrue() {
- final String pkgName = "test.pkg";
- final ComponentName defaultHome = new ComponentName(pkgName, "class");
+ final String pkgName = TEST_PACKAGE;
+ final ComponentName defaultHome = new ComponentName(pkgName, TEST_CLASS);
when(mPackageManager.getHomeActivities(anyList())).thenReturn(defaultHome);
@@ -124,8 +126,8 @@ public class DefaultHomePreferenceControllerTest {
@Test
public void testIsHomeDefault_defaultSetToOtherPkg_shouldReturnFalse() {
- final String pkgName = "test.pkg";
- final ComponentName defaultHome = new ComponentName("not" + pkgName, "class");
+ final String pkgName = TEST_PACKAGE;
+ final ComponentName defaultHome = new ComponentName("not" + pkgName, TEST_CLASS);
when(mPackageManager.getHomeActivities(anyList())).thenReturn(defaultHome);
@@ -136,29 +138,28 @@ public class DefaultHomePreferenceControllerTest {
@Test
public void testGetSettingIntent_homeHasNoSetting_shouldNotReturnSettingIntent() {
when(mPackageManager.getHomeActivities(anyList()))
- .thenReturn(new ComponentName("test.pkg", "class"));
+ .thenReturn(new ComponentName(TEST_PACKAGE, TEST_CLASS));
+ when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
+ .thenReturn(null);
+
assertThat(mController.getSettingIntent(mController.getDefaultAppInfo())).isNull();
}
@Test
public void testGetSettingIntent_homeHasOneSetting_shouldReturnSettingIntent() {
when(mPackageManager.getHomeActivities(anyList()))
- .thenReturn(new ComponentName("test.pkg", "class"));
- when(mPackageManager.queryIntentActivities(any(), eq(0)))
- .thenReturn(Collections.singletonList(mock(ResolveInfo.class)));
+ .thenReturn(new ComponentName(TEST_PACKAGE, TEST_CLASS));
+ final ResolveInfo info = mock(ResolveInfo.class);
+ info.activityInfo = mock(ActivityInfo.class);
+ info.activityInfo.name = TEST_CLASS;
+ info.activityInfo.applicationInfo = mock(ApplicationInfo.class);
+ info.activityInfo.applicationInfo.packageName = TEST_PACKAGE;
+ when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
+ .thenReturn(info);
Intent intent = mController.getSettingIntent(mController.getDefaultAppInfo());
assertThat(intent).isNotNull();
- assertThat(intent.getPackage()).isEqualTo("test.pkg");
- }
-
- @Test
- public void testGetSettingIntent_homeHasMultipleSettings_shouldNotReturnSettingIntent() {
- when(mPackageManager.getHomeActivities(anyList()))
- .thenReturn(new ComponentName("test.pkg", "class"));
- when(mPackageManager.queryIntentActivities(any(), eq(0)))
- .thenReturn(Arrays.asList(mock(ResolveInfo.class), mock(ResolveInfo.class)));
- assertThat(mController.getSettingIntent(mController.getDefaultAppInfo())).isNull();
+ assertThat(intent.getPackage()).isEqualTo(TEST_PACKAGE);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
index 62414e4b52f..848cdffe982 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
@@ -31,8 +31,8 @@ import android.content.Context;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowBluetoothDevice;
+import com.android.settings.testutils.shadow.ShadowBluetoothDevice;
import com.android.settingslib.bluetooth.A2dpProfile;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -55,7 +55,7 @@ import androidx.preference.PreferenceCategory;
import androidx.preference.SwitchPreference;
@RunWith(SettingsRobolectricTestRunner.class)
-@Config(shadows = SettingsShadowBluetoothDevice.class)
+@Config(shadows = {SettingsShadowBluetoothDevice.class, ShadowBluetoothDevice.class})
public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsControllerTestBase {
private BluetoothDetailsProfilesController mController;
@@ -290,8 +290,7 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
@Test
public void pbapProfileStartsEnabled() {
setupDevice(makeDefaultDeviceConfig());
- when(mCachedDevice.getPhonebookPermissionChoice())
- .thenReturn(CachedBluetoothDevice.ACCESS_ALLOWED);
+ mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
PbapServerProfile psp = mock(PbapServerProfile.class);
when(psp.getNameResource(mDevice)).thenReturn(R.string.bluetooth_profile_pbap);
when(psp.toString()).thenReturn(PbapServerProfile.NAME);
@@ -306,14 +305,14 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
pref.performClick();
assertThat(mProfiles.getPreferenceCount()).isEqualTo(1);
- verify(mCachedDevice).setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_REJECTED);
+ assertThat(mDevice.getPhonebookAccessPermission())
+ .isEqualTo(BluetoothDevice.ACCESS_REJECTED);
}
@Test
public void pbapProfileStartsDisabled() {
setupDevice(makeDefaultDeviceConfig());
- when(mCachedDevice.getPhonebookPermissionChoice())
- .thenReturn(CachedBluetoothDevice.ACCESS_REJECTED);
+ mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
PbapServerProfile psp = mock(PbapServerProfile.class);
when(psp.getNameResource(mDevice)).thenReturn(R.string.bluetooth_profile_pbap);
when(psp.toString()).thenReturn(PbapServerProfile.NAME);
@@ -328,7 +327,8 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
pref.performClick();
assertThat(mProfiles.getPreferenceCount()).isEqualTo(1);
- verify(mCachedDevice).setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_ALLOWED);
+ assertThat(mDevice.getPhonebookAccessPermission())
+ .isEqualTo(BluetoothDevice.ACCESS_ALLOWED);
}
@Test
@@ -338,8 +338,7 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
when(mapProfile.getNameResource(mDevice)).thenReturn(R.string.bluetooth_profile_map);
when(mProfileManager.getMapProfile()).thenReturn(mapProfile);
when(mProfileManager.getProfileByName(eq(mapProfile.toString()))).thenReturn(mapProfile);
- when(mCachedDevice.getMessagePermissionChoice())
- .thenReturn(CachedBluetoothDevice.ACCESS_REJECTED);
+ mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED);
showScreen(mController);
List switches = getProfileSwitches(false);
assertThat(switches.size()).isEqualTo(1);
@@ -349,7 +348,7 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
pref.performClick();
assertThat(mProfiles.getPreferenceCount()).isEqualTo(1);
- verify(mCachedDevice).setMessagePermissionChoice(BluetoothDevice.ACCESS_ALLOWED);
+ assertThat(mDevice.getMessageAccessPermission()).isEqualTo(BluetoothDevice.ACCESS_ALLOWED);
}
private A2dpProfile addMockA2dpProfile(boolean preferred, boolean supportsHighQualityAudio,
diff --git a/tests/robotests/src/com/android/settings/development/HighFrequencyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/HighFrequencyPreferenceControllerTest.java
new file mode 100644
index 00000000000..cf8babb5114
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/HighFrequencyPreferenceControllerTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.development;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.ShadowParcel;
+
+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;
+import org.robolectric.util.ReflectionHelpers;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class HighFrequencyPreferenceControllerTest {
+
+ private Context mContext;
+ private SwitchPreference mPreference;
+
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private IBinder mSurfaceFlingerBinder;
+
+ private HighFrequencyDisplayPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mPreference = new SwitchPreference(mContext);
+ mController = spy(new HighFrequencyDisplayPreferenceController(mContext));
+ ReflectionHelpers.setField(mController, "mSurfaceFlingerBinder", mSurfaceFlingerBinder);
+ when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+ mController.displayPreference(mScreen);
+ }
+
+ @Test
+ public void onPreferenceChange_settingToggledOn_shouldWriteTrueToHighFrequencySetting() {
+ mController.onPreferenceChange(mPreference, true /* new value */);
+
+ verify(mController).writeHighFrequencyDisplaySetting(true);
+ }
+
+ @Test
+ public void onPreferenceChange_settingToggledOff_shouldWriteFalseToHighFrequencySetting() {
+ mController.onPreferenceChange(mPreference, false /* new value */);
+
+ verify(mController).writeHighFrequencyDisplaySetting(false);
+ }
+
+ @Test
+ public void updateState_settingEnabled_shouldCheckPreference() throws RemoteException {
+ mController.writeHighFrequencyDisplaySetting(true);
+ mController.updateState(mPreference);
+
+ verify(mController).readHighFrequencyDisplaySetting();
+ }
+
+ @Test
+ public void updateState_settingDisabled_shouldUnCheckPreference() throws RemoteException {
+ mController.writeHighFrequencyDisplaySetting(true);
+ mController.updateState(mPreference);
+
+ verify(mController).readHighFrequencyDisplaySetting();
+ }
+
+ @Test
+ public void onDeveloperOptionsSwitchDisabled_preferenceChecked_shouldTurnOffPreference() {
+ mController.onDeveloperOptionsSwitchDisabled();
+
+ verify(mController).writeHighFrequencyDisplaySetting(false);
+ }
+
+ @Test
+ public void onDeveloperOptionsSwitchDisabled_preferenceUnchecked_shouldNotTurnOffPreference() {
+ mController.onDeveloperOptionsSwitchDisabled();
+
+ verify(mController).writeHighFrequencyDisplaySetting(false);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/conditional/BackgroundDataConditionControllerTest.java b/tests/robotests/src/com/android/settings/homepage/conditional/BackgroundDataConditionControllerTest.java
index 4ad7e6dee7b..e3db59b0853 100644
--- a/tests/robotests/src/com/android/settings/homepage/conditional/BackgroundDataConditionControllerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/conditional/BackgroundDataConditionControllerTest.java
@@ -22,28 +22,37 @@ import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.Intent;
+import android.net.NetworkPolicyManager;
import com.android.settings.Settings;
-import com.android.settings.homepage.conditional.BackgroundDataConditionController;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
@RunWith(SettingsRobolectricTestRunner.class)
public class BackgroundDataConditionControllerTest {
+
+ @Mock
+ private ConditionManager mConditionManager;
+ @Mock
+ private NetworkPolicyManager mNetworkPolicyManager;
private Context mContext;
private BackgroundDataConditionController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ ShadowApplication.getInstance().setSystemService(Context.NETWORK_POLICY_SERVICE,
+ mNetworkPolicyManager);
mContext = spy(RuntimeEnvironment.application);
- mController = new BackgroundDataConditionController(mContext);
+ mController = new BackgroundDataConditionController(mContext, mConditionManager);
}
@Test
@@ -56,4 +65,10 @@ public class BackgroundDataConditionControllerTest {
assertThat(intent.getComponent().getClassName()).isEqualTo(
Settings.DataUsageSummaryActivity.class.getName());
}
+
+ @Test
+ public void onActionClick_shouldRefreshCondition() {
+ mController.onActionClick();
+ verify(mConditionManager).onConditionChanged();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/homepage/conditional/NightDisplayConditionControllerTest.java b/tests/robotests/src/com/android/settings/homepage/conditional/NightDisplayConditionControllerTest.java
new file mode 100644
index 00000000000..130df90c696
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/conditional/NightDisplayConditionControllerTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.homepage.conditional;
+
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+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;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class NightDisplayConditionControllerTest {
+
+ @Mock
+ private ConditionManager mConditionManager;
+
+ private Context mContext;
+ private NightDisplayConditionController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mController = new NightDisplayConditionController(mContext, mConditionManager);
+ }
+
+ @Test
+ public void onActivated_shouldUpdateCondition() {
+ mController.onActivated(true);
+
+ verify(mConditionManager).onConditionChanged();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/conditional/WorkModeConditionControllerTest.java b/tests/robotests/src/com/android/settings/homepage/conditional/WorkModeConditionControllerTest.java
index 52c9ffedbf0..c993e68923d 100644
--- a/tests/robotests/src/com/android/settings/homepage/conditional/WorkModeConditionControllerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/conditional/WorkModeConditionControllerTest.java
@@ -24,24 +24,28 @@ import android.content.ComponentName;
import android.content.Context;
import com.android.settings.Settings;
-import com.android.settings.homepage.conditional.WorkModeConditionController;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
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;
@RunWith(SettingsRobolectricTestRunner.class)
public class WorkModeConditionControllerTest {
+ @Mock
+ private ConditionManager mConditionManager;
private Context mContext;
private WorkModeConditionController mController;
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
- mController = new WorkModeConditionController(mContext);
+ mController = new WorkModeConditionController(mContext, mConditionManager);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java
index 2c15a6dd088..2941e902c6e 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java
@@ -15,9 +15,11 @@
*/
package com.android.settings.network;
-import static androidx.lifecycle.Lifecycle.Event.ON_START;
-import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+import static com.android.settings.network.MobileNetworkPreferenceController.MOBILE_NETWORK_CLASS;
+import static com.android.settings.network.MobileNetworkPreferenceController.MOBILE_NETWORK_PACKAGE;
+
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -25,14 +27,21 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.shadow.api.Shadow.extract;
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.net.ConnectivityManager;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
+import android.util.FeatureFlagUtils;
+import com.android.settings.core.FeatureFlags;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowConnectivityManager;
import com.android.settings.testutils.shadow.ShadowUserManager;
@@ -43,6 +52,7 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
@@ -68,6 +78,7 @@ public class MobileNetworkPreferenceControllerTest {
private Lifecycle mLifecycle;
private LifecycleOwner mLifecycleOwner;
private MobileNetworkPreferenceController mController;
+ private Preference mPreference;
@Before
public void setUp() {
@@ -76,6 +87,8 @@ public class MobileNetworkPreferenceControllerTest {
mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner);
when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
+ mPreference = new Preference(mContext);
+ mPreference.setKey(MobileNetworkPreferenceController.KEY_MOBILE_NETWORK_SETTINGS);
}
@Test
@@ -173,4 +186,18 @@ public class MobileNetworkPreferenceControllerTest {
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isFalse();
}
+
+ @Test
+ public void handlePreferenceTreeClick_mobileFeatureDisabled_sendIntent() {
+ mController = new MobileNetworkPreferenceController(mContext);
+ FeatureFlagUtils.setEnabled(mContext, FeatureFlags.MOBILE_NETWORK_V2, false);
+ ArgumentCaptor argument = ArgumentCaptor.forClass(Intent.class);
+
+ mController.handlePreferenceTreeClick(mPreference);
+
+ verify(mContext).startActivity(argument.capture());
+ final ComponentName componentName = argument.getValue().getComponent();
+ assertThat(componentName.getPackageName()).isEqualTo(MOBILE_NETWORK_PACKAGE);
+ assertThat(componentName.getClassName()).isEqualTo(MOBILE_NETWORK_CLASS);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowApplicationsState.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowApplicationsState.java
new file mode 100644
index 00000000000..3ee4fcb1647
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowApplicationsState.java
@@ -0,0 +1,32 @@
+/*
+ * 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.testutils.shadow;
+
+import android.os.Looper;
+
+import com.android.settingslib.applications.ApplicationsState;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@Implements(ApplicationsState.class)
+public class ShadowApplicationsState {
+ @Implementation
+ public Looper getBackgroundLooper() {
+ return Looper.getMainLooper();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowBluetoothDevice.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowBluetoothDevice.java
new file mode 100644
index 00000000000..4cc77c3b072
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowBluetoothDevice.java
@@ -0,0 +1,59 @@
+/*
+ * 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.testutils.shadow;
+
+import android.bluetooth.BluetoothDevice;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@Implements(value = BluetoothDevice.class, inheritImplementationMethods = true)
+public class ShadowBluetoothDevice extends org.robolectric.shadows.ShadowBluetoothDevice {
+
+ private int mMessageAccessPermission = BluetoothDevice.ACCESS_UNKNOWN;
+ private int mPhonebookAccessPermission = BluetoothDevice.ACCESS_UNKNOWN;
+ private int mSimAccessPermission = BluetoothDevice.ACCESS_UNKNOWN;
+
+ @Implementation
+ public void setMessageAccessPermission(int value) {
+ mMessageAccessPermission = value;
+ }
+
+ @Implementation
+ public int getMessageAccessPermission() {
+ return mMessageAccessPermission;
+ }
+
+ @Implementation
+ public void setPhonebookAccessPermission(int value) {
+ mPhonebookAccessPermission = value;
+ }
+
+ @Implementation
+ public int getPhonebookAccessPermission() {
+ return mPhonebookAccessPermission;
+ }
+
+ @Implementation
+ public void setSimAccessPermission(int value) {
+ mSimAccessPermission = value;
+ }
+
+ @Implementation
+ public int getSimAccessPermission() {
+ return mSimAccessPermission;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java
index 5b332825e3e..e5cb12d4405 100644
--- a/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java
@@ -131,4 +131,16 @@ public class ValidatedEditTextPreferenceTest {
& (InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_CLASS_TEXT))
.isNotEqualTo(0);
}
+
+ @Test
+ public void bindViewHolder_isNotPassword_shouldNotAutoCorrectText() {
+ final TextView textView = spy(new TextView(RuntimeEnvironment.application));
+ when(mViewHolder.findViewById(android.R.id.summary)).thenReturn(textView);
+
+ mPreference.setIsSummaryPassword(false);
+ mPreference.onBindViewHolder(mViewHolder);
+
+ assertThat(textView.getInputType()).isEqualTo(
+ InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_CLASS_TEXT);
+ }
}