Merge "Bluetooth: remove unused SINK_STATE_CHANGED action" am: fb0ab547c2 am: e10af2add7
am: 5741187f31
Change-Id: I7ecebb4aebb9755571baebf00718156d28415f3e
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ddbe730..f92149e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -6,6 +6,9 @@
<original-package android:name="com.android.settings" />
+ <protected-broadcast android:name="com.android.settings.CARRIER_PROVISIONING" />
+ <protected-broadcast android:name="com.android.settings.TRIGGER_CARRIER_PROVISIONING" />
+
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
diff --git a/res/layout/radio_info.xml b/res/layout/radio_info.xml
index e11e997..e2447fe 100644
--- a/res/layout/radio_info.xml
+++ b/res/layout/radio_info.xml
@@ -302,5 +302,23 @@
android:textSize="12sp" />
</LinearLayout>
+ <!-- Carrier Provisioning -->
+ <LinearLayout style="@style/entry_layout">
+ <Button android:id="@+id/carrier_provisioning"
+ android:textSize="14sp"
+ android:layout_marginTop="8dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/carrier_provisioning"
+ />
+ <Button android:id="@+id/trigger_carrier_provisioning"
+ android:textSize="14sp"
+ android:layout_marginTop="8dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/trigger_carrier_provisioning"
+ />
+ </LinearLayout>
+
</LinearLayout>
</ScrollView>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8789aef..dd2188b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -81,7 +81,23 @@
<!-- Phone Info screen. Menu item label. Used for diagnostic info screens, precise translation isn't needed -->
<string name="radioInfo_menu_viewSDN">View Service Dialing Numbers</string>
<!-- Phone Info screen. Menu item label. Used for diagnostic info screens, precise translation isn't needed -->
- <string name="radioInfo_menu_getPDP">Get PDP List</string>
+ <string name="radioInfo_menu_getIMS">IMS Service Status</string>
+
+ <!-- Phone Info screen. IMS Registration Title. Used for diagnostic info screens, precise translation isn't needed -->
+ <string name="radio_info_ims_reg_status_title">IMS Status</string>
+
+ <!-- Phone Info screen. IMS Status - Registered. Used for diagnostic info screens, precise translation isn't needed -->
+ <string name="radio_info_ims_reg_status_registered">Registered</string>
+ <!-- Phone Info screen. Ims Status - Unregistered. Used for diagnostic info screens, precise translation isn't needed -->
+ <string name="radio_info_ims_reg_status_not_registered">Not Registered</string>
+
+ <!-- Phone Info screen. Ims Feature Status label. Used for diagnostic info screens, precise translation isn't needed -->
+ <string name="radio_info_ims_feature_status_available">Available</string>
+ <!-- Phone Info screen. Ims Feature status label. Used for diagnostic info screens, precise translation isn't needed -->
+ <string name="radio_info_ims_feature_status_unavailable">Unavailable</string>
+
+ <!-- Phone Info screen. IMS Registration. Used for diagnostic info screens, precise translation isn't needed -->
+ <string name="radio_info_ims_reg_status">IMS Registration: <xliff:g id="status" example="registered">%1$s</xliff:g>\u000AVoice over LTE: <xliff:g id="availability" example="available">%2$s</xliff:g>\u000AVoice over WiFi: <xliff:g id="availability" example="available">%3$s</xliff:g>\u000AVideo Calling: <xliff:g id="availability" example="available">%4$s</xliff:g>\u000AUT Interface: <xliff:g id="availability" example="available">%5$s</xliff:g></string>
<!-- Phone Info screen. Status label. Used for diagnostic info screens, precise translation isn't needed -->
<string name="radioInfo_service_in">In Service</string>
@@ -6884,6 +6900,9 @@
<!-- Label for list to control apps that ignore battery saving restrictions [CHAR LIMIT=27]-->
<string name="high_power_apps">Battery optimization</string>
+ <!-- Label for menu to launch a screen showing usage alerts for battery [CHAR LIMIT=30] -->
+ <string name="additional_battery_info">Usage alerts</string>
+
<!-- Filter for apps allowed to use a lot of power [CHAR LIMIT=25] -->
<string name="high_power_filter_on">Not optimized</string>
@@ -7864,4 +7883,10 @@
<!-- Warning when activating the automatic storage manager on legacy devices. [CHAR LIMIT=NONE] -->
<string name="automatic_storage_manager_activation_warning">Your storage is now being managed by the storage manager</string>
+
+ <!-- Carrier Provisioning Info [CHAR LIMIT=NONE] -->
+ <string name="carrier_provisioning">Carrier Provisioning Info</string>
+ <!-- Trigger Carrier Provisioning [CHAR LIMIT=NONE] -->
+ <string name="trigger_carrier_provisioning">Trigger Carrier Provisioning</string>
+
</resources>
diff --git a/res/xml/suggestion_ordering.xml b/res/xml/suggestion_ordering.xml
index 1eeafba..1da4067 100644
--- a/res/xml/suggestion_ordering.xml
+++ b/res/xml/suggestion_ordering.xml
@@ -15,6 +15,7 @@
-->
<optional-steps>
+ <step category="com.android.settings.suggested.category.RESTORE_BACKUP" />
<step category="com.android.settings.suggested.category.LOCK_SCREEN" />
<step category="com.android.settings.suggested.category.EMAIL" />
<step category="com.android.settings.suggested.category.PARTNER_ACCOUNT"
diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java
index d109eb1..e059041 100644
--- a/src/com/android/settings/ChooseLockGeneric.java
+++ b/src/com/android/settings/ChooseLockGeneric.java
@@ -186,22 +186,15 @@
ENCRYPT_REQUESTED_DISABLED);
}
- int targetUser = Utils.getSecureTargetUser(
+ // a) If this is started from other user, use that user id.
+ // b) If this is started from the same user, read the extra if this is launched
+ // from Settings app itself.
+ // c) Otherwise, use UserHandle.myUserId().
+ mUserId = Utils.getSecureTargetUser(
getActivity().getActivityToken(),
UserManager.get(getActivity()),
- null,
+ getArguments(),
getActivity().getIntent().getExtras()).getIdentifier();
- if (ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(chooseLockAction)
- || !mLockPatternUtils.isSeparateProfileChallengeAllowed(targetUser)) {
- // Always use parent if explicitely requested or if profile challenge is not
- // supported
- Bundle arguments = getArguments();
- mUserId = Utils.getUserIdFromBundle(getContext(), arguments != null ? arguments
- : getActivity().getIntent().getExtras());
- } else {
- mUserId = targetUser;
- }
-
if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction)
&& Utils.isManagedProfile(UserManager.get(getActivity()), mUserId)
&& mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
@@ -256,6 +249,8 @@
} else if (KEY_SKIP_FINGERPRINT.equals(key)) {
Intent chooseLockGenericIntent = new Intent(getActivity(), ChooseLockGeneric.class);
chooseLockGenericIntent.setAction(getIntent().getAction());
+ // Forward the target user id to ChooseLockGeneric.
+ chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
chooseLockGenericIntent.putExtra(PASSWORD_CONFIRMED, mPasswordConfirmed);
startActivityForResult(chooseLockGenericIntent, SKIP_FINGERPRINT_REQUEST);
return true;
@@ -343,6 +338,8 @@
if (data != null) {
intent.putExtras(data.getExtras());
}
+ // Forward the target user id to fingerprint setup page.
+ intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
startActivity(intent);
finish();
} else if (requestCode == SKIP_FINGERPRINT_REQUEST) {
diff --git a/src/com/android/settings/InstrumentedFragment.java b/src/com/android/settings/InstrumentedFragment.java
index 8bab2cf..2966800 100644
--- a/src/com/android/settings/InstrumentedFragment.java
+++ b/src/com/android/settings/InstrumentedFragment.java
@@ -16,10 +16,14 @@
package com.android.settings;
+import android.app.Activity;
+import android.content.BroadcastReceiver;
import android.os.Bundle;
import android.support.v14.preference.PreferenceFragment;
import com.android.internal.logging.MetricsLogger;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.overlay.SurveyFeatureProvider;
/**
* Instrumented fragment that logs visibility state.
@@ -39,6 +43,7 @@
* {@link com.android.settings.InstrumentedFragment}.
*/
protected abstract int getMetricsCategory();
+ private BroadcastReceiver mReceiver;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@@ -48,10 +53,34 @@
public void onResume() {
super.onResume();
MetricsLogger.visible(getActivity(), getMetricsCategory());
+
+ Activity activity = getActivity();
+ // guard against the activity not existing yet or the feature being disabled
+ if (activity != null) {
+ SurveyFeatureProvider provider =
+ FeatureFactory.getFactory(activity).getSurveyFeatureProvider(activity);
+ if (provider != null) {
+ // Try to download a survey if there is none available, show the survey otherwise
+ String id = provider.getSurveyId(activity, getClass().getSimpleName());
+ if (provider.getSurveyExpirationDate(activity, id) <= -1) {
+ // register the receiver to show the survey on completion.
+ mReceiver = provider.createAndRegisterReceiver(activity);
+ provider.downloadSurvey(activity, id, "fakeData");
+ } else {
+ provider.showSurveyIfAvailable(activity, id);
+ }
+ }
+ }
}
@Override
public void onPause() {
+ Activity activity = getActivity();
+ if (mReceiver != null && activity != null) {
+ SurveyFeatureProvider.unregisterReceiver(activity, mReceiver);
+ mReceiver = null;
+ }
+
super.onPause();
MetricsLogger.hidden(getActivity(), getMetricsCategory());
}
diff --git a/src/com/android/settings/InstrumentedPreferenceFragment.java b/src/com/android/settings/InstrumentedPreferenceFragment.java
index 243e0bc..ba6cb79 100644
--- a/src/com/android/settings/InstrumentedPreferenceFragment.java
+++ b/src/com/android/settings/InstrumentedPreferenceFragment.java
@@ -16,9 +16,13 @@
package com.android.settings;
+import android.app.Activity;
+import android.content.BroadcastReceiver;
import android.support.v14.preference.PreferenceFragment;
import com.android.internal.logging.MetricsLogger;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.overlay.SurveyFeatureProvider;
/**
* Instrumented preference fragment that logs visibility state.
@@ -32,15 +36,40 @@
* {@link com.android.settings.InstrumentedFragment}.
*/
protected abstract int getMetricsCategory();
+ private BroadcastReceiver mReceiver;
@Override
public void onResume() {
super.onResume();
MetricsLogger.visible(getActivity(), getMetricsCategory());
+
+ Activity activity = getActivity();
+ // guard against the activity not existing yet or the feature being disabled
+ if (activity != null) {
+ SurveyFeatureProvider provider =
+ FeatureFactory.getFactory(activity).getSurveyFeatureProvider(activity);
+ if (provider != null) {
+ // Try to download a survey if there is none available, show the survey otherwise
+ String id = provider.getSurveyId(activity, getClass().getSimpleName());
+ if (provider.getSurveyExpirationDate(activity, id) <= -1) {
+ // register the receiver to show the survey on completion.
+ mReceiver = provider.createAndRegisterReceiver(activity);
+ provider.downloadSurvey(activity, id, null /* data */);
+ } else {
+ provider.showSurveyIfAvailable(activity, id);
+ }
+ }
+ }
}
@Override
public void onPause() {
+ Activity activity = getActivity();
+ if (mReceiver != null && activity != null) {
+ SurveyFeatureProvider.unregisterReceiver(activity, mReceiver);
+ mReceiver = null;
+ }
+
super.onPause();
MetricsLogger.hidden(getActivity(), getMetricsCategory());
}
diff --git a/src/com/android/settings/RadioInfo.java b/src/com/android/settings/RadioInfo.java
index 54ff4db..65a784a 100644
--- a/src/com/android/settings/RadioInfo.java
+++ b/src/com/android/settings/RadioInfo.java
@@ -17,6 +17,8 @@
package com.android.settings;
import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
import android.app.QueuedWork;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -160,7 +162,7 @@
private static final int MENU_ITEM_VIEW_ADN = 1;
private static final int MENU_ITEM_VIEW_FDN = 2;
private static final int MENU_ITEM_VIEW_SDN = 3;
- private static final int MENU_ITEM_GET_PDP_LIST = 4;
+ private static final int MENU_ITEM_GET_IMS_STATUS = 4;
private static final int MENU_ITEM_TOGGLE_DATA = 5;
private TextView mDeviceId; //DeviceId is the IMEI in GSM and the MEID in CDMA
@@ -193,6 +195,8 @@
private Button updateSmscButton;
private Button refreshSmscButton;
private Button oemInfoButton;
+ private Button carrierProvisioningButton;
+ private Button triggercarrierProvisioningButton;
private Switch imsVolteProvisionedSwitch;
private Switch imsVtProvisionedSwitch;
private Switch imsWfcProvisionedSwitch;
@@ -412,6 +416,11 @@
refreshSmscButton.setOnClickListener(mRefreshSmscButtonHandler);
dnsCheckToggleButton = (Button) findViewById(R.id.dns_check_toggle);
dnsCheckToggleButton.setOnClickListener(mDnsCheckButtonHandler);
+ carrierProvisioningButton = (Button) findViewById(R.id.carrier_provisioning);
+ carrierProvisioningButton.setOnClickListener(mCarrierProvisioningButtonHandler);
+ triggercarrierProvisioningButton = (Button) findViewById(R.id.trigger_carrier_provisioning);
+ triggercarrierProvisioningButton.setOnClickListener(
+ mTriggerCarrierProvisioningButtonHandler);
oemInfoButton = (Button) findViewById(R.id.oem_info);
oemInfoButton.setOnClickListener(mOemInfoButtonHandler);
@@ -497,7 +506,7 @@
}
private void restoreFromBundle(Bundle b) {
- if( b == null) {
+ if (b == null) {
return;
}
@@ -537,8 +546,8 @@
R.string.radioInfo_menu_viewFDN).setOnMenuItemClickListener(mViewFDNCallback);
menu.add(1, MENU_ITEM_VIEW_SDN, 0,
R.string.radioInfo_menu_viewSDN).setOnMenuItemClickListener(mViewSDNCallback);
- menu.add(1, MENU_ITEM_GET_PDP_LIST,
- 0, R.string.radioInfo_menu_getPDP).setOnMenuItemClickListener(mGetPdpList);
+ menu.add(1, MENU_ITEM_GET_IMS_STATUS,
+ 0, R.string.radioInfo_menu_getIMS).setOnMenuItemClickListener(mGetImsStatus);
menu.add(1, MENU_ITEM_TOGGLE_DATA,
0, R.string.radio_info_data_connection_disable).setOnMenuItemClickListener(mToggleData);
return true;
@@ -632,7 +641,7 @@
StringBuilder sb = new StringBuilder();
if (cids != null) {
- if ( cids.isEmpty() ) {
+ if (cids.isEmpty()) {
sb.append("no neighboring cells");
} else {
for (NeighboringCellInfo cell : cids) {
@@ -860,7 +869,7 @@
}
private final void updateNetworkType() {
- if( phone != null ) {
+ if (phone != null) {
ServiceState ss = phone.getServiceState();
dataNetwork.setText(ServiceState.rilRadioTechnologyToString(
phone.getServiceState().getRilDataRadioTechnology()));
@@ -1069,10 +1078,36 @@
}
};
- private MenuItem.OnMenuItemClickListener mGetPdpList = new MenuItem.OnMenuItemClickListener() {
+ private MenuItem.OnMenuItemClickListener mGetImsStatus = new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
- //FIXME: Replace with a TelephonyManager call
- phone.getDataCallList(null);
+ boolean isImsRegistered = phone.isImsRegistered();
+ boolean availableVolte = phone.isVolteEnabled();
+ boolean availableWfc = phone.isWifiCallingEnabled();
+ boolean availableVt = phone.isVideoEnabled();
+ boolean availableUt = phone.isUtEnabled();
+
+ final String imsRegString = isImsRegistered ?
+ getString(R.string.radio_info_ims_reg_status_registered) :
+ getString(R.string.radio_info_ims_reg_status_not_registered);
+
+ final String available = getString(R.string.radio_info_ims_feature_status_available);
+ final String unavailable = getString(
+ R.string.radio_info_ims_feature_status_unavailable);
+
+ String imsStatus = getString(R.string.radio_info_ims_reg_status,
+ imsRegString,
+ availableVolte ? available : unavailable,
+ availableWfc ? available : unavailable,
+ availableVt ? available : unavailable,
+ availableUt ? available : unavailable);
+
+ AlertDialog imsDialog = new AlertDialog.Builder(RadioInfo.this)
+ .setMessage(imsStatus)
+ .setTitle(getString(R.string.radio_info_ims_reg_status_title))
+ .create();
+
+ imsDialog.show();
+
return true;
}
};
@@ -1119,22 +1154,22 @@
radioPowerOnSwitch.setOnCheckedChangeListener(mRadioPowerOnChangeListener);
}
- void setImsVolteProvisionedState( boolean state ) {
+ void setImsVolteProvisionedState(boolean state) {
Log.d(TAG, "setImsVolteProvisioned state: " + ((state)? "on":"off"));
- setImsConfigProvisionedState( IMS_VOLTE_PROVISIONED_CONFIG_ID, state );
+ setImsConfigProvisionedState(IMS_VOLTE_PROVISIONED_CONFIG_ID, state);
}
- void setImsVtProvisionedState( boolean state ) {
+ void setImsVtProvisionedState(boolean state) {
Log.d(TAG, "setImsVtProvisioned() state: " + ((state)? "on":"off"));
- setImsConfigProvisionedState( IMS_VT_PROVISIONED_CONFIG_ID, state );
+ setImsConfigProvisionedState(IMS_VT_PROVISIONED_CONFIG_ID, state);
}
- void setImsWfcProvisionedState( boolean state ) {
+ void setImsWfcProvisionedState(boolean state) {
Log.d(TAG, "setImsWfcProvisioned() state: " + ((state)? "on":"off"));
- setImsConfigProvisionedState( IMS_WFC_PROVISIONED_CONFIG_ID, state );
+ setImsConfigProvisionedState(IMS_WFC_PROVISIONED_CONFIG_ID, state);
}
- void setImsConfigProvisionedState( int configItem, boolean state ) {
+ void setImsConfigProvisionedState(int configItem, boolean state) {
if (phone != null && mImsManager != null) {
QueuedWork.singleThreadExecutor().submit(new Runnable() {
public void run() {
@@ -1170,7 +1205,7 @@
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
setImsVolteProvisionedState(isChecked);
- }
+ }
};
private boolean isImsVtProvisioned() {
@@ -1185,7 +1220,7 @@
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
setImsVtProvisionedState(isChecked);
- }
+ }
};
private boolean isImsWfcProvisioned() {
@@ -1200,7 +1235,7 @@
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
setImsWfcProvisionedState(isChecked);
- }
+ }
};
private void updateImsProvisionedState() {
@@ -1210,14 +1245,20 @@
imsVolteProvisionedSwitch.setOnCheckedChangeListener(null);
imsVolteProvisionedSwitch.setChecked(isImsVolteProvisioned());
imsVolteProvisionedSwitch.setOnCheckedChangeListener(mImsVolteCheckedChangeListener);
+ imsVolteProvisionedSwitch.setEnabled(
+ mImsManager.isVolteEnabledByPlatform(phone.getContext()));
imsVtProvisionedSwitch.setOnCheckedChangeListener(null);
imsVtProvisionedSwitch.setChecked(isImsVtProvisioned());
imsVtProvisionedSwitch.setOnCheckedChangeListener(mImsVtCheckedChangeListener);
+ imsVtProvisionedSwitch.setEnabled(
+ mImsManager.isVtEnabledByPlatform(phone.getContext()));
imsWfcProvisionedSwitch.setOnCheckedChangeListener(null);
imsWfcProvisionedSwitch.setChecked(isImsWfcProvisioned());
imsWfcProvisionedSwitch.setOnCheckedChangeListener(mImsWfcCheckedChangeListener);
+ imsWfcProvisionedSwitch.setEnabled(
+ mImsManager.isWfcEnabledByPlatform(phone.getContext()));
}
OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
@@ -1261,6 +1302,22 @@
}
};
+ OnClickListener mCarrierProvisioningButtonHandler = new OnClickListener() {
+ public void onClick(View v) {
+ Intent intent = new Intent("com.android.settings.CARRIER_PROVISIONING");
+ getApplicationContext().sendBroadcast(
+ intent, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+ }
+ };
+
+ OnClickListener mTriggerCarrierProvisioningButtonHandler = new OnClickListener() {
+ public void onClick(View v) {
+ Intent intent = new Intent("com.android.settings.TRIGGER_CARRIER_PROVISIONING");
+ getApplicationContext().sendBroadcast(
+ intent, android.Manifest.permission.MODIFY_PHONE_STATE);
+ }
+ };
+
AdapterView.OnItemSelectedListener mPreferredNetworkHandler =
new AdapterView.OnItemSelectedListener() {
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index dd62c6f..eec269f 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -102,6 +102,7 @@
import java.util.Locale;
import static android.content.Intent.EXTRA_USER;
+import static android.content.Intent.EXTRA_USER_ID;
import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
@@ -651,16 +652,21 @@
/**
* Returns the target user for a Settings activity.
- *
- * The target user can be either the current user, the user that launched this activity or
- * the user contained as an extra in the arguments or intent extras.
- *
+ * <p>
+ * User would be retrieved in this order:
+ * <ul>
+ * <li> If this activity is launched from other user, return that user id.
+ * <li> If this is launched from the Settings app in same user, return the user contained as an
+ * extra in the arguments or intent extras.
+ * <li> Otherwise, return UserHandle.myUserId().
+ * </ul>
+ * <p>
* Note: This is secure in the sense that it only returns a target user different to the current
* one if the app launching this activity is the Settings app itself, running in the same user
* or in one that is in the same profile group, or if the user id is provided by the system.
*/
public static UserHandle getSecureTargetUser(IBinder activityToken,
- UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras) {
+ UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras) {
UserHandle currentUser = new UserHandle(UserHandle.myUserId());
IActivityManager am = ActivityManagerNative.getDefault();
try {
@@ -675,16 +681,14 @@
return launchedFromUser;
}
}
- UserHandle extrasUser = intentExtras != null
- ? (UserHandle) intentExtras.getParcelable(EXTRA_USER) : null;
+ UserHandle extrasUser = getUserHandleFromBundle(intentExtras);
if (extrasUser != null && !extrasUser.equals(currentUser)) {
// Check it's secure
if (launchedFromSettingsApp && isProfileOf(um, extrasUser)) {
return extrasUser;
}
}
- UserHandle argumentsUser = arguments != null
- ? (UserHandle) arguments.getParcelable(EXTRA_USER) : null;
+ UserHandle argumentsUser = getUserHandleFromBundle(arguments);
if (argumentsUser != null && !argumentsUser.equals(currentUser)) {
// Check it's secure
if (launchedFromSettingsApp && isProfileOf(um, argumentsUser)) {
@@ -696,7 +700,26 @@
Log.v(TAG, "Could not talk to activity manager.", e);
}
return currentUser;
- }
+ }
+
+ /**
+ * Lookup both {@link Intent#EXTRA_USER} and {@link Intent#EXTRA_USER_ID} in the bundle
+ * and return the {@link UserHandle} object. Return {@code null} if nothing is found.
+ */
+ private static @Nullable UserHandle getUserHandleFromBundle(Bundle bundle) {
+ if (bundle == null) {
+ return null;
+ }
+ final UserHandle user = bundle.getParcelable(EXTRA_USER);
+ if (user != null) {
+ return user;
+ }
+ final int userId = bundle.getInt(EXTRA_USER_ID, -1);
+ if (userId != -1) {
+ return UserHandle.of(userId);
+ }
+ return null;
+ }
/**
* Returns the target user for a Settings activity.
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
index b176efd..300451d 100755
--- a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
@@ -96,6 +96,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mReceiverRegistered = false;
Intent intent = getIntent();
if (!intent.getAction().equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) {
@@ -129,6 +130,8 @@
intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR);
if (passkey == BluetoothDevice.ERROR) {
Log.e(TAG, "Invalid Confirmation Passkey received, not showing any dialog");
+ mDevice.setPairingConfirmation(false);
+ finish();
return;
}
mPairingKey = String.format(Locale.US, "%06d", passkey);
@@ -146,6 +149,7 @@
intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR);
if (pairingKey == BluetoothDevice.ERROR) {
Log.e(TAG, "Invalid Confirmation Passkey or PIN received, not showing any dialog");
+ finish();
return;
}
if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) {
@@ -158,6 +162,8 @@
default:
Log.e(TAG, "Incorrect pairing type received, not showing any dialog");
+ finish();
+ return;
}
/*
diff --git a/src/com/android/settings/dashboard/SuggestionFeatureProvider.java b/src/com/android/settings/dashboard/SuggestionFeatureProvider.java
new file mode 100644
index 0000000..4b331fa
--- /dev/null
+++ b/src/com/android/settings/dashboard/SuggestionFeatureProvider.java
@@ -0,0 +1,30 @@
+/*
+ * 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.dashboard;
+
+import android.content.Context;
+
+/** Interface should be implemented if you have added new suggestions */
+public interface SuggestionFeatureProvider {
+
+ /** Return true if className is the name of a class of one of your newly added suggestion. */
+ boolean isPresent(String className);
+
+ /** Return true if the suggestion has already been completed and does not need to be shown */
+ boolean isSuggestionCompleted(Context context);
+
+}
\ No newline at end of file
diff --git a/src/com/android/settings/dashboard/SuggestionFeatureProviderImpl.java b/src/com/android/settings/dashboard/SuggestionFeatureProviderImpl.java
new file mode 100644
index 0000000..1b1db89
--- /dev/null
+++ b/src/com/android/settings/dashboard/SuggestionFeatureProviderImpl.java
@@ -0,0 +1,33 @@
+/*
+ * 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.dashboard;
+
+import android.content.Context;
+
+public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider {
+
+ @Override
+ public boolean isPresent(String className) {
+ return false;
+ }
+
+ @Override
+ public boolean isSuggestionCompleted(Context context) {
+ return false;
+ }
+
+}
diff --git a/src/com/android/settings/dashboard/SuggestionsChecks.java b/src/com/android/settings/dashboard/SuggestionsChecks.java
index b816a79..02fbe55 100644
--- a/src/com/android/settings/dashboard/SuggestionsChecks.java
+++ b/src/com/android/settings/dashboard/SuggestionsChecks.java
@@ -36,6 +36,7 @@
import com.android.settings.Settings.WifiCallingSuggestionActivity;
import com.android.settings.Settings.ZenModeAutomationSuggestionActivity;
import com.android.settings.WallpaperSuggestionActivity;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.drawer.Tile;
import java.util.Collection;
@@ -66,6 +67,13 @@
} else if (className.equals(FingerprintEnrollSuggestionActivity.class.getName())) {
return isDeviceSecured() || !isFingerprintEnabled();
}
+
+ SuggestionFeatureProvider provider =
+ FeatureFactory.getFactory(mContext).getSuggestionFeatureProvider();
+ if (provider != null && provider.isPresent(className)) {
+ return provider.isSuggestionCompleted(mContext);
+ }
+
return false;
}
diff --git a/src/com/android/settings/deviceinfo/StorageSettings.java b/src/com/android/settings/deviceinfo/StorageSettings.java
index 7757efc..1cba34a 100644
--- a/src/com/android/settings/deviceinfo/StorageSettings.java
+++ b/src/com/android/settings/deviceinfo/StorageSettings.java
@@ -53,6 +53,8 @@
import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw;
import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.deviceinfo.PrivateStorageInfo;
+import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
import com.android.settingslib.drawer.SettingsDrawerActivity;
import java.io.File;
@@ -167,7 +169,8 @@
for (VolumeInfo vol : volumes) {
if (vol.getType() == VolumeInfo.TYPE_PRIVATE) {
- final long volumeTotalBytes = getTotalSize(vol);
+ final long volumeTotalBytes = PrivateStorageInfo.getTotalSize(vol,
+ sTotalInternalStorage);
final int color = COLOR_PRIVATE[privateCount++ % COLOR_PRIVATE.length];
mInternalCategory.addPreference(
new StorageVolumePreference(context, vol, color, volumeTotalBytes));
@@ -276,7 +279,8 @@
if (vol.getType() == VolumeInfo.TYPE_PRIVATE) {
final Bundle args = new Bundle();
args.putString(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
- PrivateVolumeSettings.setVolumeSize(args, getTotalSize(vol));
+ PrivateVolumeSettings.setVolumeSize(args, PrivateStorageInfo.getTotalSize(vol,
+ sTotalInternalStorage));
startFragment(this, PrivateVolumeSettings.class.getCanonicalName(),
-1, 0, args);
return true;
@@ -506,47 +510,15 @@
private void updateSummary() {
// TODO: Register listener.
final StorageManager storageManager = mContext.getSystemService(StorageManager.class);
- if (sTotalInternalStorage <= 0) {
- sTotalInternalStorage = storageManager.getPrimaryStorageSize();
- }
- final List<VolumeInfo> volumes = storageManager.getVolumes();
- long privateFreeBytes = 0;
- long privateTotalBytes = 0;
- for (VolumeInfo info : volumes) {
- final File path = info.getPath();
- if (info.getType() != VolumeInfo.TYPE_PRIVATE || path == null) {
- continue;
- }
- privateTotalBytes += getTotalSize(info);
- privateFreeBytes += path.getFreeSpace();
- }
- long privateUsedBytes = privateTotalBytes - privateFreeBytes;
+ PrivateStorageInfo info = PrivateStorageInfo.getPrivateStorageInfo(
+ new StorageManagerVolumeProvider(storageManager));
+ long privateUsedBytes = info.totalBytes - info.freeBytes;
mLoader.setSummary(this, mContext.getString(R.string.storage_summary,
Formatter.formatFileSize(mContext, privateUsedBytes),
- Formatter.formatFileSize(mContext, privateTotalBytes)));
+ Formatter.formatFileSize(mContext, info.totalBytes)));
}
}
- private static long getTotalSize(VolumeInfo info) {
- // Device could have more than one primary storage, which could be located in the
- // internal flash (UUID_PRIVATE_INTERNAL) or in an external disk.
- // If it's internal, try to get its total size from StorageManager first
- // (sTotalInternalStorage), since that size is more precise because it accounts for
- // the system partition.
- if (info.getType() == VolumeInfo.TYPE_PRIVATE
- && Objects.equals(info.getFsUuid(), StorageManager.UUID_PRIVATE_INTERNAL)
- && sTotalInternalStorage > 0) {
- return sTotalInternalStorage;
- } else {
- final File path = info.getPath();
- if (path == null) {
- // Should not happen, caller should have checked.
- Log.e(TAG, "info's path is null on getTotalSize(): " + info);
- return 0;
- }
- return path.getTotalSpace();
- }
- }
public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
= new SummaryLoader.SummaryProviderFactory() {
diff --git a/src/com/android/settings/fuelgauge/PowerUsageBase.java b/src/com/android/settings/fuelgauge/PowerUsageBase.java
index 269249a..1af9df1 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageBase.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageBase.java
@@ -25,6 +25,7 @@
import android.os.Handler;
import android.os.Message;
import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -39,7 +40,8 @@
public abstract class PowerUsageBase extends SettingsPreferenceFragment {
// +1 to allow ordering for PowerUsageSummary.
- private static final int MENU_STATS_REFRESH = Menu.FIRST + 1;
+ @VisibleForTesting
+ static final int MENU_STATS_REFRESH = Menu.FIRST + 1;
protected BatteryStatsHelper mStatsHelper;
protected UserManager mUm;
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
new file mode 100644
index 0000000..25743d1
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge;
+
+import android.content.Intent;
+
+/**
+ * Feature Provider used in power usage
+ */
+public interface PowerUsageFeatureProvider {
+
+ /**
+ * Check whether additional battery info feature is enabled.
+ */
+ boolean isAdditionalBatteryInfoEnabled();
+
+ /**
+ * Gets an {@link Intent} to show additional battery info.
+ */
+ Intent getAdditionalBatteryInfoIntent();
+}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 443b480..be0a7cc 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -26,6 +26,7 @@
import android.os.Message;
import android.os.Process;
import android.os.UserHandle;
+import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.text.TextUtils;
@@ -43,6 +44,7 @@
import com.android.settings.SettingsActivity;
import com.android.settings.applications.ManageApplications;
import com.android.settings.dashboard.SummaryLoader;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.BatteryInfo;
import java.util.ArrayList;
@@ -67,7 +69,9 @@
private static final int MENU_STATS_TYPE = Menu.FIRST;
private static final int MENU_HIGH_POWER_APPS = Menu.FIRST + 3;
- private static final int MENU_HELP = Menu.FIRST + 4;
+ @VisibleForTesting
+ static final int MENU_ADDITIONAL_BATTERY_INFO = Menu.FIRST + 4;
+ private static final int MENU_HELP = Menu.FIRST + 5;
private BatteryHistoryPreference mHistPref;
private PreferenceGroup mAppListGroup;
@@ -130,12 +134,20 @@
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (DEBUG) {
- menu.add(0, MENU_STATS_TYPE, 0, R.string.menu_stats_total)
+ menu.add(Menu.NONE, MENU_STATS_TYPE, Menu.NONE, R.string.menu_stats_total)
.setIcon(com.android.internal.R.drawable.ic_menu_info_details)
.setAlphabeticShortcut('t');
}
- menu.add(0, MENU_HIGH_POWER_APPS, 0, R.string.high_power_apps);
+ menu.add(Menu.NONE, MENU_HIGH_POWER_APPS, Menu.NONE, R.string.high_power_apps);
+
+ PowerUsageFeatureProvider powerUsageFeatureProvider =
+ FeatureFactory.getFactory(getContext()).getPowerUsageFeatureProvider(getContext());
+ if (powerUsageFeatureProvider != null &&
+ powerUsageFeatureProvider.isAdditionalBatteryInfoEnabled()) {
+ menu.add(Menu.NONE, MENU_ADDITIONAL_BATTERY_INFO,
+ Menu.NONE, R.string.additional_battery_info);
+ }
super.onCreateOptionsMenu(menu, inflater);
}
@@ -163,6 +175,11 @@
sa.startPreferencePanel(ManageApplications.class.getName(), args,
R.string.high_power_apps, null, null, 0);
return true;
+ case MENU_ADDITIONAL_BATTERY_INFO:
+ startActivity(FeatureFactory.getFactory(getContext())
+ .getPowerUsageFeatureProvider(getContext())
+ .getAdditionalBatteryInfoIntent());
+ return true;
default:
return super.onOptionsItemSelected(item);
}
diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java
index 0e637a7..c7dbfdd 100644
--- a/src/com/android/settings/notification/NotificationSettingsBase.java
+++ b/src/com/android/settings/notification/NotificationSettingsBase.java
@@ -155,7 +155,7 @@
}
protected void setupImportancePrefs(boolean notBlockable, boolean notSilenceable,
- int importance, boolean banned) {
+ int importance, boolean banned) {
if (mShowSlider && !notSilenceable) {
setVisible(mBlock, false);
setVisible(mSilent, false);
@@ -176,10 +176,11 @@
});
} else {
setVisible(mImportance, false);
- if (notBlockable) {
+ // Hide controls that are not settable, unless they are already switched on.
+ final boolean blocked = (importance == Ranking.IMPORTANCE_NONE || banned);
+ if (notBlockable && !blocked) {
setVisible(mBlock, false);
} else {
- boolean blocked = importance == Ranking.IMPORTANCE_NONE || banned;
mBlock.setChecked(blocked);
mBlock.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
@@ -193,10 +194,11 @@
}
});
}
- if (notSilenceable) {
+ final boolean silenced = (importance == Ranking.IMPORTANCE_LOW);
+ if (notSilenceable && !silenced) {
setVisible(mSilent, false);
} else {
- mSilent.setChecked(importance == Ranking.IMPORTANCE_LOW);
+ mSilent.setChecked(silenced);
mSilent.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java
index 1bffc2b..277642d 100644
--- a/src/com/android/settings/overlay/FeatureFactory.java
+++ b/src/com/android/settings/overlay/FeatureFactory.java
@@ -21,6 +21,8 @@
import android.util.Log;
import com.android.settings.R;
+import com.android.settings.dashboard.SuggestionFeatureProvider;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
/**
* Abstract class for creating feature controllers. Allows OEM implementations to define their own
@@ -59,8 +61,14 @@
return sFactory;
}
+ public abstract SuggestionFeatureProvider getSuggestionFeatureProvider();
+
public abstract SupportFeatureProvider getSupportFeatureProvider(Context context);
+ public abstract PowerUsageFeatureProvider getPowerUsageFeatureProvider(Context context);
+
+ public abstract SurveyFeatureProvider getSurveyFeatureProvider(Context context);
+
public static final class FactoryNotFoundException extends RuntimeException {
public FactoryNotFoundException(Throwable throwable) {
super("Unable to create factory. Did you misconfigure Proguard?", throwable);
diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java
index ce561f3..a31ce72 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.java
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -17,15 +17,40 @@
package com.android.settings.overlay;
import android.content.Context;
+import android.support.annotation.Keep;
+import com.android.settings.dashboard.SuggestionFeatureProvider;
+import com.android.settings.dashboard.SuggestionFeatureProviderImpl;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
/**
* {@link FeatureFactory} implementation for AOSP Settings.
*/
-public final class FeatureFactoryImpl extends FeatureFactory {
+@Keep
+public class FeatureFactoryImpl extends FeatureFactory {
+
+ private SuggestionFeatureProvider mSuggestionFeatureProvider;
@Override
public SupportFeatureProvider getSupportFeatureProvider(Context context) {
return null;
}
+ @Override
+ public PowerUsageFeatureProvider getPowerUsageFeatureProvider(Context context) {
+ return null;
+ }
+
+ @Override
+ public SurveyFeatureProvider getSurveyFeatureProvider(Context context) {
+ return null;
+ }
+
+ @Override
+ public SuggestionFeatureProvider getSuggestionFeatureProvider() {
+ if (mSuggestionFeatureProvider == null) {
+ mSuggestionFeatureProvider = new SuggestionFeatureProviderImpl();
+ }
+ return mSuggestionFeatureProvider;
+ }
+
}
diff --git a/src/com/android/settings/overlay/SurveyFeatureProvider.java b/src/com/android/settings/overlay/SurveyFeatureProvider.java
new file mode 100644
index 0000000..416a602
--- /dev/null
+++ b/src/com/android/settings/overlay/SurveyFeatureProvider.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.overlay;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.support.annotation.Nullable;
+import android.support.v4.content.LocalBroadcastManager;
+
+/**
+ * An interface for classes wishing to provide the ability to serve surveys to implement.
+ */
+public interface SurveyFeatureProvider {
+
+ /**
+ * Downloads a survey asynchronously to shared preferences to be served at a later date.
+ *
+ * @param activity A valid context.
+ * @param surveyId A unique Id representing a survey to download.
+ * @param data a text blob to be attached to the survey results.
+ */
+ void downloadSurvey(Activity activity, String surveyId, @Nullable String data);
+
+ /**
+ * Shows a previously downloaded survey/prompt if possible in the activity provided.
+ *
+ * @param activity The host activity to show the survey in.
+ * @param surveyId A unique Id representing a survey to download.
+ * @return A boolean indicating if a survey was shown or not.
+ */
+ boolean showSurveyIfAvailable(Activity activity, String surveyId);
+
+ /**
+ * A helper method to get the surveyId. Implementers should create a mapping of
+ * keys to surveyIds and provide them via this function.
+ *
+ * @param context A valid context.
+ * @param simpleKey The simple name of the key to get the surveyId for.
+ * @return The unique Id as a string or null on error.
+ */
+ String getSurveyId(Context context, String simpleKey);
+
+ /**
+ * Removes the survey for {@code siteId} if it expired, then returns the expiration date (as a
+ * unix timestamp) for the remaining survey should it exist and be ready to show. Returns -1 if
+ * no valid survey exists after removing the potentially expired one.
+ *
+ * @param context the calling context.
+ * @param surveyId the site ID.
+ * @return the unix timestamp for the available survey for the given {@coe siteId} or -1 if
+ * there is none available.
+ */
+ long getSurveyExpirationDate(Context context, String surveyId);
+
+ /**
+ * Registers an activity to show surveys/prompts as soon as they are downloaded. The receiver
+ * should be unregistered prior to destroying the activity to avoid undefined behavior by
+ * calling {@link #unregisterReceiver(Activity, BroadcastReceiver)}.
+ * @param activity The activity that should show surveys once they are downloaded.
+ * @return the broadcast receiver listening for survey downloads. Must be unregistered before
+ * leaving the activity.
+ */
+ BroadcastReceiver createAndRegisterReceiver(Activity activity);
+
+ /**
+ * Unregisters the broadcast receiver for this activity. Should only be called once per activity
+ * after a call to {@link #createAndRegisterReceiver(Activity)}.
+ * @param activity The activity that was used to register the BroadcastReceiver.
+ */
+ static void unregisterReceiver(Activity activity, BroadcastReceiver receiver) {
+ if (activity == null) {
+ throw new IllegalStateException("Cannot unregister receiver if activity is null");
+ }
+
+ LocalBroadcastManager.getInstance(activity).unregisterReceiver(receiver);
+ }
+}
diff --git a/src/com/android/settings/password/FingerprintManagerWrapper.java b/src/com/android/settings/password/FingerprintManagerWrapper.java
new file mode 100644
index 0000000..b00f786
--- /dev/null
+++ b/src/com/android/settings/password/FingerprintManagerWrapper.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.password;
+
+import android.annotation.NonNull;
+import android.hardware.fingerprint.FingerprintManager;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Wrapper of {@link FingerprintManager}. Workaround for roboelectic testing. See
+ * {@link IFingerprintManager} for details.
+ */
+public class FingerprintManagerWrapper implements IFingerprintManager {
+ private @NonNull FingerprintManager mFingerprintManager;
+
+ public FingerprintManagerWrapper(@NonNull FingerprintManager fingerprintManager) {
+ Preconditions.checkNotNull(fingerprintManager);
+ mFingerprintManager = fingerprintManager;
+ }
+
+ public boolean isHardwareDetected() {
+ return mFingerprintManager.isHardwareDetected();
+ }
+
+ public boolean hasEnrolledFingerprints(int userId) {
+ return mFingerprintManager.hasEnrolledFingerprints(userId);
+ }
+
+ public long preEnroll() {
+ return mFingerprintManager.preEnroll();
+ }
+}
diff --git a/src/com/android/settings/password/IFingerprintManager.java b/src/com/android/settings/password/IFingerprintManager.java
new file mode 100644
index 0000000..15a9242
--- /dev/null
+++ b/src/com/android/settings/password/IFingerprintManager.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.password;
+
+/**
+ * This is the workaround to allow us test {@link SetNewPasswordController} which uses a new hidden
+ * API {@link android.hardware.fingerprint.FingerprintManager#hasEnrolledFingerprints(int)} that
+ * roboelectric does not support yet. Having roboelectic to support latest platform API is tracked
+ * in b/30995831.
+ */
+public interface IFingerprintManager {
+ boolean isHardwareDetected();
+
+ boolean hasEnrolledFingerprints(int userId);
+
+ long preEnroll();
+}
diff --git a/src/com/android/settings/password/SetNewPasswordActivity.java b/src/com/android/settings/password/SetNewPasswordActivity.java
index 7cdf006..b06da02 100644
--- a/src/com/android/settings/password/SetNewPasswordActivity.java
+++ b/src/com/android/settings/password/SetNewPasswordActivity.java
@@ -16,13 +16,18 @@
package com.android.settings.password;
-import android.annotation.Nullable;
+import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
+import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
+
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.Intent;
import android.os.Bundle;
+import android.util.Log;
import com.android.settings.ChooseLockGeneric;
+import com.android.settings.SetupChooseLockGeneric;
+import com.android.settings.Utils;
/**
* Trampolines {@link DevicePolicyManager#ACTION_SET_NEW_PASSWORD} and
@@ -30,6 +35,7 @@
* activity for handling set new password.
*/
public class SetNewPasswordActivity extends Activity implements SetNewPasswordController.Ui {
+ private static final String TAG = "SetNewPasswordActivity";
private String mNewPasswordAction;
private SetNewPasswordController mSetNewPasswordController;
@@ -38,17 +44,22 @@
super.onCreate(savedState);
mNewPasswordAction = getIntent().getAction();
- mSetNewPasswordController = new SetNewPasswordController(this, this);
+ if (!ACTION_SET_NEW_PASSWORD.equals(mNewPasswordAction)
+ && !ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(mNewPasswordAction)) {
+ Log.e(TAG, "Unexpected action to launch this activity");
+ finish();
+ return;
+ }
+ mSetNewPasswordController = SetNewPasswordController.create(
+ this, this, getIntent(), getActivityToken());
mSetNewPasswordController.dispatchSetNewPasswordIntent();
}
@Override
- public void launchChooseLock(@Nullable Bundle chooseLockFingerprintExtras) {
+ public void launchChooseLock(Bundle chooseLockFingerprintExtras) {
Intent intent = new Intent(this, ChooseLockGeneric.class)
.setAction(mNewPasswordAction);
- if (chooseLockFingerprintExtras != null) {
- intent.putExtras(chooseLockFingerprintExtras);
- }
+ intent.putExtras(chooseLockFingerprintExtras);
startActivity(intent);
finish();
}
diff --git a/src/com/android/settings/password/SetNewPasswordController.java b/src/com/android/settings/password/SetNewPasswordController.java
index 470723b..b2b20d9 100644
--- a/src/com/android/settings/password/SetNewPasswordController.java
+++ b/src/com/android/settings/password/SetNewPasswordController.java
@@ -16,20 +16,27 @@
package com.android.settings.password;
+import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
-import android.os.UserHandle;
+import android.os.IBinder;
+import android.os.UserManager;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.LockPatternUtils;
import com.android.settings.ChooseLockGeneric;
import com.android.settings.ChooseLockSettingsHelper;
+import com.android.settings.Utils;
/**
* Business logic for {@link SetNewPasswordActivity}.
@@ -42,31 +49,54 @@
interface Ui {
/** Starts the {@link ChooseLockGeneric} activity with the given extras. */
- void launchChooseLock(@Nullable Bundle chooseLockFingerprintExtras);
+ void launchChooseLock(Bundle chooseLockFingerprintExtras);
}
- private final int mCurrentUserId;
+ /**
+ * Which user is setting new password.
+ */
+ private final int mTargetUserId;
private final PackageManager mPackageManager;
- @Nullable private final FingerprintManager mFingerprintManager;
+ @Nullable private final IFingerprintManager mFingerprintManager;
private final DevicePolicyManager mDevicePolicyManager;
private final Ui mUi;
- public SetNewPasswordController(Context context, Ui ui) {
- this(context.getUserId(),
+ public static SetNewPasswordController create(Context context, Ui ui, Intent intent,
+ IBinder activityToken) {
+ // Trying to figure out which user is setting new password. If it is
+ // ACTION_SET_NEW_PARENT_PROFILE_PASSWORD or the calling user is not allowed to set
+ // separate profile challenge, it is the current user to set new password. Otherwise,
+ // it is the user who starts this activity setting new password.
+ int userId = ActivityManager.getCurrentUser();
+ if (ACTION_SET_NEW_PASSWORD.equals(intent.getAction())) {
+ final int callingUserId = Utils.getSecureTargetUser(activityToken,
+ UserManager.get(context), null, intent.getExtras()).getIdentifier();
+ final LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
+ if (lockPatternUtils.isSeparateProfileChallengeAllowed(callingUserId)) {
+ userId = callingUserId;
+ }
+ }
+ // Create a wrapper of FingerprintManager for testing, see IFingerPrintManager for details.
+ final FingerprintManager fingerprintManager =
+ (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
+ final IFingerprintManager fingerprintManagerWrapper =
+ fingerprintManager == null
+ ? null
+ : new FingerprintManagerWrapper(fingerprintManager);
+ return new SetNewPasswordController(userId,
context.getPackageManager(),
- (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE),
- (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE),
- ui);
+ fingerprintManagerWrapper,
+ (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE), ui);
}
@VisibleForTesting
SetNewPasswordController(
- int currentUserId,
+ int targetUserId,
PackageManager packageManager,
- FingerprintManager fingerprintManager,
+ IFingerprintManager fingerprintManager,
DevicePolicyManager devicePolicyManager,
Ui ui) {
- mCurrentUserId = currentUserId;
+ mTargetUserId = targetUserId;
mPackageManager = checkNotNull(packageManager);
mFingerprintManager = fingerprintManager;
mDevicePolicyManager = checkNotNull(devicePolicyManager);
@@ -77,38 +107,38 @@
* Dispatches the set new password intent to the correct activity that handles it.
*/
public void dispatchSetNewPasswordIntent() {
+ final Bundle extras;
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
&& mFingerprintManager != null
&& mFingerprintManager.isHardwareDetected()
- && !mFingerprintManager.hasEnrolledFingerprints()
+ && !mFingerprintManager.hasEnrolledFingerprints(mTargetUserId)
&& !isFingerprintDisabledByAdmin()) {
- mUi.launchChooseLock(getFingerprintChooseLockExtras());
+ extras = getFingerprintChooseLockExtras();
} else {
- mUi.launchChooseLock(null);
+ extras = new Bundle();
}
+ // No matter we show fingerprint options or not, we should tell the next activity which
+ // user is setting new password.
+ extras.putInt(Intent.EXTRA_USER_ID, mTargetUserId);
+ mUi.launchChooseLock(extras);
}
private Bundle getFingerprintChooseLockExtras() {
Bundle chooseLockExtras = new Bundle();
- if (mFingerprintManager != null) {
- long challenge = mFingerprintManager.preEnroll();
- chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
- chooseLockExtras.putBoolean(
- ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
- chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true);
- chooseLockExtras.putLong(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);
- chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true);
- if (mCurrentUserId != UserHandle.USER_NULL) {
- chooseLockExtras.putInt(Intent.EXTRA_USER_ID, mCurrentUserId);
- }
- }
+ long challenge = mFingerprintManager.preEnroll();
+ chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
+ PASSWORD_QUALITY_SOMETHING);
+ chooseLockExtras.putBoolean(
+ ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
+ chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true);
+ chooseLockExtras.putLong(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);
+ chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true);
return chooseLockExtras;
}
private boolean isFingerprintDisabledByAdmin() {
- int disabledFeatures = mDevicePolicyManager.getKeyguardDisabledFeatures(
- null, mCurrentUserId);
- return (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) != 0;
+ int disabledFeatures =
+ mDevicePolicyManager.getKeyguardDisabledFeatures(null, mTargetUserId);
+ return (disabledFeatures & KEYGUARD_DISABLE_FINGERPRINT) != 0;
}
}
diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java
index f064050..15be224 100644
--- a/src/com/android/settings/wifi/WifiEnabler.java
+++ b/src/com/android/settings/wifi/WifiEnabler.java
@@ -226,8 +226,13 @@
if (mayDisableTethering(isChecked)) {
mWifiManager.setWifiApEnabled(null, false);
}
- MetricsLogger.action(mContext,
- isChecked ? MetricsEvent.ACTION_WIFI_ON : MetricsEvent.ACTION_WIFI_OFF);
+ if (isChecked) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_WIFI_ON);
+ } else {
+ // Log if user was connected at the time of switching off.
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_WIFI_OFF,
+ mConnected.get());
+ }
if (!mWifiManager.setWifiEnabled(isChecked)) {
// Error
mSwitchBar.setEnabled(true);
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 7007d19..1d07f6c 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -481,12 +481,13 @@
}
switch (item.getItemId()) {
case MENU_ID_CONNECT: {
- if (mSelectedAccessPoint.isSaved()) {
- connect(mSelectedAccessPoint.getConfig());
+ boolean isSavedNetwork = mSelectedAccessPoint.isSaved();
+ if (isSavedNetwork) {
+ connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
} else if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
/** Bypass dialog for unsecured networks */
mSelectedAccessPoint.generateOpenNetworkConfig();
- connect(mSelectedAccessPoint.getConfig());
+ connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
} else {
showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT);
}
@@ -519,7 +520,7 @@
if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE &&
!mSelectedAccessPoint.isSaved() && !mSelectedAccessPoint.isActive()) {
mSelectedAccessPoint.generateOpenNetworkConfig();
- connect(mSelectedAccessPoint.getConfig());
+ connect(mSelectedAccessPoint.getConfig(), false /* isSavedNetwork */);
} else if (mSelectedAccessPoint.isSaved()) {
showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_VIEW);
} else {
@@ -813,14 +814,14 @@
if (config == null) {
if (mSelectedAccessPoint != null
&& mSelectedAccessPoint.isSaved()) {
- connect(mSelectedAccessPoint.getConfig());
+ connect(mSelectedAccessPoint.getConfig(), true /* isSavedNetwork */);
}
} else if (configController.getMode() == WifiConfigUiBase.MODE_MODIFY) {
mWifiManager.save(config, mSaveListener);
} else {
mWifiManager.save(config, mSaveListener);
if (mSelectedAccessPoint != null) { // Not an "Add network"
- connect(config);
+ connect(config, false /* isSavedNetwork */);
}
}
@@ -850,13 +851,17 @@
changeNextButtonState(false);
}
- protected void connect(final WifiConfiguration config) {
- MetricsLogger.action(getActivity(), MetricsEvent.ACTION_WIFI_CONNECT);
+ protected void connect(final WifiConfiguration config, boolean isSavedNetwork) {
+ // Log subtype if configuration is a saved network.
+ MetricsLogger.action(getActivity(), MetricsEvent.ACTION_WIFI_CONNECT,
+ isSavedNetwork);
mWifiManager.connect(config, mConnectListener);
}
- protected void connect(final int networkId) {
- MetricsLogger.action(getActivity(), MetricsEvent.ACTION_WIFI_CONNECT);
+ protected void connect(final int networkId, boolean isSavedNetwork) {
+ // Log subtype if configuration is a saved network.
+ MetricsLogger.action(getActivity(), MetricsEvent.ACTION_WIFI_CONNECT,
+ isSavedNetwork);
mWifiManager.connect(networkId, mConnectListener);
}
diff --git a/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java b/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java
index 2f35478..68f28ee 100644
--- a/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java
+++ b/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java
@@ -130,17 +130,17 @@
}
@Override
- protected void connect(final WifiConfiguration config) {
+ protected void connect(final WifiConfiguration config, boolean isSavedNetwork) {
WifiSetupActivity activity = (WifiSetupActivity) getActivity();
activity.networkSelected();
- super.connect(config);
+ super.connect(config, isSavedNetwork);
}
@Override
- protected void connect(final int networkId) {
+ protected void connect(final int networkId, boolean isSavedNetwork) {
WifiSetupActivity activity = (WifiSetupActivity) getActivity();
activity.networkSelected();
- super.connect(networkId);
+ super.connect(networkId, isSavedNetwork);
}
@Override