diff options
Diffstat (limited to 'src/com/android/settings')
32 files changed, 1062 insertions, 208 deletions
diff --git a/src/com/android/settings/AppHeader.java b/src/com/android/settings/AppHeader.java index 5cd126a..cd76e80 100644 --- a/src/com/android/settings/AppHeader.java +++ b/src/com/android/settings/AppHeader.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.settings; import android.app.Activity; diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java index bfb328d..aeb3827 100644 --- a/src/com/android/settings/ChooseLockGeneric.java +++ b/src/com/android/settings/ChooseLockGeneric.java @@ -35,6 +35,8 @@ import android.os.UserManager; import android.preference.Preference; import android.preference.PreferenceScreen; import android.security.KeyStore; +import android.service.fingerprint.FingerprintManager; +import android.service.fingerprint.FingerprintManagerReceiver; import android.util.EventLog; import android.util.Log; import android.util.MutableBoolean; @@ -72,26 +74,24 @@ public class ChooseLockGeneric extends SettingsActivity { } public static class ChooseLockGenericFragment extends SettingsPreferenceFragment { + private static final String TAG = "ChooseLockGenericFragment"; private static final int MIN_PASSWORD_LENGTH = 4; - private static final String KEY_UNLOCK_BACKUP_INFO = "unlock_backup_info"; private static final String KEY_UNLOCK_SET_OFF = "unlock_set_off"; private static final String KEY_UNLOCK_SET_NONE = "unlock_set_none"; private static final String KEY_UNLOCK_SET_PIN = "unlock_set_pin"; private static final String KEY_UNLOCK_SET_PASSWORD = "unlock_set_password"; private static final String KEY_UNLOCK_SET_PATTERN = "unlock_set_pattern"; - private static final int CONFIRM_EXISTING_REQUEST = 100; - private static final int ENABLE_ENCRYPTION_REQUEST = 102; - private static final int CHOOSE_LOCK_REQUEST = 103; private static final String PASSWORD_CONFIRMED = "password_confirmed"; - private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation"; - private static final String TAG = "ChooseLockGenericFragment"; public static final String MINIMUM_QUALITY_KEY = "minimum_quality"; + public static final String HIDE_DISABLED_PREFS = "hide_disabled_prefs"; public static final String ENCRYPT_REQUESTED_QUALITY = "encrypt_requested_quality"; public static final String ENCRYPT_REQUESTED_DISABLED = "encrypt_requested_disabled"; public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog"; - private static final boolean ALWAY_SHOW_TUTORIAL = true; + private static final int CONFIRM_EXISTING_REQUEST = 100; + private static final int ENABLE_ENCRYPTION_REQUEST = 101; + private static final int CHOOSE_LOCK_REQUEST = 102; private ChooseLockSettingsHelper mChooseLockSettingsHelper; private DevicePolicyManager mDPM; @@ -102,11 +102,14 @@ public class ChooseLockGeneric extends SettingsActivity { private boolean mEncryptionRequestDisabled; private boolean mRequirePassword; private LockPatternUtils mLockPatternUtils; + private FingerprintManager mFingerprintManager; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mFingerprintManager = + (FingerprintManager) getActivity().getSystemService(Context.FINGERPRINT_SERVICE); mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); mKeyStore = KeyStore.getInstance(); mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity()); @@ -219,12 +222,14 @@ public class ChooseLockGeneric extends SettingsActivity { // If caller didn't specify password quality, show UI and allow the user to choose. quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1); quality = upgradeQuality(quality); + final boolean hideDisabledPrefs = intent.getBooleanExtra( + HIDE_DISABLED_PREFS, false); final PreferenceScreen prefScreen = getPreferenceScreen(); if (prefScreen != null) { prefScreen.removeAll(); } addPreferencesFromResource(R.xml.security_settings_picker); - disableUnusablePreferences(quality); + disableUnusablePreferences(quality, hideDisabledPrefs); updatePreferenceSummaryIfNeeded(); } else { updateUnlockMethodAndFinish(quality, false); @@ -261,9 +266,11 @@ public class ChooseLockGeneric extends SettingsActivity { * implementation is in disableUnusablePreferenceImpl. * * @param quality the requested quality. + * @param hideDisabledPrefs if false preferences show why they were disabled; otherwise + * they're not shown at all. */ - protected void disableUnusablePreferences(final int quality) { - disableUnusablePreferencesImpl(quality, false /* hideDisabled */); + protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) { + disableUnusablePreferencesImpl(quality, hideDisabledPrefs); } /*** @@ -391,13 +398,36 @@ public class ChooseLockGeneric extends SettingsActivity { } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { mChooseLockSettingsHelper.utils().clearLock(); mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled); + removeAllFingerprintTemplates(); getActivity().setResult(Activity.RESULT_OK); finish(); } else { + removeAllFingerprintTemplates(); finish(); } } + // TODO: This is only required because we used to enforce clients have a listener, + // which is no longer required in the new API. Remove when that happens. + FingerprintManagerReceiver mReceiver = new FingerprintManagerReceiver() { + public void onRemoved(int fingerprintId) { + Log.v(TAG, "onRemoved(id=" + fingerprintId + ")"); + } + }; + + private void removeAllFingerprintTemplates() { + if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) { + mFingerprintManager.startListening(mReceiver); + mFingerprintManager.remove(0 /* all fingerprint templates */); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + mFingerprintManager.stopListening(); + } + @Override protected int getHelpResource() { return R.string.help_url_choose_lockscreen; diff --git a/src/com/android/settings/ChooseLockPassword.java b/src/com/android/settings/ChooseLockPassword.java index b85daa7..0a0aebd 100644 --- a/src/com/android/settings/ChooseLockPassword.java +++ b/src/com/android/settings/ChooseLockPassword.java @@ -432,7 +432,6 @@ public class ChooseLockPassword extends SettingsActivity { } else if (mUiStage == Stage.NeedToConfirm) { if (mFirstPin.equals(pin)) { boolean wasSecureBefore = mLockPatternUtils.isSecure(); - mLockPatternUtils.clearLock(); final boolean required = getActivity().getIntent().getBooleanExtra( EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true); mLockPatternUtils.setCredentialRequiredToDecrypt(required); diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java index cba0879..3ab1d23 100644 --- a/src/com/android/settings/DataUsageSummary.java +++ b/src/com/android/settings/DataUsageSummary.java @@ -62,6 +62,7 @@ import android.content.Intent; import android.content.Loader; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.content.res.Resources; import android.content.res.TypedArray; @@ -120,6 +121,7 @@ import android.widget.ProgressBar; import android.widget.Spinner; import android.widget.Switch; import android.widget.TabHost; +import android.widget.Toast; import android.widget.TabHost.OnTabChangeListener; import android.widget.TabHost.TabContentFactory; import android.widget.TabHost.TabSpec; @@ -142,7 +144,6 @@ import com.android.settings.sim.SimSettings; import com.android.settings.widget.ChartDataUsageView; import com.android.settings.widget.ChartDataUsageView.DataUsageChartListener; import com.android.settings.widget.ChartNetworkSeriesView; - import com.google.android.collect.Lists; import libcore.util.Objects; @@ -191,6 +192,8 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable "data_usage_disable_mobile_limit"; private static final String DATA_USAGE_CYCLE_KEY = "data_usage_cycle"; + public static final String EXTRA_SHOW_APP_IMMEDIATE_PKG = "showAppImmediatePkg"; + private static final int LOADER_CHART_DATA = 2; private static final int LOADER_SUMMARY = 3; @@ -281,6 +284,9 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable private UidDetailProvider mUidDetailProvider; + // Indicates request to show app immediately rather than list. + private String mShowAppImmediatePkg; + /** * Local cache of data enabled for subId, used to work around delays. */ @@ -332,6 +338,13 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable mShowEthernet = true; } + mUidDetailProvider = new UidDetailProvider(context); + + Bundle arguments = getArguments(); + if (arguments != null) { + mShowAppImmediatePkg = arguments.getString(EXTRA_SHOW_APP_IMMEDIATE_PKG); + } + setHasOptionsMenu(true); } @@ -342,7 +355,6 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable final Context context = inflater.getContext(); final View view = inflater.inflate(R.layout.data_usage_summary, container, false); - mUidDetailProvider = new UidDetailProvider(context); mTabHost = (TabHost) view.findViewById(android.R.id.tabhost); mTabsContainer = (ViewGroup) view.findViewById(R.id.tabs_container); @@ -448,9 +460,34 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable mListView.setOnItemClickListener(mListListener); mListView.setAdapter(mAdapter); + showRequestedAppIfNeeded(); + return view; } + private void showRequestedAppIfNeeded() { + if (mShowAppImmediatePkg == null) { + return; + } + try { + int uid = getActivity().getPackageManager().getPackageUid(mShowAppImmediatePkg, + UserHandle.myUserId()); + AppItem app = new AppItem(uid); + app.addUid(uid); + + final UidDetail detail = mUidDetailProvider.getUidDetail(app.key, true); + // When we are going straight to an app then we are coming from App Info and want + // a header at the top. + AppHeader.createAppHeader(getActivity(), detail.icon, detail.label, null); + AppDetailsFragment.show(DataUsageSummary.this, app, detail.label, false); + } catch (NameNotFoundException e) { + Log.w(TAG, "Could not find " + mShowAppImmediatePkg, e); + Toast.makeText(getActivity(), getString(R.string.unknown_app), Toast.LENGTH_LONG) + .show(); + getActivity().finish(); + } + } + @Override public void onViewStateRestored(Bundle savedInstanceState) { super.onViewStateRestored(savedInstanceState); @@ -639,6 +676,10 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable * only be assigned after initial layout is complete. */ private void ensureLayoutTransitions() { + if (mShowAppImmediatePkg != null) { + // If we are skipping right to showing an app, we don't care about transitions. + return; + } // skip when already setup if (mChart.getLayoutTransition() != null) return; @@ -1887,6 +1928,11 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable private static final String EXTRA_APP = "app"; public static void show(DataUsageSummary parent, AppItem app, CharSequence label) { + show(parent, app, label, true); + } + + public static void show(DataUsageSummary parent, AppItem app, CharSequence label, + boolean addToBack) { if (!parent.isAdded()) return; final Bundle args = new Bundle(); @@ -1897,7 +1943,9 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable fragment.setTargetFragment(parent, 0); final FragmentTransaction ft = parent.getFragmentManager().beginTransaction(); ft.add(fragment, TAG_APP_DETAILS); - ft.addToBackStack(TAG_APP_DETAILS); + if (addToBack) { + ft.addToBackStack(TAG_APP_DETAILS); + } ft.setBreadCrumbTitle( parent.getResources().getString(R.string.data_usage_app_summary_title)); ft.commitAllowingStateLoss(); diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java index a4002ab..b5b33f4 100644 --- a/src/com/android/settings/DevelopmentSettings.java +++ b/src/com/android/settings/DevelopmentSettings.java @@ -728,7 +728,7 @@ public class DevelopmentSettings extends SettingsPreferenceFragment return !SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals(""); } - private boolean showEnableMultiWindowPreference() { + private static boolean showEnableMultiWindowPreference() { return !"user".equals(Build.TYPE); } @@ -1781,6 +1781,9 @@ public class DevelopmentSettings extends SettingsPreferenceFragment if (!showEnableOemUnlockPreference()) { keys.add(ENABLE_OEM_UNLOCK); } + if (!showEnableMultiWindowPreference()) { + keys.add(ENABLE_MULTI_WINDOW_KEY); + } return keys; } }; diff --git a/src/com/android/settings/FingerprintEnroll.java b/src/com/android/settings/FingerprintEnroll.java index 24f479e..865fcdc 100644 --- a/src/com/android/settings/FingerprintEnroll.java +++ b/src/com/android/settings/FingerprintEnroll.java @@ -21,10 +21,12 @@ import android.animation.Animator.AnimatorListener; import android.animation.ObjectAnimator; import android.app.Activity; import android.app.Fragment; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.graphics.drawable.AnimationDrawable; +import android.graphics.drawable.Drawable; import android.media.AudioAttributes; import android.os.Bundle; import android.os.PowerManager; @@ -80,11 +82,13 @@ public class FingerprintEnroll extends SettingsActivity { } public static class FingerprintEnrollFragment extends Fragment implements View.OnClickListener { + private static final int PROGRESS_BAR_MAX = 10000; private static final String TAG = "FingerprintEnroll"; private static final boolean DEBUG = true; private static final int CONFIRM_REQUEST = 101; private static final int CHOOSE_LOCK_GENERIC_REQUEST = 102; private static final long ENROLL_TIMEOUT = 300*1000; + private static final int FINISH_DELAY = 250; private PowerManager mPowerManager; private FingerprintManager mFingerprintManager; @@ -98,6 +102,15 @@ public class FingerprintEnroll extends SettingsActivity { private ProgressBar mProgressBar; private ImageView mFingerprintAnimator; private ObjectAnimator mProgressAnim; + + // Give the user a chance to see progress completed before jumping to the next stage. + Runnable mDelayedFinishRunnable = new Runnable() { + @Override + public void run() { + updateStage(Stage.EnrollingFinish); + } + }; + private final AnimatorListener mProgressAnimationListener = new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @@ -107,8 +120,8 @@ public class FingerprintEnroll extends SettingsActivity { @Override public void onAnimationEnd(Animator animation) { - if (mProgressBar.getProgress() >= 100) { - updateStage(Stage.EnrollingFinish); + if (mProgressBar.getProgress() >= PROGRESS_BAR_MAX) { + mContentView.postDelayed(mDelayedFinishRunnable, FINISH_DELAY); } } @@ -133,12 +146,17 @@ public class FingerprintEnroll extends SettingsActivity { R.id.fingerprint_enroll_button_next }; - private static final int VIEWS_ENROLL_START[] = { + private static final int VIEWS_ENROLL_FIND_SENSOR[] = { R.id.fingerprint_sensor_location, - R.id.fingerprint_progress_bar + R.id.fingerprint_enroll_button_area, + R.id.fingerprint_enroll_button_next }; - private static final int VIEWS_ENROLL_PROGRESS[] = { + private static final int VIEWS_ENROLL_START[] = { + R.id.fingerprint_animator, + }; + + private static final int VIEWS_ENROLL_REPEAT[] = { R.id.fingerprint_animator, R.id.fingerprint_progress_bar }; @@ -149,17 +167,21 @@ public class FingerprintEnroll extends SettingsActivity { R.id.fingerprint_enroll_button_add, R.id.fingerprint_enroll_button_next }; + private static final boolean ALWAYS_SHOW_FIND_SCREEN = true; - enum Stage { - EnrollingOnboarding(R.string.security_settings_fingerprint_enroll_onboard_title, + private enum Stage { + EnrollingOnboard(R.string.security_settings_fingerprint_enroll_onboard_title, R.string.security_settings_fingerprint_enroll_onboard_message, VIEWS_ENROLL_ONBOARD), + EnrollingFindSensor(R.string.security_settings_fingerprint_enroll_find_sensor_title, + R.string.security_settings_fingerprint_enroll_find_sensor_message, + VIEWS_ENROLL_FIND_SENSOR), EnrollingStart(R.string.security_settings_fingerprint_enroll_start_title, R.string.security_settings_fingerprint_enroll_start_message, VIEWS_ENROLL_START), EnrollingRepeat(R.string.security_settings_fingerprint_enroll_repeat_title, R.string.security_settings_fingerprint_enroll_repeat_message, - VIEWS_ENROLL_PROGRESS), + VIEWS_ENROLL_REPEAT), EnrollingFinish(R.string.security_settings_fingerprint_enroll_finish_title, R.string.security_settings_fingerprint_enroll_finish_message, VIEWS_ENROLL_FINISH); @@ -196,22 +218,29 @@ public class FingerprintEnroll extends SettingsActivity { } private void startFingerprintAnimator() { - AnimationDrawable drawable = (AnimationDrawable) mFingerprintAnimator.getDrawable(); - drawable.start(); + final Drawable d = mFingerprintAnimator.getDrawable(); + if (d instanceof AnimationDrawable) { + ((AnimationDrawable) d).start(); + } } private void stopFingerprintAnimator() { - AnimationDrawable drawable = (AnimationDrawable) mFingerprintAnimator.getDrawable(); - drawable.stop(); - drawable.setLevel(0); + final Drawable d = mFingerprintAnimator.getDrawable(); + if (d instanceof AnimationDrawable) { + final AnimationDrawable drawable = (AnimationDrawable) d; + drawable.stop(); + drawable.setLevel(0); + } } private void onStageChanged(Stage stage) { // Update state switch (stage) { - case EnrollingOnboarding: + case EnrollingOnboard: // pass through + case EnrollingFindSensor: mEnrollmentSteps = -1; mEnrolling = false; + mFingerprintManager.stopListening(); break; case EnrollingStart: @@ -288,7 +317,7 @@ public class FingerprintEnroll extends SettingsActivity { } if (remaining >= 0) { int progress = Math.max(0, mEnrollmentSteps + 1 - remaining); - updateProgress(100*progress / (mEnrollmentSteps + 1)); + updateProgress(PROGRESS_BAR_MAX * progress / (mEnrollmentSteps + 1)); // Treat fingerprint like a touch event mPowerManager.userActivity(SystemClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_OTHER, @@ -371,7 +400,7 @@ public class FingerprintEnroll extends SettingsActivity { if (requestCode == CHOOSE_LOCK_GENERIC_REQUEST) { if (resultCode == RESULT_FINISHED) { // The lock pin/pattern/password was set. Start enrolling! - updateStage(Stage.EnrollingStart); + updateStage(Stage.EnrollingFindSensor); } } } @@ -401,7 +430,10 @@ public class FingerprintEnroll extends SettingsActivity { LockPatternUtils utils = new LockPatternUtils(activity); if (!utils.isSecure()) { // Device doesn't have any security. Set that up first. - updateStage(Stage.EnrollingOnboarding); + updateStage(Stage.EnrollingOnboard); + } else if (ALWAYS_SHOW_FIND_SCREEN + || mFingerprintManager.getEnrolledFingerprints().size() == 0) { + updateStage(Stage.EnrollingFindSensor); } else { updateStage(Stage.EnrollingStart); } @@ -415,8 +447,10 @@ public class FingerprintEnroll extends SettingsActivity { updateStage(Stage.EnrollingStart); break; case R.id.fingerprint_enroll_button_next: - if (mStage == Stage.EnrollingOnboarding) { + if (mStage == Stage.EnrollingOnboard) { launchChooseLock(); + } else if (mStage == Stage.EnrollingFindSensor) { + updateStage(Stage.EnrollingStart); } else if (mStage == Stage.EnrollingFinish) { getActivity().finish(); } else { @@ -429,6 +463,9 @@ public class FingerprintEnroll extends SettingsActivity { private void launchChooseLock() { Intent intent = new Intent(); intent.setClassName("com.android.settings", ChooseLockGeneric.class.getName()); + intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, + DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); + intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST); } } diff --git a/src/com/android/settings/FingerprintSettings.java b/src/com/android/settings/FingerprintSettings.java new file mode 100644 index 0000000..f91fcfa --- /dev/null +++ b/src/com/android/settings/FingerprintSettings.java @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2015 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; + + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceChangeListener; +import android.preference.PreferenceGroup; +import android.preference.PreferenceScreen; +import android.service.fingerprint.FingerprintManager; +import android.service.fingerprint.FingerprintManagerReceiver; +import android.service.fingerprint.FingerprintManager.FingerprintItem; +import android.util.Log; +import android.widget.EditText; + +import com.android.settings.search.Indexable; + +import java.util.HashMap; +import java.util.List; + +/** + * Settings screen for fingerprints + */ +public class FingerprintSettings extends SettingsActivity { + + @Override + public Intent getIntent() { + Intent modIntent = new Intent(super.getIntent()); + modIntent.putExtra(EXTRA_SHOW_FRAGMENT, FingerprintSettingsFragment.class.getName()); + return modIntent; + } + + @Override + protected boolean isValidFragment(String fragmentName) { + if (FingerprintSettingsFragment.class.getName().equals(fragmentName)) return true; + return false; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + CharSequence msg = getText(R.string.security_settings_fingerprint_preference_title); + setTitle(msg); + } + + public static class FingerprintSettingsFragment extends SettingsPreferenceFragment + implements OnPreferenceChangeListener, Indexable { + private static final String TAG = "FingerprintSettings"; + private static final String KEY_FINGERPRINT_ITEM = "key_fingerprint_item"; + private static final String KEY_USAGE_CATEGORY = "fingerprint_usage_category"; + private static final String KEY_FINGERPRINT_ADD = "key_fingerprint_add"; + private static final String KEY_MANAGE_CATEGORY = "fingerprint_manage_category"; + private static final String KEY_FINGERPRINT_ENABLE_KEYGUARD_TOGGLE = + "fingerprint_enable_keyguard_toggle"; + + private static final int ADD_FINGERPRINT_REQUEST = 10; + + private static final boolean ENABLE_USAGE_CATEGORY = false; + + private FingerprintManager mFingerprintManager; + private HashMap<Preference, FingerprintItem> mFingerprintMap + = new HashMap<Preference, FingerprintManager.FingerprintItem>(); + private EditText mDialogTextField; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mFingerprintManager = (FingerprintManager) getActivity().getSystemService( + Context.FINGERPRINT_SERVICE); + mFingerprintManager.startListening(new FingerprintManagerReceiver() { + @Override + public void onRemoved(int fingerprintId) { + Log.v(TAG, "Fingerprint template " + fingerprintId + " removed"); + // TODO: this is a bit wasteful; just remove the fingerprint id item + createPreferenceHierarchy(); + } + @Override + public void onProcessed(int fingerprintId) { + Log.v(TAG, "Fingerprint " + fingerprintId + " detected"); + } + }); + } + + /** + * Important! + * + * Don't forget to update the SecuritySearchIndexProvider if you are doing any change in the + * logic or adding/removing preferences here. + */ + private PreferenceScreen createPreferenceHierarchy() { + PreferenceScreen root = getPreferenceScreen(); + if (root != null) { + root.removeAll(); + } + addPreferencesFromResource(R.xml.security_settings_fingerprint); + root = getPreferenceScreen(); + + // Fingerprint items + PreferenceGroup manageCategory = (PreferenceGroup) root.findPreference( + KEY_MANAGE_CATEGORY); + if (manageCategory != null) { + addFingerprintItemPreferences(manageCategory); + } + + // Fingerprint usage options + PreferenceGroup usageCategory = (PreferenceGroup) root.findPreference( + KEY_USAGE_CATEGORY); + if (usageCategory != null) { + Preference toggle = root.findPreference(KEY_FINGERPRINT_ENABLE_KEYGUARD_TOGGLE); + toggle.setOnPreferenceChangeListener(this); + if (!ENABLE_USAGE_CATEGORY) { + root.removePreference(usageCategory); + } else { + toggle.setOnPreferenceChangeListener(this); + } + } + + return root; + } + + private void addFingerprintItemPreferences(PreferenceGroup manageFingerprintCategory) { + manageFingerprintCategory.removeAll(); + List<FingerprintItem> items = mFingerprintManager.getEnrolledFingerprints(); + final int fingerprintCount = items.size(); + mFingerprintMap.clear(); + for (int i = 0; i < fingerprintCount; i++) { + Preference pref = new Preference(manageFingerprintCategory.getContext()); + pref.setKey(KEY_FINGERPRINT_ITEM); + FingerprintItem item = items.get(i); + pref.setTitle(item.name); + manageFingerprintCategory.addPreference(pref); + pref.setOnPreferenceChangeListener(this); + mFingerprintMap.put(pref, item); + } + Preference addPreference = new Preference(manageFingerprintCategory.getContext()); + addPreference.setKey(KEY_FINGERPRINT_ADD); + addPreference.setTitle(R.string.fingerprint_add_title); + manageFingerprintCategory.addPreference(addPreference); + addPreference.setOnPreferenceChangeListener(this); + } + + @Override + public void onResume() { + super.onResume(); + // Make sure we reload the preference hierarchy since fingerprints may be added, + // deleted or renamed. + createPreferenceHierarchy(); + } + + @Override + public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference pref) { + final String key = pref.getKey(); + if (KEY_FINGERPRINT_ADD.equals(key)) { + Intent intent = new Intent(); + intent.setClassName("com.android.settings", FingerprintEnroll.class.getName()); + startActivityForResult(intent, ADD_FINGERPRINT_REQUEST); + } else if (KEY_FINGERPRINT_ITEM.equals(key)) { + final FingerprintItem item = mFingerprintMap.get(pref); + showRenameDeleteDialog(item.name, pref, item.id); + return super.onPreferenceTreeClick(preferenceScreen, pref); + } + return true; + } + + private void showRenameDeleteDialog(final CharSequence name, Preference pref, + final int fpId) { + final Activity activity = getActivity(); + AlertDialog dialog = new AlertDialog.Builder(activity) + .setView(R.layout.fingerprint_rename_dialog) + .setPositiveButton(R.string.security_settings_fingerprint_enroll_dialog_ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String newName = mDialogTextField.getText().toString(); + if (!newName.equals(name)) { + Log.v(TAG, "Would rename " + name + " to " + newName); + mFingerprintManager.rename(fpId, newName); + } + dialog.dismiss(); + } + }) + .setNegativeButton(R.string.security_settings_fingerprint_enroll_dialog_delete, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Log.v(TAG, "Removing fpId " + fpId); + mFingerprintManager.remove(fpId); + dialog.dismiss(); + } + }) + .create(); + dialog.show(); + mDialogTextField = (EditText) dialog.findViewById(R.id.fingerprint_rename_field); + mDialogTextField.setText(name); + mDialogTextField.selectAll(); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object value) { + boolean result = true; + final String key = preference.getKey(); + if (KEY_FINGERPRINT_ENABLE_KEYGUARD_TOGGLE.equals(key)) { + // TODO + } else { + Log.v(TAG, "Unknown key:" + key); + } + return result; + } + + @Override + protected int getHelpResource() { + return R.string.help_url_security; + } + } +} diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index 95826e4..053e7f0 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -67,8 +67,9 @@ import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; */ public class SecuritySettings extends SettingsPreferenceFragment implements OnPreferenceChangeListener, DialogInterface.OnClickListener, Indexable { + + private static final String TAG = "SecuritySettings"; private static final String TRUST_AGENT_CLICK_INTENT = "trust_agent_click_intent"; - static final String TAG = "SecuritySettings"; private static final Intent TRUST_AGENT_INTENT = new Intent(TrustAgentService.SERVICE_INTERFACE); @@ -81,6 +82,7 @@ public class SecuritySettings extends SettingsPreferenceFragment private static final String KEY_OWNER_INFO_SETTINGS = "owner_info_settings"; private static final String KEY_ADVANCED_SECURITY = "advanced_security"; private static final String KEY_MANAGE_TRUST_AGENTS = "manage_trust_agents"; + private static final String KEY_FINGERPRINT_SETTINGS = "fingerprint_settings"; private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123; private static final int CHANGE_TRUST_AGENT_SETTINGS = 126; @@ -337,21 +339,22 @@ public class SecuritySettings extends SettingsPreferenceFragment return; } Preference fingerprintPreference = new Preference(securityCategory.getContext()); - fingerprintPreference.setKey(KEY_TRUST_AGENT); + fingerprintPreference.setKey(KEY_FINGERPRINT_SETTINGS); fingerprintPreference.setTitle(R.string.security_settings_fingerprint_preference_title); Intent intent = new Intent(); List<FingerprintItem> items = fpm.getEnrolledFingerprints(); int fingerprintCount = items.size(); + final String clazz; if (fingerprintCount > 0) { fingerprintPreference.setSummary(getResources().getQuantityString( R.plurals.security_settings_fingerprint_preference_summary, fingerprintCount, fingerprintCount)); - // TODO: Launch fingerprintSettings instead... - intent.setClassName("com.android.settings", FingerprintEnroll.class.getName()); + clazz = FingerprintSettings.class.getName(); } else { - // No fingerprints registered, launch directly into fingerprint enrollment wizard - intent.setClassName("com.android.settings", FingerprintEnroll.class.getName()); + // No fingerprints registered, launch directly into enrollment wizard + clazz = FingerprintEnroll.class.getName(); } + intent.setClassName("com.android.settings", clazz); fingerprintPreference.setIntent(intent); securityCategory.addPreference(fingerprintPreference); } diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index d41c387..b16fe81 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -100,5 +100,6 @@ public class Settings extends SettingsActivity { public static class TopLevelSettings extends SettingsActivity { /* empty */ } public static class ApnSettingsActivity extends SettingsActivity { /* empty */ } + public static class WifiCallingSettingsActivity extends SettingsActivity { /* empty */ } } diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 8eacc32..db080c6 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -112,6 +112,7 @@ import com.android.settings.wifi.AdvancedWifiSettings; import com.android.settings.wifi.SavedAccessPointsWifiSettings; import com.android.settings.wifi.WifiSettings; import com.android.settings.wifi.p2p.WifiP2pSettings; +import com.android.settings.WifiCallingSettings; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -301,7 +302,8 @@ public class SettingsActivity extends Activity NotificationAppList.class.getName(), AppNotificationSettings.class.getName(), OtherSoundSettings.class.getName(), - ApnSettings.class.getName() + ApnSettings.class.getName(), + WifiCallingSettings.class.getName() }; diff --git a/src/com/android/settings/SetupChooseLockGeneric.java b/src/com/android/settings/SetupChooseLockGeneric.java index 94ff8d6..f29f08a 100644 --- a/src/com/android/settings/SetupChooseLockGeneric.java +++ b/src/com/android/settings/SetupChooseLockGeneric.java @@ -110,7 +110,7 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric * @param quality the requested quality. */ @Override - protected void disableUnusablePreferences(final int quality) { + protected void disableUnusablePreferences(final int quality, boolean hideDisabled) { // At this part of the flow, the user has already indicated they want to add a pin, // pattern or password, so don't show "None" or "Slide". We disable them here and set // the HIDE_DISABLED flag to true to hide them. This only happens for setup wizard. diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 5a2618e..16037c5 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -67,6 +67,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; +import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -133,6 +134,8 @@ public final class Utils { private static final int SECONDS_PER_HOUR = 60 * 60; private static final int SECONDS_PER_DAY = 24 * 60 * 60; + private static SparseArray<Bitmap> sDarkDefaultUserBitmapCache = new SparseArray<Bitmap>(); + /** * Finds a matching activity for a preference's intent. If a matching * activity is not found, it will remove the preference. @@ -1083,4 +1086,22 @@ public final class Utils { return (sm.getStorageBytesUntilLow(context.getFilesDir()) < 0); } + + /** + * Returns a default user icon (as a {@link Bitmap}) for the given user. + * + * Note that for guest users, you should pass in {@code UserHandle.USER_NULL}. + * @param userId the user id or {@code UserHandle.USER_NULL} for a non-user specific icon + */ + public static Bitmap getDefaultUserIconAsBitmap(int userId) { + Bitmap bitmap = null; + // Try finding the corresponding bitmap in the dark bitmap cache + bitmap = sDarkDefaultUserBitmapCache.get(userId); + if (bitmap == null) { + bitmap = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(userId, false)); + // Save it to cache + sDarkDefaultUserBitmapCache.put(userId, bitmap); + } + return bitmap; + } } diff --git a/src/com/android/settings/WifiCallingSettings.java b/src/com/android/settings/WifiCallingSettings.java new file mode 100644 index 0000000..dacdc7b --- /dev/null +++ b/src/com/android/settings/WifiCallingSettings.java @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2015 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; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.preference.ListPreference; +import android.preference.Preference; +import android.preference.SwitchPreference; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyManager; +import android.util.Log; +import android.widget.Switch; + +import com.android.ims.ImsConfig; +import com.android.ims.ImsManager; +import com.android.internal.telephony.imsphone.ImsPhone; +import com.android.settings.widget.SwitchBar; + +/** + * "Wi-Fi Calling settings" screen. This preference screen lets you + * enable/disable Wi-Fi Calling, change mode, enable/disable + * handover while on roaming. + */ +public class WifiCallingSettings extends SettingsPreferenceFragment + implements SwitchBar.OnSwitchChangeListener, + Preference.OnPreferenceChangeListener { + + private static final String TAG = "WifiCallingSettings"; + + //String keys for preference lookup + private static final String BUTTON_WFC_MODE = "wifi_calling_mode"; + private static final String BUTTON_WFC_ROAM = "wifi_calling_roam"; + + //UI objects + private SwitchBar mSwitchBar; + private Switch mSwitch; + private ListPreference mButtonWfcMode; + private SwitchPreference mButtonWfcRoam; + + private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + /* + * Enable/disable controls when in/out of a call and depending on + * TTY mode and TTY support over VoLTE. + * @see android.telephony.PhoneStateListener#onCallStateChanged(int, + * java.lang.String) + */ + @Override + public void onCallStateChanged(int state, String incomingNumber) { + final SettingsActivity activity = (SettingsActivity) getActivity(); + boolean isNonTtyOrTtyOnVolteEnabled = ImsManager + .isNonTtyOrTtyOnVolteEnabled(activity); + final SwitchBar switchBar = activity.getSwitchBar(); + boolean isWfcEnabled = switchBar.getSwitch().isChecked() + && isNonTtyOrTtyOnVolteEnabled; + + switchBar.setEnabled((state == TelephonyManager.CALL_STATE_IDLE) + && isNonTtyOrTtyOnVolteEnabled); + + Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE); + int wfcMode = ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY; + if (pref != null) { + pref.setEnabled(isWfcEnabled + && (state == TelephonyManager.CALL_STATE_IDLE)); + ListPreference prefWfcMode = (ListPreference) pref; + wfcMode = Integer.valueOf(prefWfcMode.getValue()).intValue(); + } + pref = getPreferenceScreen().findPreference(BUTTON_WFC_ROAM); + if (pref != null) { + pref.setEnabled(isWfcEnabled + && (wfcMode != ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY) + && (state == TelephonyManager.CALL_STATE_IDLE)); + } + } + }; + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + final SettingsActivity activity = (SettingsActivity) getActivity(); + + mSwitchBar = activity.getSwitchBar(); + mSwitch = mSwitchBar.getSwitch(); + mSwitchBar.show(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mSwitchBar.hide(); + } + + private void showAlert(Intent intent) { + Context context = getActivity(); + + CharSequence title = intent.getCharSequenceExtra(ImsPhone.EXTRA_KEY_ALERT_TITLE); + CharSequence message = intent.getCharSequenceExtra(ImsPhone.EXTRA_KEY_ALERT_MESSAGE); + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setMessage(message) + .setTitle(title) + .setIcon(android.R.drawable.stat_sys_warning) + .setPositiveButton(android.R.string.ok, null); + AlertDialog dialog = builder.create(); + dialog.show(); + } + + private IntentFilter mIntentFilter; + + private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(ImsPhone.REGISTRATION_ERROR)) { + // If this fragment is active then we are immediately + // showing alert on screen. There is no need to add + // notification in this case. + // + // In order to communicate to ImsPhone that it should + // not show notification, we are changing result code here. + setResultCode(Activity.RESULT_CANCELED); + + showAlert(intent); + } + } + }; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + addPreferencesFromResource(R.xml.wifi_calling_settings); + + mButtonWfcMode = (ListPreference) findPreference(BUTTON_WFC_MODE); + mButtonWfcMode.setOnPreferenceChangeListener(this); + + mButtonWfcRoam = (SwitchPreference) findPreference(BUTTON_WFC_ROAM); + mButtonWfcRoam.setOnPreferenceChangeListener(this); + + mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(ImsPhone.REGISTRATION_ERROR); + } + + @Override + public void onResume() { + super.onResume(); + + final Context context = getActivity(); + + if (ImsManager.isWfcEnabledByPlatform(context)) { + TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); + tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); + + mSwitchBar.addOnSwitchChangeListener(this); + } + + // NOTE: Buttons will be enabled/disabled in mPhoneStateListener + boolean wfcEnabled = ImsManager.isWfcEnabledByUser(context) + && ImsManager.isNonTtyOrTtyOnVolteEnabled(context); + mSwitch.setChecked(wfcEnabled); + + int wfcMode = ImsManager.getWfcMode(context); + mButtonWfcMode.setValue(Integer.toString(wfcMode)); + mButtonWfcMode.setSummary(getWfcModeSummary(context, wfcMode)); + + mButtonWfcRoam.setChecked(wfcEnabled + && (wfcMode != ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY) + && ImsManager.isWfcRoamingEnabledByUser(context)); + + context.registerReceiver(mIntentReceiver, mIntentFilter); + + Intent intent = getActivity().getIntent(); + if (intent.getBooleanExtra(ImsPhone.EXTRA_KEY_ALERT_SHOW, false)) { + showAlert(intent); + } + } + + @Override + public void onPause() { + super.onPause(); + + final Context context = getActivity(); + + if (ImsManager.isWfcEnabledByPlatform(getActivity())) { + TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); + tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); + + mSwitchBar.removeOnSwitchChangeListener(this); + } + + context.unregisterReceiver(mIntentReceiver); + } + + /** + * Listens to the state change of the switch. + */ + @Override + public void onSwitchChanged(Switch switchView, boolean isChecked) { + final Context context = getActivity(); + + ImsManager.setWfcSetting(context, isChecked); + + int wfcMode = ImsManager.getWfcMode(context); + mButtonWfcMode.setSummary(getWfcModeSummary(context, wfcMode)); + mButtonWfcMode.setEnabled(isChecked); + boolean wfcHandoffEnabled = (wfcMode != ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY); + mButtonWfcRoam.setEnabled(isChecked && wfcHandoffEnabled); + mButtonWfcRoam.setChecked(isChecked && wfcHandoffEnabled + && ImsManager.isWfcRoamingEnabledByUser(context)); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + final Context context = getActivity(); + if (preference == mButtonWfcMode) { + mButtonWfcMode.setValue((String) newValue); + int buttonMode = Integer.valueOf((String) newValue); + int currentMode = ImsManager.getWfcMode(context); + if (buttonMode != currentMode) { + ImsManager.setWfcMode(context, buttonMode); + mButtonWfcMode.setSummary(getWfcModeSummary(context, buttonMode)); + } + boolean wfcHandoffEnabled = + (buttonMode != ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY); + mButtonWfcRoam.setEnabled(wfcHandoffEnabled); + mButtonWfcRoam.setChecked(wfcHandoffEnabled && + ImsManager.isWfcRoamingEnabledByUser(context)); + } else if (preference == mButtonWfcRoam) { + SwitchPreference wfcRoamPref = (SwitchPreference) preference; + wfcRoamPref.setChecked(!wfcRoamPref.isChecked()); + ImsManager.setWfcRoamingSetting(context, wfcRoamPref.isChecked()); + } + return true; + } + + static int getWfcModeSummary(Context context, int wfcMode) { + int resId = R.string.wifi_calling_off_summary; + if (ImsManager.isWfcEnabledByUser(context)) { + switch (wfcMode) { + case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY: + resId = R.string.wfc_mode_wifi_only_summary; + break; + case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED: + resId = R.string.wfc_mode_cellular_preferred_summary; + break; + case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED: + resId = R.string.wfc_mode_wifi_preferred_summary; + break; + default: + Log.e(TAG, "Unexpected WFC mode value: " + wfcMode); + } + } + return resId; + } +} diff --git a/src/com/android/settings/WirelessSettings.java b/src/com/android/settings/WirelessSettings.java index 0bd6b29..71cd322 100644 --- a/src/com/android/settings/WirelessSettings.java +++ b/src/com/android/settings/WirelessSettings.java @@ -47,6 +47,8 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; +import com.android.ims.ImsConfig; +import com.android.ims.ImsManager; import com.android.internal.telephony.SmsApplication; import com.android.internal.telephony.SmsApplication.SmsApplicationData; import com.android.internal.telephony.TelephonyIntents; @@ -54,6 +56,7 @@ import com.android.internal.telephony.TelephonyProperties; import com.android.settings.nfc.NfcEnabler; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; +import com.android.settings.WifiCallingSettings; import java.util.ArrayList; import java.util.Arrays; @@ -76,6 +79,7 @@ public class WirelessSettings extends SettingsPreferenceFragment private static final String KEY_SMS_APPLICATION = "sms_application"; private static final String KEY_TOGGLE_NSD = "toggle_nsd"; //network service discovery private static final String KEY_CELL_BROADCAST_SETTINGS = "cell_broadcast_settings"; + private static final String KEY_WFC_SETTINGS = "wifi_calling_settings"; public static final String EXIT_ECM_RESULT = "exit_ecm_result"; public static final int REQUEST_CODE_EXIT_ECM = 1; @@ -95,6 +99,7 @@ public class WirelessSettings extends SettingsPreferenceFragment private static final String SAVED_MANAGE_MOBILE_PLAN_MSG = "mManageMobilePlanMessage"; private AppListPreference mSmsApplicationPreference; + private PreferenceScreen mButtonWfc; /** * Invoked on each preference click in this hierarchy, overrides @@ -272,6 +277,12 @@ public class WirelessSettings extends SettingsPreferenceFragment initSmsApplicationSetting(); } + if (ImsManager.isWfcEnabledByPlatform(activity)) { + mButtonWfc = (PreferenceScreen) findPreference(KEY_WFC_SETTINGS); + } else { + removePreference(KEY_WFC_SETTINGS); + } + // Remove NSD checkbox by default getPreferenceScreen().removePreference(nsd); //mNsdEnabler = new NsdEnabler(activity, nsd); @@ -413,6 +424,12 @@ public class WirelessSettings extends SettingsPreferenceFragment if (mNsdEnabler != null) { mNsdEnabler.resume(); } + + final Context context = getActivity(); + if (ImsManager.isWfcEnabledByPlatform(context)) { + mButtonWfc.setSummary(WifiCallingSettings.getWfcModeSummary( + context, ImsManager.getWfcMode(context))); + } } @Override diff --git a/src/com/android/settings/applications/AppInfoBase.java b/src/com/android/settings/applications/AppInfoBase.java index 2203a21..28f2925 100644 --- a/src/com/android/settings/applications/AppInfoBase.java +++ b/src/com/android/settings/applications/AppInfoBase.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.settings.applications; import android.app.Activity; @@ -29,6 +30,7 @@ import android.hardware.usb.IUsbManager; import android.os.Bundle; import android.os.IBinder; import android.os.ServiceManager; +import android.os.UserHandle; import android.os.UserManager; import android.preference.PreferenceFragment; import android.util.Log; @@ -52,6 +54,7 @@ public abstract class AppInfoBase extends PreferenceFragment private ApplicationsState.Session mSession; protected ApplicationsState.AppEntry mAppEntry; protected PackageInfo mPackageInfo; + protected int mUserId; protected String mPackageName; protected IUsbManager mUsbManager; @@ -114,7 +117,8 @@ public abstract class AppInfoBase extends PreferenceFragment mPackageName = intent.getData().getSchemeSpecificPart(); } } - mAppEntry = mState.getEntry(mPackageName); + mUserId = UserHandle.myUserId(); + mAppEntry = mState.getEntry(mPackageName, mUserId); if (mAppEntry != null) { // Get application info again to refresh changed properties of application try { @@ -151,15 +155,29 @@ public abstract class AppInfoBase extends PreferenceFragment protected abstract AlertDialog createDialog(int id, int errorCode); @Override - public void onRunningStateChanged(boolean running) { } + public void onRunningStateChanged(boolean running) { + // No op. + } + @Override - public void onRebuildComplete(ArrayList<AppEntry> apps) { } + public void onRebuildComplete(ArrayList<AppEntry> apps) { + // No op. + } + @Override - public void onPackageIconChanged() { } + public void onPackageIconChanged() { + // No op. + } + @Override - public void onPackageSizeChanged(String packageName) { } + public void onPackageSizeChanged(String packageName) { + // No op. + } + @Override - public void onAllSizesComputed() { } + public void onAllSizesComputed() { + // No op. + } @Override public void onPackageListChanged() { diff --git a/src/com/android/settings/applications/AppLaunchSettings.java b/src/com/android/settings/applications/AppLaunchSettings.java index 6379102..c31d8ad 100644 --- a/src/com/android/settings/applications/AppLaunchSettings.java +++ b/src/com/android/settings/applications/AppLaunchSettings.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.settings.applications; import android.app.AlertDialog; @@ -41,7 +42,6 @@ import com.android.settings.Utils; import com.android.settings.applications.ApplicationsState.AppEntry; import java.util.ArrayList; -import java.util.Collections; import java.util.List; public class AppLaunchSettings extends AppInfoWithHeader implements OnClickListener { @@ -167,9 +167,9 @@ public class AppLaunchSettings extends AppInfoWithHeader implements OnClickListe private static boolean hasPreferredActivities(PackageManager pm, String packageName) { // Get list of preferred activities - List<ComponentName> prefActList = Collections.emptyList(); + List<ComponentName> prefActList = new ArrayList<>(); // Intent list cannot be null. so pass empty list - List<IntentFilter> intentList = Collections.emptyList(); + List<IntentFilter> intentList = new ArrayList<>(); pm.getPreferredActivities(intentList, prefActList, packageName); if (localLOGV) { Log.i(TAG, "Have " + prefActList.size() + " number of activities in preferred list"); diff --git a/src/com/android/settings/applications/AppPermissionSettings.java b/src/com/android/settings/applications/AppPermissionSettings.java index a5b4895..496faf5 100644 --- a/src/com/android/settings/applications/AppPermissionSettings.java +++ b/src/com/android/settings/applications/AppPermissionSettings.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.settings.applications; import android.app.AlertDialog; diff --git a/src/com/android/settings/applications/AppStorageSettings.java b/src/com/android/settings/applications/AppStorageSettings.java index 5ae5e8f..72fa805 100644 --- a/src/com/android/settings/applications/AppStorageSettings.java +++ b/src/com/android/settings/applications/AppStorageSettings.java @@ -45,7 +45,7 @@ import com.android.settings.applications.ApplicationsState.AppEntry; import com.android.settings.applications.ApplicationsState.Callbacks; public class AppStorageSettings extends AppInfoWithHeader implements OnClickListener, Callbacks { - private static final String TAG = "AppStorageSettings"; + private static final String TAG = AppStorageSettings.class.getSimpleName(); //internal constants used in Handler private static final int OP_SUCCESSFUL = 1; @@ -345,7 +345,7 @@ public class AppStorageSettings extends AppInfoWithHeader implements OnClickList if (result == PackageManager.MOVE_SUCCEEDED) { Log.i(TAG, "Moved resources for " + packageName); // Refresh size information again. - mState.requestSize(mAppEntry.info.packageName); + mState.requestSize(mPackageName, mUserId); } else { showDialogInner(DLG_MOVE_FAILED, result); } @@ -362,7 +362,7 @@ public class AppStorageSettings extends AppInfoWithHeader implements OnClickList mClearDataButton.setText(R.string.clear_user_data_text); if(result == OP_SUCCESSFUL) { Log.i(TAG, "Cleared user data for package : "+packageName); - mState.requestSize(mAppEntry.info.packageName); + mState.requestSize(mPackageName, mUserId); } else { mClearDataButton.setEnabled(true); } @@ -443,7 +443,7 @@ public class AppStorageSettings extends AppInfoWithHeader implements OnClickList break; case MSG_CLEAR_CACHE: // Refresh size info - mState.requestSize(mPackageName); + mState.requestSize(mPackageName, mUserId); break; case MSG_PACKAGE_MOVE: processMoveMsg(msg); diff --git a/src/com/android/settings/applications/ApplicationsState.java b/src/com/android/settings/applications/ApplicationsState.java index 9c51181..3f25d47 100644 --- a/src/com/android/settings/applications/ApplicationsState.java +++ b/src/com/android/settings/applications/ApplicationsState.java @@ -1,15 +1,18 @@ package com.android.settings.applications; +import android.app.AppGlobals; import android.app.Application; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; import android.content.pm.IPackageStatsObserver; import android.content.pm.PackageManager; import android.content.pm.PackageStats; -import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ParceledListSlice; +import android.content.pm.UserInfo; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; @@ -17,10 +20,13 @@ import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.Process; +import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; +import android.os.UserManager; import android.text.format.Formatter; import android.util.Log; +import android.util.SparseArray; import java.io.File; import java.text.Collator; @@ -140,7 +146,7 @@ public class ApplicationsState { boolean ensureIconLocked(Context context, PackageManager pm) { if (this.icon == null) { if (this.apkFile.exists()) { - this.icon = this.info.loadIcon(pm); + this.icon = getBadgedIcon(pm); return true; } else { this.mounted = false; @@ -152,12 +158,18 @@ public class ApplicationsState { // its icon. if (this.apkFile.exists()) { this.mounted = true; - this.icon = this.info.loadIcon(pm); + this.icon = getBadgedIcon(pm); return true; } } return false; } + + private Drawable getBadgedIcon(PackageManager pm) { + // Do badging ourself so that it comes from the user of the app not the current user. + return pm.getUserBadgedIcon(pm.loadUnbadgedItemIcon(info, info), + new UserHandle(UserHandle.getUserId(info.uid))); + } } public static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() { @@ -265,6 +277,8 @@ public class ApplicationsState { final Context mContext; final PackageManager mPm; + final IPackageManager mIpm; + final UserManager mUm; final int mRetrieveFlags; PackageIntentReceiver mPackageIntentReceiver; @@ -276,11 +290,14 @@ public class ApplicationsState { final ArrayList<Session> mSessions = new ArrayList<Session>(); final ArrayList<Session> mRebuildingSessions = new ArrayList<Session>(); final InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges(); - final HashMap<String, AppEntry> mEntriesMap = new HashMap<String, AppEntry>(); + // Map: userid => (Map: package name => AppEntry) + final SparseArray<HashMap<String, AppEntry>> mEntriesMap = + new SparseArray<HashMap<String, AppEntry>>(); final ArrayList<AppEntry> mAppEntries = new ArrayList<AppEntry>(); List<ApplicationInfo> mApplications = new ArrayList<ApplicationInfo>(); long mCurId = 1; String mCurComputingSizePkg; + int mCurComputingSizeUserId; boolean mSessionsChanged; // Temporary for dispatching session callbacks. Only touched by main thread. @@ -301,6 +318,11 @@ public class ApplicationsState { sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(this, sdFilter); + // Register for events related to user creation/deletion. + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_ADDED); + userFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiver(this, userFilter); } void unregisterReceiver() { mContext.unregisterReceiver(this); @@ -311,15 +333,21 @@ public class ApplicationsState { if (Intent.ACTION_PACKAGE_ADDED.equals(actionStr)) { Uri data = intent.getData(); String pkgName = data.getEncodedSchemeSpecificPart(); - addPackage(pkgName); + for (int i = 0; i < mEntriesMap.size(); i++) { + addPackage(pkgName, mEntriesMap.keyAt(i)); + } } else if (Intent.ACTION_PACKAGE_REMOVED.equals(actionStr)) { Uri data = intent.getData(); String pkgName = data.getEncodedSchemeSpecificPart(); - removePackage(pkgName); + for (int i = 0; i < mEntriesMap.size(); i++) { + removePackage(pkgName, mEntriesMap.keyAt(i)); + } } else if (Intent.ACTION_PACKAGE_CHANGED.equals(actionStr)) { Uri data = intent.getData(); String pkgName = data.getEncodedSchemeSpecificPart(); - invalidatePackage(pkgName); + for (int i = 0; i < mEntriesMap.size(); i++) { + invalidatePackage(pkgName, mEntriesMap.keyAt(i)); + } } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(actionStr) || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(actionStr)) { // When applications become available or unavailable (perhaps because @@ -336,9 +364,15 @@ public class ApplicationsState { boolean avail = Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(actionStr); if (avail) { for (String pkgName : pkgList) { - invalidatePackage(pkgName); + for (int i = 0; i < mEntriesMap.size(); i++) { + invalidatePackage(pkgName, mEntriesMap.keyAt(i)); + } } } + } else if (Intent.ACTION_USER_ADDED.equals(actionStr)) { + addUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)); + } else if (Intent.ACTION_USER_REMOVED.equals(actionStr)) { + removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)); } } } @@ -426,6 +460,11 @@ public class ApplicationsState { private ApplicationsState(Application app) { mContext = app; mPm = mContext.getPackageManager(); + mIpm = AppGlobals.getPackageManager(); + mUm = (UserManager) app.getSystemService(Context.USER_SERVICE); + for (UserHandle user : mUm.getUserProfiles()) { + mEntriesMap.put(user.getIdentifier(), new HashMap<String, AppEntry>()); + } mThread = new HandlerThread("ApplicationsState.Loader", Process.THREAD_PRIORITY_BACKGROUND); mThread.start(); @@ -630,15 +669,22 @@ public class ApplicationsState { mPackageIntentReceiver = new PackageIntentReceiver(); mPackageIntentReceiver.registerReceiver(); } - mApplications = mPm.getInstalledApplications(mRetrieveFlags); - if (mApplications == null) { - mApplications = new ArrayList<ApplicationInfo>(); + mApplications = new ArrayList<ApplicationInfo>(); + for (UserHandle user : mUm.getUserProfiles()) { + try { + ParceledListSlice<ApplicationInfo> list = + mIpm.getInstalledApplications(mRetrieveFlags, user.getIdentifier()); + mApplications.addAll(list.getList()); + } catch (RemoteException e) { + } } if (mInterestingConfigChanges.applyNewConfig(mContext.getResources())) { // If an interesting part of the configuration has changed, we // should completely reload the app entries. - mEntriesMap.clear(); + for (int i = 0; i < mEntriesMap.size(); i++) { + mEntriesMap.valueAt(i).clear(); + } mAppEntries.clear(); } else { for (int i=0; i<mAppEntries.size(); i++) { @@ -659,7 +705,8 @@ public class ApplicationsState { } mHaveDisabledApps = true; } - final AppEntry entry = mEntriesMap.get(info.packageName); + int userId = UserHandle.getUserId(info.uid); + final AppEntry entry = mEntriesMap.get(userId).get(info.packageName); if (entry != null) { entry.info = info; } @@ -683,6 +730,10 @@ public class ApplicationsState { return; } } + doPauseLocked(); + } + + void doPauseLocked() { mResumed = false; if (mPackageIntentReceiver != null) { mPackageIntentReceiver.unregisterReceiver(); @@ -690,10 +741,10 @@ public class ApplicationsState { } } - AppEntry getEntry(String packageName) { + AppEntry getEntry(String packageName, int userId) { if (DEBUG_LOCKING) Log.v(TAG, "getEntry about to acquire lock..."); synchronized (mEntriesMap) { - AppEntry entry = mEntriesMap.get(packageName); + AppEntry entry = mEntriesMap.get(userId).get(packageName); if (entry == null) { for (int i=0; i<mApplications.size(); i++) { ApplicationInfo info = mApplications.get(i); @@ -717,12 +768,12 @@ public class ApplicationsState { } } - void requestSize(String packageName) { + void requestSize(String packageName, int userId) { if (DEBUG_LOCKING) Log.v(TAG, "requestSize about to acquire lock..."); synchronized (mEntriesMap) { - AppEntry entry = mEntriesMap.get(packageName); + AppEntry entry = mEntriesMap.get(userId).get(packageName); if (entry != null) { - mPm.getPackageSizeInfo(packageName, mBackgroundHandler.mStatsObserver); + mPm.getPackageSizeInfo(packageName, userId, mBackgroundHandler.mStatsObserver); } if (DEBUG_LOCKING) Log.v(TAG, "...requestSize releasing lock"); } @@ -741,16 +792,18 @@ public class ApplicationsState { return sum; } - int indexOfApplicationInfoLocked(String pkgName) { + int indexOfApplicationInfoLocked(String pkgName, int userId) { for (int i=mApplications.size()-1; i>=0; i--) { - if (mApplications.get(i).packageName.equals(pkgName)) { + ApplicationInfo appInfo = mApplications.get(i); + if (appInfo.packageName.equals(pkgName) + && UserHandle.getUserId(appInfo.uid) == userId) { return i; } } return -1; } - void addPackage(String pkgName) { + void addPackage(String pkgName, int userId) { try { synchronized (mEntriesMap) { if (DEBUG_LOCKING) Log.v(TAG, "addPackage acquired lock"); @@ -762,12 +815,15 @@ public class ApplicationsState { if (DEBUG_LOCKING) Log.v(TAG, "addPackage release lock: not resumed"); return; } - if (indexOfApplicationInfoLocked(pkgName) >= 0) { + if (indexOfApplicationInfoLocked(pkgName, userId) >= 0) { if (DEBUG) Log.i(TAG, "Package already exists!"); if (DEBUG_LOCKING) Log.v(TAG, "addPackage release lock: already exists"); return; } - ApplicationInfo info = mPm.getApplicationInfo(pkgName, mRetrieveFlags); + ApplicationInfo info = mIpm.getApplicationInfo(pkgName, mRetrieveFlags, userId); + if (info == null) { + return; + } if (!info.enabled) { if (info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { @@ -784,20 +840,20 @@ public class ApplicationsState { } if (DEBUG_LOCKING) Log.v(TAG, "addPackage releasing lock"); } - } catch (NameNotFoundException e) { + } catch (RemoteException e) { } } - void removePackage(String pkgName) { + void removePackage(String pkgName, int userId) { synchronized (mEntriesMap) { if (DEBUG_LOCKING) Log.v(TAG, "removePackage acquired lock"); - int idx = indexOfApplicationInfoLocked(pkgName); + int idx = indexOfApplicationInfoLocked(pkgName, userId); if (DEBUG) Log.i(TAG, "removePackage: " + pkgName + " @ " + idx); if (idx >= 0) { - AppEntry entry = mEntriesMap.get(pkgName); + AppEntry entry = mEntriesMap.get(userId).get(pkgName); if (DEBUG) Log.i(TAG, "removePackage: " + entry); if (entry != null) { - mEntriesMap.remove(pkgName); + mEntriesMap.get(userId).remove(pkgName); mAppEntries.remove(entry); } ApplicationInfo info = mApplications.get(idx); @@ -819,18 +875,53 @@ public class ApplicationsState { } } - void invalidatePackage(String pkgName) { - removePackage(pkgName); - addPackage(pkgName); + void invalidatePackage(String pkgName, int userId) { + removePackage(pkgName, userId); + addPackage(pkgName, userId); } - + + void addUser(int userId) { + if (mUm.getUserProfiles().contains(new UserHandle(userId))) { + synchronized (mEntriesMap) { + mEntriesMap.put(userId, new HashMap<String, AppEntry>()); + if (mResumed) { + // If resumed, Manually pause, then cause a resume to repopulate the app list. + // This is the simplest way to reload the packages so that the new user + // is included. Otherwise the list will be repopulated on next resume. + doPauseLocked(); + doResumeIfNeededLocked(); + } + if (!mMainHandler.hasMessages(MainHandler.MSG_PACKAGE_LIST_CHANGED)) { + mMainHandler.sendEmptyMessage(MainHandler.MSG_PACKAGE_LIST_CHANGED); + } + } + } + } + + void removeUser(int userId) { + synchronized (mEntriesMap) { + HashMap<String, AppEntry> userMap = mEntriesMap.get(userId); + if (userMap != null) { + for (AppEntry appEntry : userMap.values()) { + mAppEntries.remove(appEntry); + mApplications.remove(appEntry.info); + } + mEntriesMap.remove(userId); + if (!mMainHandler.hasMessages(MainHandler.MSG_PACKAGE_LIST_CHANGED)) { + mMainHandler.sendEmptyMessage(MainHandler.MSG_PACKAGE_LIST_CHANGED); + } + } + } + } + AppEntry getEntryLocked(ApplicationInfo info) { - AppEntry entry = mEntriesMap.get(info.packageName); + int userId = UserHandle.getUserId(info.uid); + AppEntry entry = mEntriesMap.get(userId).get(info.packageName); if (DEBUG) Log.i(TAG, "Looking up entry of pkg " + info.packageName + ": " + entry); if (entry == null) { if (DEBUG) Log.i(TAG, "Creating AppEntry for " + info.packageName); entry = new AppEntry(mContext, info, mCurId++); - mEntriesMap.put(info.packageName, entry); + mEntriesMap.get(userId).put(info.packageName, entry); mAppEntries.add(entry); } else if (entry.info != info) { entry.info = info; @@ -880,7 +971,12 @@ public class ApplicationsState { boolean sizeChanged = false; synchronized (mEntriesMap) { if (DEBUG_LOCKING) Log.v(TAG, "onGetStatsCompleted acquired lock"); - AppEntry entry = mEntriesMap.get(stats.packageName); + HashMap<String, AppEntry> userMap = mEntriesMap.get(stats.userHandle); + if (userMap == null) { + // The user must have been removed. + return; + } + AppEntry entry = userMap.get(stats.packageName); if (entry != null) { synchronized (entry) { entry.sizeStale = false; @@ -922,7 +1018,8 @@ public class ApplicationsState { } } if (mCurComputingSizePkg == null - || mCurComputingSizePkg.equals(stats.packageName)) { + || (mCurComputingSizePkg.equals(stats.packageName) + && mCurComputingSizeUserId == stats.userHandle)) { mCurComputingSizePkg = null; sendEmptyMessage(MSG_LOAD_SIZES); } @@ -966,7 +1063,8 @@ public class ApplicationsState { mMainHandler.sendMessage(m); } ApplicationInfo info = mApplications.get(i); - if (mEntriesMap.get(info.packageName) == null) { + int userId = UserHandle.getUserId(info.uid); + if (mEntriesMap.get(userId).get(info.packageName) == null) { numDone++; getEntryLocked(info); } @@ -1035,7 +1133,9 @@ public class ApplicationsState { } entry.sizeLoadStart = now; mCurComputingSizePkg = entry.info.packageName; - mPm.getPackageSizeInfo(mCurComputingSizePkg, mStatsObserver); + mCurComputingSizeUserId = UserHandle.getUserId(entry.info.uid); + mPm.getPackageSizeInfo(mCurComputingSizePkg, + mCurComputingSizeUserId, mStatsObserver); } if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES releasing: now computing"); return; diff --git a/src/com/android/settings/applications/HeaderPreference.java b/src/com/android/settings/applications/HeaderPreference.java index 57fe9f3..a3d4bde 100644 --- a/src/com/android/settings/applications/HeaderPreference.java +++ b/src/com/android/settings/applications/HeaderPreference.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.settings.applications; import android.content.Context; diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java index d77d63f..7f20b32 100755 --- a/src/com/android/settings/applications/InstalledAppDetails.java +++ b/src/com/android/settings/applications/InstalledAppDetails.java @@ -19,23 +19,33 @@ package com.android.settings.applications; import android.app.Activity; import android.app.ActivityManager; import android.app.AlertDialog; +import android.app.LoaderManager.LoaderCallbacks; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.Loader; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; +import android.net.INetworkStatsService; +import android.net.INetworkStatsSession; +import android.net.NetworkTemplate; +import android.net.TrafficStats; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.UserHandle; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.provider.Settings; +import android.text.format.DateUtils; +import android.text.format.Formatter; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -44,10 +54,14 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; +import com.android.settings.DataUsageSummary; +import com.android.settings.DataUsageSummary.AppItem; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.applications.ApplicationsState.AppEntry; +import com.android.settings.net.ChartData; +import com.android.settings.net.ChartDataLoader; import com.android.settings.notification.NotificationAppList; import com.android.settings.notification.NotificationAppList.AppRow; import com.android.settings.notification.NotificationAppList.Backend; @@ -76,6 +90,8 @@ public class InstalledAppDetails extends AppInfoBase public static final int REQUEST_UNINSTALL = 0; private static final int SUB_INFO_FRAGMENT = 1; + private static final int LOADER_CHART_DATA = 2; + private static final int DLG_FORCE_STOP = DLG_BASE + 1; private static final int DLG_DISABLE = DLG_BASE + 2; private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3; @@ -109,6 +125,9 @@ public class InstalledAppDetails extends AppInfoBase // Used for updating notification preference. private final Backend mBackend = new Backend(); + private ChartData mChartData; + private INetworkStatsSession mStatsSession; + private boolean handleDisableable(Button button) { boolean disableable = false; // Try to prevent the user from bricking their phone @@ -207,6 +226,37 @@ public class InstalledAppDetails extends AppInfoBase setHasOptionsMenu(true); addPreferencesFromResource(R.xml.installed_app_details); + + INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); + try { + mStatsSession = statsService.openSession(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onResume() { + super.onResume(); + AppItem app = new AppItem(mAppEntry.info.uid); + app.addUid(mAppEntry.info.uid); + getLoaderManager().restartLoader(LOADER_CHART_DATA, + ChartDataLoader.buildArgs(NetworkTemplate.buildTemplateMobileWildcard(), app), + mDataCallbacks); + } + + @Override + public void onPause() { + getLoaderManager().destroyLoader(LOADER_CHART_DATA); + super.onPause(); + } + + @Override + public void onDestroy() { + TrafficStats.closeQuietly(mStatsSession); + + super.onDestroy(); } public void onActivityCreated(Bundle savedInstanceState) { @@ -223,8 +273,6 @@ public class InstalledAppDetails extends AppInfoBase mLaunchPreference.setOnPreferenceClickListener(this); mDataPreference = findPreference(KEY_DATA); mDataPreference.setOnPreferenceClickListener(this); - // Data isn't ready, lets just pull it for now. - getPreferenceScreen().removePreference(mDataPreference); } private void handleHeader() { @@ -384,6 +432,7 @@ public class InstalledAppDetails extends AppInfoBase mPm, context)); mNotificationPreference.setSummary(getNotificationSummary(mAppEntry, context, mBackend)); + mDataPreference.setSummary(getDataSummary()); if (!mInitialized) { // First time init: are we displaying an uninstalled app? @@ -410,6 +459,18 @@ public class InstalledAppDetails extends AppInfoBase return true; } + private CharSequence getDataSummary() { + if (mChartData != null) { + long totalBytes = mChartData.detail.getTotalBytes(); + Context context = getActivity(); + return getString(R.string.data_summary_format, + Formatter.formatFileSize(context, totalBytes), + DateUtils.formatDateTime(context, mChartData.detail.getStart(), + DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH)); + } + return getString(R.string.computing_size); + } + @Override protected AlertDialog createDialog(int id, int errorCode) { switch (id) { @@ -482,8 +543,9 @@ public class InstalledAppDetails extends AppInfoBase ActivityManager am = (ActivityManager)getActivity().getSystemService( Context.ACTIVITY_SERVICE); am.forceStopPackage(pkgName); - mState.invalidatePackage(pkgName); - ApplicationsState.AppEntry newEnt = mState.getEntry(pkgName); + int userId = UserHandle.getUserId(mAppEntry.info.uid); + mState.invalidatePackage(pkgName, userId); + ApplicationsState.AppEntry newEnt = mState.getEntry(pkgName, userId); if (newEnt != null) { mAppEntry = newEnt; } @@ -578,7 +640,13 @@ public class InstalledAppDetails extends AppInfoBase } else if (preference == mLaunchPreference) { startAppInfoFragment(AppLaunchSettings.class, mLaunchPreference.getTitle()); } else if (preference == mDataPreference) { - // Not yet. + Bundle args = new Bundle(); + args.putString(DataUsageSummary.EXTRA_SHOW_APP_IMMEDIATE_PKG, + mAppEntry.info.packageName); + + SettingsActivity sa = (SettingsActivity) getActivity(); + sa.startPreferencePanel(DataUsageSummary.class.getName(), args, -1, + getString(R.string.app_data_usage), this, SUB_INFO_FRAGMENT); } else { return false; } @@ -626,6 +694,26 @@ public class InstalledAppDetails extends AppInfoBase } } + private final LoaderCallbacks<ChartData> mDataCallbacks = new LoaderCallbacks<ChartData>() { + + @Override + public Loader<ChartData> onCreateLoader(int id, Bundle args) { + return new ChartDataLoader(getActivity(), mStatsSession, args); + } + + @Override + public void onLoadFinished(Loader<ChartData> loader, ChartData data) { + mChartData = data; + mDataPreference.setSummary(getDataSummary()); + } + + @Override + public void onLoaderReset(Loader<ChartData> loader) { + mChartData = null; + mDataPreference.setSummary(getDataSummary()); + } + }; + private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java index 45431eb..0152755 100644 --- a/src/com/android/settings/applications/ManageApplications.java +++ b/src/com/android/settings/applications/ManageApplications.java @@ -35,6 +35,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.NetworkPolicyManager; +import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; @@ -70,13 +71,12 @@ import android.widget.Spinner; import com.android.internal.app.IMediaContainerService; import com.android.internal.content.PackageHelper; import com.android.settings.R; -import com.android.settings.SettingsActivity; -import com.android.settings.UserSpinnerAdapter; import com.android.settings.Settings.RunningServicesActivity; import com.android.settings.Settings.StorageUseActivity; +import com.android.settings.UserSpinnerAdapter; +import com.android.settings.Utils; import com.android.settings.applications.ApplicationsState.AppEntry; import com.android.settings.deviceinfo.StorageMeasurement; -import com.android.settings.Utils; import java.util.ArrayList; import java.util.Comparator; @@ -135,8 +135,7 @@ interface AppClickListener { * intent. */ public class ManageApplications extends Fragment implements - AppClickListener, DialogInterface.OnClickListener, - DialogInterface.OnDismissListener, OnItemSelectedListener { + AppClickListener, DialogInterface.OnClickListener, DialogInterface.OnDismissListener { static final String TAG = "ManageApplications"; static final boolean DEBUG = false; @@ -451,6 +450,7 @@ public class ManageApplications extends Fragment implements private LayoutInflater mInflater; private String mCurrentPkgName; + private int mCurrentUid; private Menu mOptionsMenu; @@ -472,7 +472,6 @@ public class ManageApplications extends Fragment implements private View mRootView; private ViewPager mViewPager; private ViewGroup mPinnedHeader; - private UserSpinnerAdapter mProfileSpinnerAdapter; private Spinner mSpinner; private Context mContext; @@ -911,9 +910,6 @@ public class ManageApplications extends Fragment implements mTabs.add(tab); mNumTabs = mTabs.size(); - - final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - mProfileSpinnerAdapter = Utils.createUserSpinnerAdapter(um, mContext); } @@ -926,14 +922,6 @@ public class ManageApplications extends Fragment implements container, false); mContentContainer = container; mRootView = rootView; - mPinnedHeader = (ViewGroup) mRootView.findViewById(R.id.pinned_header); - if (mProfileSpinnerAdapter != null) { - mSpinner = (Spinner) inflater.inflate(R.layout.spinner_view, null); - mSpinner.setAdapter(mProfileSpinnerAdapter); - mSpinner.setOnItemSelectedListener(this); - mPinnedHeader.addView(mSpinner); - mPinnedHeader.setVisibility(View.VISIBLE); - } mViewPager = (ViewPager) rootView.findViewById(R.id.pager); MyPagerAdapter adapter = new MyPagerAdapter(); mViewPager.setAdapter(adapter); @@ -1029,31 +1017,10 @@ public class ManageApplications extends Fragment implements @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) { - mApplicationsState.requestSize(mCurrentPkgName); - } - } - - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - UserHandle selectedUser = mProfileSpinnerAdapter.getUserHandle(position); - if (selectedUser.getIdentifier() != UserHandle.myUserId()) { - Intent intent = new Intent(Settings.ACTION_APPLICATION_SETTINGS); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); - int currentTab = mViewPager.getCurrentItem(); - intent.putExtra(EXTRA_LIST_TYPE, mTabs.get(currentTab).mListType); - mContext.startActivityAsUser(intent, selectedUser); - // Go back to default selection, which is the first one; this makes sure that pressing - // the back button takes you into a consistent state - mSpinner.setSelection(0); + mApplicationsState.requestSize(mCurrentPkgName, UserHandle.getUserId(mCurrentUid)); } } - @Override - public void onNothingSelected(AdapterView<?> parent) { - // Nothing to do - } - private void updateNumTabs() { int newNum = mApplicationsState.haveDisabledApps() ? mTabs.size() : (mTabs.size()-1); if (newNum != mNumTabs) { @@ -1076,13 +1043,13 @@ public class ManageApplications extends Fragment implements // utility method used to start sub activity private void startApplicationDetailsActivity() { - // start new fragment to display extended information - Bundle args = new Bundle(); - args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mCurrentPkgName); - - SettingsActivity sa = (SettingsActivity) getActivity(); - sa.startPreferencePanel(InstalledAppDetails.class.getName(), args, - R.string.application_info_label, null, this, INSTALLED_APP_DETAILS); + // TODO: Figure out if there is a way where we can spin up the profile's settings + // process ahead of time, to avoid a long load of data when user clicks on a managed app. + // Maybe when they load the list of apps that contains managed profile apps. + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.fromParts("package", mCurrentPkgName, null)); + getActivity().startActivityAsUser(intent, + new UserHandle(UserHandle.getUserId(mCurrentUid))); } @Override @@ -1273,6 +1240,7 @@ public class ManageApplications extends Fragment implements if (tab.mApplications != null && tab.mApplications.getCount() > position) { ApplicationsState.AppEntry entry = tab.mApplications.getAppEntry(position); mCurrentPkgName = entry.info.packageName; + mCurrentUid = entry.info.uid; startApplicationDetailsActivity(); } } diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java index 67c026b..0bb54b2 100644 --- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java +++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java @@ -112,7 +112,7 @@ public final class BluetoothDevicePreference extends Preference implements */ setTitle(mCachedDevice.getName()); - int summaryResId = getConnectionSummary(); + int summaryResId = mCachedDevice.getConnectionSummary(); if (summaryResId != 0) { setSummary(summaryResId); } else { @@ -232,60 +232,6 @@ public final class BluetoothDevicePreference extends Preference implements } } - private int getConnectionSummary() { - final CachedBluetoothDevice cachedDevice = mCachedDevice; - - boolean profileConnected = false; // at least one profile is connected - boolean a2dpNotConnected = false; // A2DP is preferred but not connected - boolean headsetNotConnected = false; // Headset is preferred but not connected - - for (LocalBluetoothProfile profile : cachedDevice.getProfiles()) { - int connectionStatus = cachedDevice.getProfileConnectionState(profile); - - switch (connectionStatus) { - case BluetoothProfile.STATE_CONNECTING: - case BluetoothProfile.STATE_DISCONNECTING: - return Utils.getConnectionStateSummary(connectionStatus); - - case BluetoothProfile.STATE_CONNECTED: - profileConnected = true; - break; - - case BluetoothProfile.STATE_DISCONNECTED: - if (profile.isProfileReady()) { - if (profile instanceof A2dpProfile) { - a2dpNotConnected = true; - } else if (profile instanceof HeadsetProfile) { - headsetNotConnected = true; - } - } - break; - } - } - - if (profileConnected) { - if (a2dpNotConnected && headsetNotConnected) { - return R.string.bluetooth_connected_no_headset_no_a2dp; - } else if (a2dpNotConnected) { - return R.string.bluetooth_connected_no_a2dp; - } else if (headsetNotConnected) { - return R.string.bluetooth_connected_no_headset; - } else { - return R.string.bluetooth_connected; - } - } - - switch (cachedDevice.getBondState()) { - case BluetoothDevice.BOND_BONDING: - return R.string.bluetooth_pairing; - - case BluetoothDevice.BOND_BONDED: - case BluetoothDevice.BOND_NONE: - default: - return 0; - } - } - private int getBtClassDrawable() { BluetoothClass btClass = mCachedDevice.getBtClass(); if (btClass != null) { diff --git a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java index b2a703d..f07a9f2 100644 --- a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java +++ b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java @@ -220,4 +220,6 @@ public abstract class DeviceListPreferenceFragment extends updateProgressUi(false); } } + + public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { } } diff --git a/src/com/android/settings/bluetooth/DockService.java b/src/com/android/settings/bluetooth/DockService.java index c4f6485..020ca0c 100644 --- a/src/com/android/settings/bluetooth/DockService.java +++ b/src/com/android/settings/bluetooth/DockService.java @@ -937,6 +937,7 @@ public final class DockService extends Service implements ServiceListener { public void onBluetoothStateChanged(int bluetoothState) { } public void onDeviceAdded(CachedBluetoothDevice cachedDevice) { } public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) { } + public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { } @Override public void onScanningStateChanged(boolean started) { diff --git a/src/com/android/settings/inputmethod/InputMethodSettingValuesWrapper.java b/src/com/android/settings/inputmethod/InputMethodSettingValuesWrapper.java index ada476e..8f10bdf 100644 --- a/src/com/android/settings/inputmethod/InputMethodSettingValuesWrapper.java +++ b/src/com/android/settings/inputmethod/InputMethodSettingValuesWrapper.java @@ -186,13 +186,16 @@ class InputMethodSettingValuesWrapper { if (imi.isAuxiliaryIme()) { return false; } - if (InputMethodUtils.isValidSystemDefaultIme(true /* isSystemReady */, imi, context)) { + final Locale systemLocale = context.getResources().getConfiguration().locale; + if (InputMethodUtils.isSystemImeThatHasSubtypeOf(imi, context, + true /* checkDefaultAttribute */, systemLocale, false /* checkCountry */, + InputMethodUtils.SUBTYPE_MODE_ANY)) { return true; } if (mAsciiCapableEnabledImis.isEmpty()) { Log.w(TAG, "ascii capable subtype enabled imi not found. Fall back to English" + " Keyboard subtype."); - return InputMethodUtils.containsSubtypeOf(imi, Locale.ENGLISH.getLanguage(), + return InputMethodUtils.containsSubtypeOf(imi, Locale.ENGLISH, false /* checkCountry */, InputMethodUtils.SUBTYPE_MODE_KEYBOARD); } return mAsciiCapableEnabledImis.contains(imi); diff --git a/src/com/android/settings/notification/NotificationSettings.java b/src/com/android/settings/notification/NotificationSettings.java index b392484..41ae0ab 100644 --- a/src/com/android/settings/notification/NotificationSettings.java +++ b/src/com/android/settings/notification/NotificationSettings.java @@ -71,6 +71,7 @@ public class NotificationSettings extends SettingsPreferenceFragment implements private static final String KEY_PHONE_RINGTONE = "ringtone"; private static final String KEY_NOTIFICATION_RINGTONE = "notification_ringtone"; private static final String KEY_VIBRATE_WHEN_RINGING = "vibrate_when_ringing"; + private static final String KEY_WIFI_DISPLAY = "wifi_display"; private static final String KEY_NOTIFICATION = "notification"; private static final String KEY_NOTIFICATION_PULSE = "notification_pulse"; private static final String KEY_LOCK_SCREEN_NOTIFICATIONS = "lock_screen_notifications"; @@ -601,6 +602,7 @@ public class NotificationSettings extends SettingsPreferenceFragment implements } else { rt.add(KEY_RING_VOLUME); rt.add(KEY_PHONE_RINGTONE); + rt.add(KEY_WIFI_DISPLAY); rt.add(KEY_VIBRATE_WHEN_RINGING); } return rt; diff --git a/src/com/android/settings/search/Ranking.java b/src/com/android/settings/search/Ranking.java index 6abbc3d..0022338 100644 --- a/src/com/android/settings/search/Ranking.java +++ b/src/com/android/settings/search/Ranking.java @@ -47,6 +47,7 @@ import com.android.settings.voice.VoiceInputSettings; import com.android.settings.wifi.AdvancedWifiSettings; import com.android.settings.wifi.SavedAccessPointsWifiSettings; import com.android.settings.wifi.WifiSettings; +import com.android.settings.WifiCallingSettings; import java.util.HashMap; @@ -104,6 +105,7 @@ public final class Ranking { // Other wireless settinfs sRankMap.put(WirelessSettings.class.getName(), RANK_WIRELESS); + sRankMap.put(WifiCallingSettings.class.getName(), RANK_WIRELESS); // Home sRankMap.put(HomeSettings.class.getName(), RANK_HOME); diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java index 502480d..d774469 100644 --- a/src/com/android/settings/search/SearchIndexableResources.java +++ b/src/com/android/settings/search/SearchIndexableResources.java @@ -49,6 +49,7 @@ import com.android.settings.voice.VoiceInputSettings; import com.android.settings.wifi.AdvancedWifiSettings; import com.android.settings.wifi.SavedAccessPointsWifiSettings; import com.android.settings.wifi.WifiSettings; +import com.android.settings.WifiCallingSettings; import java.util.Collection; import java.util.HashMap; @@ -270,6 +271,13 @@ public final class SearchIndexableResources { NO_DATA_RES_ID, DeviceInfoSettings.class.getName(), R.drawable.ic_settings_about)); + + sResMap.put(WifiCallingSettings.class.getName(), + new SearchIndexableResource( + Ranking.getRankForClassName(WifiCallingSettings.class.getName()), + R.xml.wifi_calling_settings, + WifiCallingSettings.class.getName(), + R.drawable.ic_settings_wireless)); } private SearchIndexableResources() { diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index dbd0481..e54ea9f 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -872,8 +872,7 @@ public class UserSettings extends SettingsPreferenceFragment for (int userId : values[0]) { Bitmap bitmap = mUserManager.getUserIcon(userId); if (bitmap == null) { - bitmap = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(userId, - /* light= */ false)); + bitmap = Utils.getDefaultUserIconAsBitmap(userId); } mUserIcons.append(userId, bitmap); } @@ -889,15 +888,13 @@ public class UserSettings extends SettingsPreferenceFragment } private void assignDefaultPhoto(UserInfo user) { - Bitmap bitmap = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(user.id, - /* light= */ false)); + Bitmap bitmap = Utils.getDefaultUserIconAsBitmap(user.id); mUserManager.setUserIcon(user.id, bitmap); } private Drawable getEncircledDefaultIcon() { if (mDefaultIconDrawable == null) { - mDefaultIconDrawable = encircle(UserIcons.convertToBitmap( - UserIcons.getDefaultUserIcon(UserHandle.USER_NULL, /* light= */ false))); + mDefaultIconDrawable = encircle(Utils.getDefaultUserIconAsBitmap(UserHandle.USER_NULL)); } return mDefaultIconDrawable; } diff --git a/src/com/android/settings/wifi/WifiApDialog.java b/src/com/android/settings/wifi/WifiApDialog.java index fb8026a..eee3db9 100644 --- a/src/com/android/settings/wifi/WifiApDialog.java +++ b/src/com/android/settings/wifi/WifiApDialog.java @@ -22,6 +22,7 @@ import android.content.DialogInterface; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.AuthAlgorithm; import android.net.wifi.WifiConfiguration.KeyMgmt; +import android.net.wifi.WifiManager; import android.os.Bundle; import android.text.Editable; import android.text.InputType; @@ -32,9 +33,13 @@ import android.widget.CheckBox; import android.widget.EditText; import android.widget.Spinner; import android.widget.TextView; +import android.widget.RadioGroup; +import android.widget.RadioButton; import com.android.settings.R; +import android.util.Log; + /** * Dialog to configure the SSID and security settings * for Access Point operation @@ -53,8 +58,14 @@ public class WifiApDialog extends AlertDialog implements View.OnClickListener, private TextView mSsid; private int mSecurityTypeIndex = OPEN_INDEX; private EditText mPassword; + private RadioGroup mChannel; + private RadioButton mChannel2G; + private RadioButton mChannel5G; WifiConfiguration mWifiConfig; + WifiManager mWifiManager; + + private static final String TAG = "WifiApDialog"; public WifiApDialog(Context context, DialogInterface.OnClickListener listener, WifiConfiguration wifiConfig) { @@ -64,6 +75,7 @@ public class WifiApDialog extends AlertDialog implements View.OnClickListener, if (wifiConfig != null) { mSecurityTypeIndex = getSecurityTypeIndex(wifiConfig); } + mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); } public static int getSecurityTypeIndex(WifiConfiguration wifiConfig) { @@ -85,6 +97,16 @@ public class WifiApDialog extends AlertDialog implements View.OnClickListener, */ config.SSID = mSsid.getText().toString(); + //obtain the band configure + if (mChannel2G.isChecked()) { + config.apBand = 0; + } else if(mChannel5G.isChecked()) { + config.apBand = 1; + } else { + Log.e("TAG", "AP band configure error!"); + return null; + } + switch (mSecurityTypeIndex) { case OPEN_INDEX: config.allowedKeyManagement.set(KeyMgmt.NONE); @@ -118,15 +140,36 @@ public class WifiApDialog extends AlertDialog implements View.OnClickListener, mSsid = (TextView) mView.findViewById(R.id.ssid); mPassword = (EditText) mView.findViewById(R.id.password); + mChannel = (RadioGroup) mView.findViewById(R.id.choose_channel); + mChannel2G = (RadioButton) mView.findViewById(R.id.ap_2G_band); + mChannel5G = (RadioButton) mView.findViewById(R.id.ap_5G_band); + + String countryCode = mWifiManager.getCountryCode(); + if (!mWifiManager.is5GHzBandSupported() || countryCode == null) { + //If no country code, 5GHz AP is forbidden + Log.e(TAG," NO country code, forbid 5GHz"); + mChannel5G.setVisibility(View.INVISIBLE); + mWifiConfig.apBand = 0; + } else { + mChannel5G.setVisibility(View.VISIBLE); + } + + setButton(BUTTON_SUBMIT, context.getString(R.string.wifi_save), mListener); setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(R.string.wifi_cancel), mListener); if (mWifiConfig != null) { mSsid.setText(mWifiConfig.SSID); + if (mWifiConfig.apBand == 0) { + mChannel2G.setChecked(true); + } else { + mChannel5G.setChecked(true); + } + mSecurity.setSelection(mSecurityTypeIndex); if (mSecurityTypeIndex == WPA2_INDEX) { - mPassword.setText(mWifiConfig.preSharedKey); + mPassword.setText(mWifiConfig.preSharedKey); } } diff --git a/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java b/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java index efa56d7..5716bec 100644 --- a/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java +++ b/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java @@ -73,7 +73,9 @@ public class WifiSettingsForSetupWizard extends WifiSettings { final Intent intent = getActivity().getIntent(); if (intent.getBooleanExtra(EXTRA_SHOW_WIFI_REQUIRED_INFO, false)) { - view.findViewById(R.id.wifi_required_info).setVisibility(View.VISIBLE); + final View requiredInfo = + inflater.inflate(R.layout.setup_wifi_required_info, list, false); + list.addHeaderView(requiredInfo, null, false); } return view; |