= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
+ if (quality == DevicePolicyManager.PASSWORD_QUALITY_GESTURE_WEAK) {
+ Intent intent = new Intent().setClass(getActivity(), ChooseLockGesture.class);
+ intent.putExtra(CONFIRM_CREDENTIALS, false);
+ intent.putExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
+ isFallback);
+ if (isFallback) {
+ startActivityForResult(intent, FALLBACK_REQUEST);
+ return;
+ } else {
+ mFinishPending = true;
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
+ }
+ } else if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
int minLength = mDPM.getPasswordMinimumLength(null);
if (minLength < MIN_PASSWORD_LENGTH) {
minLength = MIN_PASSWORD_LENGTH;
@@ -405,7 +422,7 @@ void updateUnlockMethodAndFinish(int quality, boolean disabled) {
startActivity(intent);
}
} else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
- Intent intent = new Intent(getActivity(), ChooseLockPattern.class);
+ Intent intent = new Intent(getActivity(), ChooseLockPatternSize.class);
intent.putExtra("key_lock_method", "pattern");
intent.putExtra(CONFIRM_CREDENTIALS, false);
intent.putExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
diff --git a/src/com/android/settings/ChooseLockGesture.java b/src/com/android/settings/ChooseLockGesture.java
new file mode 100644
index 00000000000..5432898e5c6
--- /dev/null
+++ b/src/com/android/settings/ChooseLockGesture.java
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2013 The ChameleonOS 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.Fragment;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.gesture.Gesture;
+import android.gesture.GestureStore;
+import android.gesture.Prediction;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
+import com.android.internal.widget.LockGestureView;
+import com.android.internal.widget.LockPatternUtils;
+
+import java.util.ArrayList;
+
+import static com.android.internal.widget.LockGestureView.DisplayMode;
+
+/**
+ * If the user has a lock gesture set already, makes them confirm the existing one.
+ *
+ * Then, prompts the user to choose a lock gesture:
+ * - prompts for initial gesture
+ * - asks for confirmation / restart
+ * - saves chosen password when confirmed
+ */
+public class ChooseLockGesture extends PreferenceActivity {
+ /**
+ * Used by the choose lock gesture wizard to indicate the wizard is
+ * finished, and each activity in the wizard should finish.
+ *
+ * Previously, each activity in the wizard would finish itself after
+ * starting the next activity. However, this leads to broken 'Back'
+ * behavior. So, now an activity does not finish itself until it gets this
+ * result.
+ */
+ static final int RESULT_FINISHED = RESULT_FIRST_USER;
+
+ @Override
+ public Intent getIntent() {
+ Intent modIntent = new Intent(super.getIntent());
+ modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ChooseLockGestureFragment.class.getName());
+ modIntent.putExtra(EXTRA_NO_HEADERS, true);
+ return modIntent;
+ }
+
+ @Override
+ protected boolean isValidFragment(String fragmentName) {
+ if (ChooseLockGestureFragment.class.getName().equals(fragmentName)) return true;
+ return false;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ CharSequence msg = getText(R.string.lockpassword_choose_your_gesture_header);
+ showBreadCrumbs(msg, msg);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ // *** TODO ***
+ return super.onKeyDown(keyCode, event);
+ }
+
+ public static class ChooseLockGestureFragment extends Fragment
+ implements View.OnClickListener {
+
+ public static final int CONFIRM_EXISTING_REQUEST = 55;
+
+ // how long after a confirmation message is shown before moving on
+ static final int INFORMATION_MSG_TIMEOUT_MS = 3000;
+
+ // how long we wait to clear a wrong gesture
+ private static final int WRONG_GESTURE_CLEAR_TIMEOUT_MS = 2000;
+
+ private static final int ID_EMPTY_MESSAGE = -1;
+
+ protected TextView mHeaderText;
+ protected LockGestureView mLockGestureView;
+ protected TextView mFooterText;
+ private TextView mFooterLeftButton;
+ private TextView mFooterRightButton;
+ protected Gesture mChosenGesture = null;
+ protected GestureStore mGestureStore;
+ protected int mMinPredictionScore;
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case CONFIRM_EXISTING_REQUEST:
+ if (resultCode != Activity.RESULT_OK) {
+ getActivity().setResult(RESULT_FINISHED);
+ getActivity().finish();
+ }
+ updateStage(Stage.Introduction);
+ break;
+ }
+ }
+
+ /**
+ * The gesture listener that responds according to a user choosing a new
+ * lock gesture.
+ */
+ protected LockGestureView.OnLockGestureListener mChooseNewLockGestureListener =
+ new LockGestureView.OnLockGestureListener() {
+
+ public void onGestureStart() {
+ mLockGestureView.removeCallbacks(mClearGestureRunnable);
+ mLockGestureView.setDisplayMode(DisplayMode.Correct);
+ gestureInProgress();
+ }
+
+ public void onGestureCleared() {
+ mLockGestureView.removeCallbacks(mClearGestureRunnable);
+ }
+
+ public void onGestureDetected(Gesture gesture) {
+ if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {
+ if (mChosenGesture == null) throw new IllegalStateException(
+ "null chosen pattern in stage 'need to confirm");
+ if (gestureMatch(gesture)) {
+ updateStage(Stage.ChoiceConfirmed);
+ } else {
+ updateStage(Stage.ConfirmWrong);
+ }
+ } else if (mUiStage == Stage.Introduction){
+ mChosenGesture = gesture;
+ if (mGestureStore.getGestures("lock_gesture") != null)
+ mGestureStore.removeEntry("lock_gesture");
+ mGestureStore.addGesture("lock_gesture", gesture);
+ updateStage(Stage.FirstChoiceValid);
+ } else {
+ throw new IllegalStateException("Unexpected stage " + mUiStage + " when "
+ + "entering the gesture.");
+ }
+ }
+
+ private void gestureInProgress() {
+ mHeaderText.setText(R.string.lockgesture_recording_inprogress);
+ mFooterText.setText("");
+ mFooterLeftButton.setEnabled(false);
+ mFooterRightButton.setEnabled(false);
+ }
+ };
+
+ protected boolean gestureMatch(Gesture gesture) {
+ ArrayList predictions = mGestureStore.recognize(gesture);
+ if (predictions.size() > 0) {
+ Prediction prediction = predictions.get(0);
+ if (prediction.score > mMinPredictionScore) {
+ if (prediction.name.equals("lock_gesture")) {
+ Gesture foundGesture = mGestureStore.getGestures("lock_gesture").get(0);
+ if (foundGesture.getStrokesCount() == gesture.getStrokesCount())
+ return true;
+ else
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * The states of the left footer button.
+ */
+ enum LeftButtonMode {
+ Cancel(R.string.cancel, true),
+ CancelDisabled(R.string.cancel, false),
+ Retry(R.string.lockgesture_retry_button_text, true),
+ RetryDisabled(R.string.lockgesture_retry_button_text, false),
+ Gone(ID_EMPTY_MESSAGE, false);
+
+
+ /**
+ * @param text The displayed text for this mode.
+ * @param enabled Whether the button should be enabled.
+ */
+ LeftButtonMode(int text, boolean enabled) {
+ this.text = text;
+ this.enabled = enabled;
+ }
+
+ final int text;
+ final boolean enabled;
+ }
+
+ /**
+ * The states of the right button.
+ */
+ enum RightButtonMode {
+ Continue(R.string.lockgesture_continue_button_text, true),
+ ContinueDisabled(R.string.lockgesture_continue_button_text, false),
+ Confirm(R.string.lockgesture_confirm_button_text, true),
+ ConfirmDisabled(R.string.lockgesture_confirm_button_text, false),
+ Ok(android.R.string.ok, true);
+
+ /**
+ * @param text The displayed text for this mode.
+ * @param enabled Whether the button should be enabled.
+ */
+ RightButtonMode(int text, boolean enabled) {
+ this.text = text;
+ this.enabled = enabled;
+ }
+
+ final int text;
+ final boolean enabled;
+ }
+
+ /**
+ * Keep track internally of where the user is in choosing a gesture.
+ */
+ protected enum Stage {
+
+ Introduction(
+ R.string.lockgesture_recording_intro_header,
+ LeftButtonMode.Cancel, RightButtonMode.ContinueDisabled,
+ ID_EMPTY_MESSAGE, true),
+ HelpScreen(
+ R.string.lockgesture_settings_help_how_to_record,
+ LeftButtonMode.Gone, RightButtonMode.Ok, ID_EMPTY_MESSAGE, false),
+ FirstChoiceValid(
+ R.string.lockgesture_pattern_entered_header,
+ LeftButtonMode.Retry, RightButtonMode.Continue, ID_EMPTY_MESSAGE, false),
+ NeedToConfirm(
+ R.string.lockgesture_need_to_confirm,
+ LeftButtonMode.Cancel, RightButtonMode.ConfirmDisabled,
+ ID_EMPTY_MESSAGE, true),
+ ConfirmWrong(
+ R.string.lockgesture_need_to_unlock_wrong,
+ LeftButtonMode.Cancel, RightButtonMode.ConfirmDisabled,
+ ID_EMPTY_MESSAGE, true),
+ ChoiceConfirmed(
+ R.string.lockgesture_pattern_confirmed_header,
+ LeftButtonMode.Cancel, RightButtonMode.Confirm, ID_EMPTY_MESSAGE, false);
+
+
+ /**
+ * @param headerMessage The message displayed at the top.
+ * @param leftMode The mode of the left button.
+ * @param rightMode The mode of the right button.
+ * @param footerMessage The footer message.
+ * @param gestureEnabled Whether the pattern widget is enabled.
+ */
+ Stage(int headerMessage,
+ LeftButtonMode leftMode,
+ RightButtonMode rightMode,
+ int footerMessage, boolean gestureEnabled) {
+ this.headerMessage = headerMessage;
+ this.leftMode = leftMode;
+ this.rightMode = rightMode;
+ this.footerMessage = footerMessage;
+ this.gestureEnabled = gestureEnabled;
+ }
+
+ final int headerMessage;
+ final LeftButtonMode leftMode;
+ final RightButtonMode rightMode;
+ final int footerMessage;
+ final boolean gestureEnabled;
+ }
+
+ private Stage mUiStage = Stage.Introduction;
+
+ private Runnable mClearGestureRunnable = new Runnable() {
+ public void run() {
+ mLockGestureView.clearGesture();
+ }
+ };
+
+ private ChooseLockSettingsHelper mChooseLockSettingsHelper;
+
+ private static final String KEY_UI_STAGE = "uiStage";
+ private static final String KEY_GESTURE_CHOICE = "chosenGesture";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
+ mGestureStore = new GestureStore();
+ mGestureStore.setOrientationStyle(GestureStore.ORIENTATION_SENSITIVE);
+ try {
+ mMinPredictionScore = getActivity().getResources().getInteger(
+ com.android.internal.R.integer.min_gesture_prediction_score);
+ } catch (Resources.NotFoundException e) {
+ mMinPredictionScore = 2;
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ // setupViews()
+ View view = inflater.inflate(R.layout.choose_lock_gesture, null);
+ mHeaderText = (TextView) view.findViewById(R.id.headerText);
+ mLockGestureView = (LockGestureView) view.findViewById(R.id.lockGesture);
+ mLockGestureView.setOnGestureListener(mChooseNewLockGestureListener);
+ mFooterText = (TextView) view.findViewById(R.id.footerText);
+
+ mFooterLeftButton = (TextView) view.findViewById(R.id.footerLeftButton);
+ mFooterRightButton = (TextView) view.findViewById(R.id.footerRightButton);
+
+ mFooterLeftButton.setOnClickListener(this);
+ mFooterRightButton.setOnClickListener(this);
+
+ // make it so unhandled touch events within the unlock screen go to the
+ // lock gesture view.
+ final LinearLayoutWithDefaultTouchRecepient topLayout
+ = (LinearLayoutWithDefaultTouchRecepient) view.findViewById(
+ R.id.topLayout);
+ topLayout.setDefaultTouchRecepient(mLockGestureView);
+
+ final boolean confirmCredentials = getActivity().getIntent()
+ .getBooleanExtra("confirm_credentials", false);
+
+ if (savedInstanceState == null) {
+ if (confirmCredentials) {
+ // first launch. As a security measure, we're in NeedToConfirm mode until we
+ // know there isn't an existing password or the user confirms their password.
+ updateStage(Stage.NeedToConfirm);
+ boolean launchedConfirmationActivity =
+ mChooseLockSettingsHelper.launchConfirmationActivity(
+ CONFIRM_EXISTING_REQUEST, null, null);
+ if (!launchedConfirmationActivity) {
+ updateStage(Stage.Introduction);
+ }
+ } else {
+ updateStage(Stage.Introduction);
+ }
+ } else {
+ // restore from previous state
+ final Gesture gesture = savedInstanceState.getParcelable(KEY_GESTURE_CHOICE);
+ if (gesture != null) {
+ mChosenGesture = gesture;
+ }
+ updateStage(Stage.values()[savedInstanceState.getInt(KEY_UI_STAGE)]);
+ }
+ return view;
+ }
+
+ public void onClick(View v) {
+ if (v == mFooterLeftButton) {
+ if (mUiStage.leftMode == LeftButtonMode.Retry) {
+ mChosenGesture = null;
+ mLockGestureView.clearGesture();
+ updateStage(Stage.Introduction);
+ } else if (mUiStage.leftMode == LeftButtonMode.Cancel) {
+ // They are canceling the entire wizard
+ getActivity().setResult(RESULT_FINISHED);
+ getActivity().finish();
+ } else {
+ throw new IllegalStateException("left footer button pressed, but stage of " +
+ mUiStage + " doesn't make sense");
+ }
+ } else if (v == mFooterRightButton) {
+
+ if (mUiStage.rightMode == RightButtonMode.Continue) {
+ if (mUiStage != Stage.FirstChoiceValid) {
+ throw new IllegalStateException("expected ui stage " + Stage.FirstChoiceValid
+ + " when button is " + RightButtonMode.Continue);
+ }
+ updateStage(Stage.NeedToConfirm);
+ } else if (mUiStage.rightMode == RightButtonMode.Confirm) {
+ if (mUiStage != Stage.ChoiceConfirmed) {
+ throw new IllegalStateException("expected ui stage " + Stage.ChoiceConfirmed
+ + " when button is " + RightButtonMode.Confirm);
+ }
+ saveChosenGestureAndFinish();
+ } else if (mUiStage.rightMode == RightButtonMode.Ok) {
+ if (mUiStage != Stage.HelpScreen) {
+ throw new IllegalStateException("Help screen is only mode with ok button, but " +
+ "stage is " + mUiStage);
+ }
+ mLockGestureView.clearGesture();
+ mLockGestureView.setDisplayMode(DisplayMode.Correct);
+ updateStage(Stage.Introduction);
+ }
+ }
+ }
+
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
+ if (mUiStage == Stage.HelpScreen) {
+ updateStage(Stage.Introduction);
+ return true;
+ }
+ }
+ if (keyCode == KeyEvent.KEYCODE_MENU && mUiStage == Stage.Introduction) {
+ updateStage(Stage.HelpScreen);
+ return true;
+ }
+ return false;
+ }
+
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ outState.putInt(KEY_UI_STAGE, mUiStage.ordinal());
+ if (mChosenGesture != null) {
+ outState.putParcelable(KEY_GESTURE_CHOICE, mChosenGesture);
+ }
+ }
+
+ /**
+ * Updates the messages and buttons appropriate to what stage the user
+ * is at in choosing a view. This doesn't handle clearing out the gesture;
+ * the gesture is expected to be in the right state.
+ * @param stage
+ */
+ protected void updateStage(Stage stage) {
+ final Stage previousStage = mUiStage;
+
+ mUiStage = stage;
+
+ // header text, footer text, visibility and
+ // enabled state all known from the stage
+ mHeaderText.setText(stage.headerMessage);
+ if (stage.footerMessage == ID_EMPTY_MESSAGE) {
+ mFooterText.setText("");
+ } else {
+ mFooterText.setText(stage.footerMessage);
+ }
+
+ if (stage.leftMode == LeftButtonMode.Gone) {
+ mFooterLeftButton.setVisibility(View.GONE);
+ } else {
+ mFooterLeftButton.setVisibility(View.VISIBLE);
+ mFooterLeftButton.setText(stage.leftMode.text);
+ mFooterLeftButton.setEnabled(stage.leftMode.enabled);
+ }
+
+ mFooterRightButton.setText(stage.rightMode.text);
+ mFooterRightButton.setEnabled(stage.rightMode.enabled);
+
+ // same for whether the patten is enabled
+ if (stage.gestureEnabled) {
+ mLockGestureView.enableInput();
+ } else {
+ mLockGestureView.disableInput();
+ }
+
+ // the rest of the stuff varies enough that it is easier just to handle
+ // on a case by case basis.
+ mLockGestureView.setDisplayMode(DisplayMode.Correct);
+
+ switch (mUiStage) {
+ case Introduction:
+ mLockGestureView.clearGesture();
+ break;
+ case HelpScreen:
+ break;
+ case FirstChoiceValid:
+ break;
+ case NeedToConfirm:
+ mLockGestureView.clearGesture();
+ break;
+ case ConfirmWrong:
+ mLockGestureView.setDisplayMode(DisplayMode.Wrong);
+ postClearGestureRunnable();
+ break;
+ case ChoiceConfirmed:
+ break;
+ }
+
+ // If the stage changed, announce the header for accessibility. This
+ // is a no-op when accessibility is disabled.
+ if (previousStage != stage) {
+ mHeaderText.announceForAccessibility(mHeaderText.getText());
+ }
+ }
+
+
+ // clear the wrong gesture unless they have started a new one
+ // already
+ private void postClearGestureRunnable() {
+ mLockGestureView.removeCallbacks(mClearGestureRunnable);
+ mLockGestureView.postDelayed(mClearGestureRunnable, WRONG_GESTURE_CLEAR_TIMEOUT_MS);
+ }
+
+ private void saveChosenGestureAndFinish() {
+ LockPatternUtils utils = mChooseLockSettingsHelper.utils();
+ final boolean lockVirgin = !utils.isGestureEverChosen();
+
+ final boolean isFallback = getActivity().getIntent()
+ .getBooleanExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false);
+ utils.saveLockGesture(mChosenGesture, isFallback);
+ utils.setLockGestureEnabled(true);
+
+ if (lockVirgin) {
+ utils.setVisibleGestureEnabled(true);
+ }
+
+ getActivity().setResult(RESULT_FINISHED);
+ getActivity().finish();
+ }
+ }
+}
diff --git a/src/com/android/settings/ChooseLockPattern.java b/src/com/android/settings/ChooseLockPattern.java
index 328312c2f73..28b722bbfe1 100644
--- a/src/com/android/settings/ChooseLockPattern.java
+++ b/src/com/android/settings/ChooseLockPattern.java
@@ -110,16 +110,12 @@ public static class ChooseLockPatternFragment extends Fragment
private TextView mFooterRightButton;
protected List mChosenPattern = null;
+ private byte mPatternSize = LockPatternUtils.PATTERN_SIZE_DEFAULT;
+
/**
* The patten used during the help screen to show how to draw a pattern.
*/
- private final List mAnimatePattern =
- Collections.unmodifiableList(Lists.newArrayList(
- LockPatternView.Cell.of(0, 0),
- LockPatternView.Cell.of(0, 1),
- LockPatternView.Cell.of(1, 1),
- LockPatternView.Cell.of(2, 1)
- ));
+ private List mAnimatePattern;
@Override
public void onActivityResult(int requestCode, int resultCode,
@@ -238,7 +234,6 @@ enum RightButtonMode {
* Keep track internally of where the user is in choosing a pattern.
*/
protected enum Stage {
-
Introduction(
R.string.lockpattern_recording_intro_header,
LeftButtonMode.Cancel, RightButtonMode.ContinueDisabled,
@@ -317,6 +312,16 @@ public void onCreate(Bundle savedInstanceState) {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
+ mPatternSize = getActivity().getIntent()
+ .getByteExtra("pattern_size", LockPatternUtils.PATTERN_SIZE_DEFAULT);
+ LockPatternView.Cell.updateSize(mPatternSize);
+ mAnimatePattern = Collections.unmodifiableList(Lists.newArrayList(
+ LockPatternView.Cell.of(0, 0, mPatternSize),
+ LockPatternView.Cell.of(0, 1, mPatternSize),
+ LockPatternView.Cell.of(1, 1, mPatternSize),
+ LockPatternView.Cell.of(2, 1, mPatternSize)
+ ));
+
// setupViews()
View view = inflater.inflate(R.layout.choose_lock_pattern, null);
mHeaderText = (TextView) view.findViewById(R.id.headerText);
@@ -324,6 +329,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
mLockPatternView.setOnPatternListener(mChooseNewLockPatternListener);
mLockPatternView.setTactileFeedbackEnabled(
mChooseLockSettingsHelper.utils().isTactileFeedbackEnabled());
+ mLockPatternView.setLockPatternSize(mPatternSize);
+ mLockPatternView.setLockPatternUtils(mChooseLockSettingsHelper.utils());
mFooterText = (TextView) view.findViewById(R.id.footerText);
@@ -361,7 +368,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
// restore from previous state
final String patternString = savedInstanceState.getString(KEY_PATTERN_CHOICE);
if (patternString != null) {
- mChosenPattern = LockPatternUtils.stringToPattern(patternString);
+ LockPatternUtils utils = mChooseLockSettingsHelper.utils();
+ mChosenPattern = utils.stringToPattern(patternString);
}
updateStage(Stage.values()[savedInstanceState.getInt(KEY_UI_STAGE)]);
}
@@ -427,8 +435,9 @@ public void onSaveInstanceState(Bundle outState) {
outState.putInt(KEY_UI_STAGE, mUiStage.ordinal());
if (mChosenPattern != null) {
+ LockPatternUtils utils = mChooseLockSettingsHelper.utils();
outState.putString(KEY_PATTERN_CHOICE,
- LockPatternUtils.patternToString(mChosenPattern));
+ utils.patternToString(mChosenPattern));
}
}
@@ -526,6 +535,7 @@ private void saveChosenPatternAndFinish() {
final boolean isFallback = getActivity().getIntent()
.getBooleanExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false);
+ utils.setLockPatternSize(mPatternSize);
utils.saveLockPattern(mChosenPattern, isFallback);
utils.setLockPatternEnabled(true);
diff --git a/src/com/android/settings/ChooseLockPatternSize.java b/src/com/android/settings/ChooseLockPatternSize.java
new file mode 100644
index 00000000000..57d0d0e752e
--- /dev/null
+++ b/src/com/android/settings/ChooseLockPatternSize.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod 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.content.Intent;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+
+import com.android.internal.widget.LockPatternUtils;
+
+public class ChooseLockPatternSize extends PreferenceActivity {
+
+ @Override
+ protected boolean isValidFragment (String fragmentName) {
+ if (ChooseLockPatternSizeFragment.class.getName().equals(fragmentName)) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public Intent getIntent() {
+ Intent modIntent = new Intent(super.getIntent());
+ modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ChooseLockPatternSizeFragment.class.getName());
+ modIntent.putExtra(EXTRA_NO_HEADERS, true);
+ return modIntent;
+ }
+
+ public static class ChooseLockPatternSizeFragment extends SettingsPreferenceFragment {
+ private ChooseLockSettingsHelper mChooseLockSettingsHelper;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity());
+ addPreferencesFromResource(R.xml.security_settings_pattern_size);
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
+ Preference preference) {
+ final String key = preference.getKey();
+
+ byte patternSize;
+ if ("lock_pattern_size_4".equals(key)) {
+ patternSize = 4;
+ } else if ("lock_pattern_size_5".equals(key)) {
+ patternSize = 5;
+ } else if ("lock_pattern_size_6".equals(key)) {
+ patternSize = 6;
+ } else {
+ patternSize = 3;
+ }
+
+ final boolean isFallback = getActivity().getIntent()
+ .getBooleanExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false);
+
+ Intent intent = new Intent();
+ intent.setClass(getActivity(), ChooseLockPattern.class);
+ intent.putExtra("pattern_size", patternSize);
+ intent.putExtra("key_lock_method", "pattern");
+ intent.putExtra("confirm_credentials", false);
+ intent.putExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
+ isFallback);
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
+
+ finish();
+ return true;
+ }
+ }
+}
diff --git a/src/com/android/settings/ChooseLockSettingsHelper.java b/src/com/android/settings/ChooseLockSettingsHelper.java
index a06971272ce..a76cad7e055 100644
--- a/src/com/android/settings/ChooseLockSettingsHelper.java
+++ b/src/com/android/settings/ChooseLockSettingsHelper.java
@@ -58,6 +58,9 @@ boolean launchConfirmationActivity(int request, CharSequence message, CharSequen
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
launched = confirmPattern(request, message, details);
break;
+ case DevicePolicyManager.PASSWORD_QUALITY_GESTURE_WEAK:
+ launched = confirmGesture(request, message, details);
+ break;
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
@@ -93,6 +96,30 @@ private boolean confirmPattern(int request, CharSequence message, CharSequence d
return true;
}
+ /**
+ * Launch screen to confirm the existing lock gesture.
+ * @param message shown in header of ConfirmLockGesture if not null
+ * @param details shown in footer of ConfirmLockGesture if not null
+ * @see #onActivityResult(int, int, android.content.Intent)
+ * @return true if we launched an activity to confirm gesture
+ */
+ private boolean confirmGesture(int request, CharSequence message, CharSequence details) {
+ if (!mLockPatternUtils.isLockGestureEnabled() || !mLockPatternUtils.savedGestureExists()) {
+ return false;
+ }
+ final Intent intent = new Intent();
+ // supply header and footer text in the intent
+ intent.putExtra(ConfirmLockPattern.HEADER_TEXT, message);
+ intent.putExtra(ConfirmLockPattern.FOOTER_TEXT, details);
+ intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockGesture");
+ if (mFragment != null) {
+ mFragment.startActivityForResult(intent, request);
+ } else {
+ mActivity.startActivityForResult(intent, request);
+ }
+ return true;
+ }
+
/**
* Launch screen to confirm the existing lock password.
* @see #onActivityResult(int, int, android.content.Intent)
diff --git a/src/com/android/settings/ConfirmLockGesture.java b/src/com/android/settings/ConfirmLockGesture.java
new file mode 100644
index 00000000000..20ddb2dac17
--- /dev/null
+++ b/src/com/android/settings/ConfirmLockGesture.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2008 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.Fragment;
+import android.content.Intent;
+import android.gesture.Gesture;
+import android.os.Bundle;
+import android.os.CountDownTimer;
+import android.os.SystemClock;
+import android.preference.PreferenceActivity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
+import com.android.internal.widget.LockGestureView;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternView;
+import com.android.internal.widget.LockPatternView.Cell;
+
+import java.util.List;
+
+/**
+ * Launch this when you want the user to confirm their lock gesture.
+ *
+ * Sets an activity result of {@link android.app.Activity#RESULT_OK} when the user
+ * successfully confirmed their gesture.
+ */
+public class ConfirmLockGesture extends PreferenceActivity {
+
+ /**
+ * Names of {@link CharSequence} fields within the originating {@link android.content.Intent}
+ * that are used to configure the keyguard confirmation view's labeling.
+ * The view will use the system-defined resource strings for any labels that
+ * the caller does not supply.
+ */
+ public static final String PACKAGE = "com.android.settings";
+ public static final String HEADER_TEXT = PACKAGE + ".ConfirmLockGesture.header";
+ public static final String FOOTER_TEXT = PACKAGE + ".ConfirmLockGesture.footer";
+ public static final String HEADER_WRONG_TEXT = PACKAGE + ".ConfirmLockGesture.header_wrong";
+ public static final String FOOTER_WRONG_TEXT = PACKAGE + ".ConfirmLockGesture.footer_wrong";
+
+ private enum Stage {
+ NeedToUnlock,
+ NeedToUnlockWrong,
+ LockedOut
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ CharSequence msg = getText(R.string.lockpassword_confirm_your_gesture_header);
+ showBreadCrumbs(msg, msg);
+ }
+
+ @Override
+ public Intent getIntent() {
+ Intent modIntent = new Intent(super.getIntent());
+ modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ConfirmLockGestureFragment.class.getName());
+ modIntent.putExtra(EXTRA_NO_HEADERS, true);
+ return modIntent;
+ }
+
+ @Override
+ protected boolean isValidFragment(String fragmentName) {
+ if (ConfirmLockGestureFragment.class.getName().equals(fragmentName)) return true;
+ return false;
+ }
+
+ public static class ConfirmLockGestureFragment extends Fragment {
+
+ // how long we wait to clear a wrong gesture
+ private static final int WRONG_GESTURE_CLEAR_TIMEOUT_MS = 2000;
+
+ private static final String KEY_NUM_WRONG_ATTEMPTS = "num_wrong_attempts";
+
+ private LockGestureView mLockGestureView;
+ private LockPatternUtils mLockPatternUtils;
+ private int mNumWrongConfirmAttempts;
+ private CountDownTimer mCountdownTimer;
+
+ private TextView mHeaderTextView;
+ private TextView mFooterTextView;
+
+ // caller-supplied text for various prompts
+ private CharSequence mHeaderText;
+ private CharSequence mFooterText;
+ private CharSequence mHeaderWrongText;
+ private CharSequence mFooterWrongText;
+
+ // required constructor for fragments
+ public ConfirmLockGestureFragment() {
+
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mLockPatternUtils = new LockPatternUtils(getActivity());
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.confirm_lock_gesture, null);
+ mHeaderTextView = (TextView) view.findViewById(R.id.headerText);
+ mLockGestureView = (LockGestureView) view.findViewById(R.id.lockGesture);
+ mFooterTextView = (TextView) view.findViewById(R.id.footerText);
+
+ // make it so unhandled touch events within the unlock screen go to the
+ // lock gesture view.
+ final LinearLayoutWithDefaultTouchRecepient topLayout
+ = (LinearLayoutWithDefaultTouchRecepient) view.findViewById(R.id.topLayout);
+ topLayout.setDefaultTouchRecepient(mLockGestureView);
+
+ Intent intent = getActivity().getIntent();
+ if (intent != null) {
+ mHeaderText = intent.getCharSequenceExtra(HEADER_TEXT);
+ mFooterText = intent.getCharSequenceExtra(FOOTER_TEXT);
+ mHeaderWrongText = intent.getCharSequenceExtra(HEADER_WRONG_TEXT);
+ mFooterWrongText = intent.getCharSequenceExtra(FOOTER_WRONG_TEXT);
+ }
+
+ mLockGestureView.setOnGestureListener(mConfirmExistingLockGestureListener);
+ updateStage(Stage.NeedToUnlock);
+
+ if (savedInstanceState != null) {
+ mNumWrongConfirmAttempts = savedInstanceState.getInt(KEY_NUM_WRONG_ATTEMPTS);
+ } else {
+ // on first launch, if no lock gesture is set, then finish with
+ // success (don't want user to get stuck confirming something that
+ // doesn't exist).
+ if (!mLockPatternUtils.savedGestureExists()) {
+ getActivity().setResult(Activity.RESULT_OK);
+ getActivity().finish();
+ }
+ }
+ return view;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ // deliberately not calling super since we are managing this in full
+ outState.putInt(KEY_NUM_WRONG_ATTEMPTS, mNumWrongConfirmAttempts);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ if (mCountdownTimer != null) {
+ mCountdownTimer.cancel();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ // if the user is currently locked out, enforce it.
+ long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
+ if (deadline != 0) {
+ handleAttemptLockout(deadline);
+ } else if (!mLockGestureView.isEnabled()) {
+ // The deadline has passed, but the timer was cancelled...
+ // Need to clean up.
+ mNumWrongConfirmAttempts = 0;
+ updateStage(Stage.NeedToUnlock);
+ }
+ }
+
+ private void updateStage(Stage stage) {
+ switch (stage) {
+ case NeedToUnlock:
+ if (mHeaderText != null) {
+ mHeaderTextView.setText(mHeaderText);
+ } else {
+ mHeaderTextView.setText(R.string.lockgesture_need_to_unlock);
+ }
+ if (mFooterText != null) {
+ mFooterTextView.setText(mFooterText);
+ } else {
+ mFooterTextView.setText(R.string.lockgesture_need_to_unlock_footer);
+ }
+
+ mLockGestureView.setEnabled(true);
+ mLockGestureView.enableInput();
+ break;
+ case NeedToUnlockWrong:
+ if (mHeaderWrongText != null) {
+ mHeaderTextView.setText(mHeaderWrongText);
+ } else {
+ mHeaderTextView.setText(R.string.lockgesture_need_to_unlock_wrong);
+ }
+ if (mFooterWrongText != null) {
+ mFooterTextView.setText(mFooterWrongText);
+ } else {
+ mFooterTextView.setText(R.string.lockgesture_need_to_unlock_wrong_footer);
+ }
+
+ mLockGestureView.setDisplayMode(LockGestureView.DisplayMode.Wrong);
+ mLockGestureView.setEnabled(true);
+ mLockGestureView.enableInput();
+ break;
+ case LockedOut:
+ mLockGestureView.clearGesture();
+ // enabled = false means: disable input, and have the
+ // appearance of being disabled.
+ mLockGestureView.setEnabled(false); // appearance of being disabled
+ break;
+ }
+
+ // Always announce the header for accessibility. This is a no-op
+ // when accessibility is disabled.
+ mHeaderTextView.announceForAccessibility(mHeaderTextView.getText());
+ }
+
+ private Runnable mClearGestureRunnable = new Runnable() {
+ public void run() {
+ mLockGestureView.clearGesture();
+ }
+ };
+
+ // clear the wrong gesture unless they have started a new one
+ // already
+ private void postClearPatternRunnable() {
+ mLockGestureView.removeCallbacks(mClearGestureRunnable);
+ mLockGestureView.postDelayed(mClearGestureRunnable, WRONG_GESTURE_CLEAR_TIMEOUT_MS);
+ }
+
+ /**
+ * The gesture listener that responds according to a user confirming
+ * an existing lock gesture.
+ */
+ private LockGestureView.OnLockGestureListener mConfirmExistingLockGestureListener
+ = new LockGestureView.OnLockGestureListener() {
+
+ public void onGestureStart() {
+ mLockGestureView.removeCallbacks(mClearGestureRunnable);
+ mLockGestureView.setDisplayMode(LockGestureView.DisplayMode.Correct);
+ }
+
+ public void onGestureCleared() {
+ mLockGestureView.removeCallbacks(mClearGestureRunnable);
+ }
+
+ public void onGestureDetected(Gesture gesture) {
+ if (mLockPatternUtils.checkGesture(gesture)) {
+
+ Intent intent = new Intent();
+ getActivity().setResult(Activity.RESULT_OK, intent);
+ getActivity().finish();
+ } else {
+ if (++mNumWrongConfirmAttempts
+ >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
+ long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
+ handleAttemptLockout(deadline);
+ } else {
+ updateStage(Stage.NeedToUnlockWrong);
+ postClearPatternRunnable();
+ }
+ }
+ }
+ };
+
+
+ private void handleAttemptLockout(long elapsedRealtimeDeadline) {
+ updateStage(Stage.LockedOut);
+ long elapsedRealtime = SystemClock.elapsedRealtime();
+ mCountdownTimer = new CountDownTimer(
+ elapsedRealtimeDeadline - elapsedRealtime,
+ LockPatternUtils.FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS) {
+
+ @Override
+ public void onTick(long millisUntilFinished) {
+ mHeaderTextView.setText(R.string.lockgesture_too_many_failed_confirmation_attempts_header);
+ final int secondsCountdown = (int) (millisUntilFinished / 1000);
+ mFooterTextView.setText(getString(
+ R.string.lockgesture_too_many_failed_confirmation_attempts_footer,
+ secondsCountdown));
+ }
+
+ @Override
+ public void onFinish() {
+ mNumWrongConfirmAttempts = 0;
+ updateStage(Stage.NeedToUnlock);
+ }
+ }.start();
+ }
+ }
+}
diff --git a/src/com/android/settings/ConfirmLockPattern.java b/src/com/android/settings/ConfirmLockPattern.java
index 3a1f06c339f..e30443419ff 100644
--- a/src/com/android/settings/ConfirmLockPattern.java
+++ b/src/com/android/settings/ConfirmLockPattern.java
@@ -137,7 +137,9 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
}
mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
+ mLockPatternView.setLockPatternSize(mLockPatternUtils.getLockPatternSize());
mLockPatternView.setOnPatternListener(mConfirmExistingLockPatternListener);
+ mLockPatternView.setLockPatternUtils(mLockPatternUtils);
updateStage(Stage.NeedToUnlock);
if (savedInstanceState != null) {
@@ -268,7 +270,7 @@ public void onPatternDetected(List pattern) {
Intent intent = new Intent();
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
- LockPatternUtils.patternToString(pattern));
+ mLockPatternUtils.patternToString(pattern));
getActivity().setResult(Activity.RESULT_OK, intent);
getActivity().finish();
diff --git a/src/com/android/settings/CreateShortcut.java b/src/com/android/settings/CreateShortcut.java
index f71df1d6f16..fc2d9c1f1f9 100644
--- a/src/com/android/settings/CreateShortcut.java
+++ b/src/com/android/settings/CreateShortcut.java
@@ -50,6 +50,17 @@ protected void onListItemClick(ListView l, View v, int position, long id) {
finish();
}
+ private int getProperShortcutIcon(String className) {
+ String c = className.substring(className.lastIndexOf(".") + 1);
+
+ if (c.equals("ScreenStateToggles"))
+ return R.drawable.ic_screen_state;
+ else if (c.equals("WakeLockBlocker"))
+ return R.drawable.ic_wakelock_blocker;
+ else
+ return R.mipmap.ic_launcher;
+ }
+
@Override
protected boolean onEvaluateShowIcons() {
return false;
diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java
index 23ec70ede83..d7a4f3332db 100644
--- a/src/com/android/settings/CryptKeeper.java
+++ b/src/com/android/settings/CryptKeeper.java
@@ -110,6 +110,7 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList
private boolean mEncryptionGoneBad;
/** A flag to indicate when the back event should be ignored */
private boolean mIgnoreBack = false;
+ private boolean mTryAgain = false;
private int mCooldown;
PowerManager.WakeLock mWakeLock;
private EditText mPasswordEntry;
@@ -121,9 +122,12 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList
*/
private static class NonConfigurationInstanceState {
final PowerManager.WakeLock wakelock;
+ final StatusBarManager statusbar;
- NonConfigurationInstanceState(PowerManager.WakeLock _wakelock) {
+ NonConfigurationInstanceState(PowerManager.WakeLock _wakelock,
+ StatusBarManager _statusbar) {
wakelock = _wakelock;
+ statusbar = _statusbar;
}
}
@@ -172,6 +176,7 @@ protected void onPostExecute(Integer failedAttempts) {
mCooldown = COOL_DOWN_INTERVAL;
cooldown();
} else {
+ mTryAgain = true;
final TextView status = (TextView) findViewById(R.id.status);
status.setText(R.string.try_again);
// Reenable the password entry
@@ -311,11 +316,6 @@ public void onCreate(Bundle savedInstanceState) {
return;
}
- // Disable the status bar, but do NOT disable back because the user needs a way to go
- // from keyboard settings and back to the password screen.
- mStatusBar = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
- mStatusBar.disable(sWidgetsToDisable);
-
setAirplaneModeIfNecessary();
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
// Check for (and recover) retained instance data
@@ -323,8 +323,17 @@ public void onCreate(Bundle savedInstanceState) {
if (lastInstance instanceof NonConfigurationInstanceState) {
NonConfigurationInstanceState retained = (NonConfigurationInstanceState) lastInstance;
mWakeLock = retained.wakelock;
+ mStatusBar = retained.statusbar;
Log.d(TAG, "Restoring wakelock from NonConfigurationInstanceState");
}
+
+ if (mStatusBar == null) {
+ // Disable the status bar, but do NOT disable back because the user needs a way to go
+ // from keyboard settings and back to the password screen.
+ mStatusBar = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
+ }
+ mStatusBar.disable(sWidgetsToDisable);
+
}
/**
@@ -354,6 +363,11 @@ private void setupUi() {
setContentView(R.layout.crypt_keeper_progress);
encryptionProgressInit();
} else if (mValidationComplete || isDebugView(FORCE_VIEW_PASSWORD)) {
+ if (mTryAgain || mCooldown > 0) {
+ mCooldown = 0;
+ mTryAgain = false;
+ setBackFunctionality(true);
+ }
setContentView(R.layout.crypt_keeper_password_entry);
passwordEntryInit();
} else if (!mValidationRequested) {
@@ -378,9 +392,11 @@ public void onStop() {
*/
@Override
public Object onRetainNonConfigurationInstance() {
- NonConfigurationInstanceState state = new NonConfigurationInstanceState(mWakeLock);
+ NonConfigurationInstanceState state = new NonConfigurationInstanceState(mWakeLock,
+ mStatusBar);
Log.d(TAG, "Handing wakelock off to NonConfigurationInstanceState");
mWakeLock = null;
+ mStatusBar = null;
return state;
}
@@ -636,6 +652,7 @@ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
// we either be re-enabled if the password was wrong or after the cooldown period.
mPasswordEntry.setEnabled(false);
setBackFunctionality(false);
+ mTryAgain = false;
Log.d(TAG, "Attempting to send command to decrypt");
new DecryptTask().execute(password);
@@ -776,4 +793,12 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
public void afterTextChanged(Editable s) {
return;
}
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ if (mTryAgain || mCooldown > 0) {
+ boolean isEnableBackKey = !hasFocus;
+ setBackFunctionality(isEnableBackKey);
+ }
+ }
}
diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java
index a0b18fd8dea..888e4fb4d45 100644
--- a/src/com/android/settings/DataUsageSummary.java
+++ b/src/com/android/settings/DataUsageSummary.java
@@ -1,4 +1,6 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,6 +24,9 @@
import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.WARNING_DISABLED;
+import static android.net.NetworkPolicy.CYCLE_DAILY;
+import static android.net.NetworkPolicy.CYCLE_MONTHLY;
+import static android.net.NetworkPolicy.CYCLE_WEEKLY;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -139,6 +144,7 @@
import com.android.settings.widget.ChartDataUsageView;
import com.android.settings.widget.ChartDataUsageView.DataUsageChartListener;
import com.android.settings.widget.PieChartView;
+import org.regulus.amrasettings.batterysaver.BatterySaverHelper;
import com.google.android.collect.Lists;
import libcore.util.Objects;
@@ -212,6 +218,8 @@ public class DataUsageSummary extends Fragment {
private LinearLayout mNetworkSwitches;
private Switch mDataEnabled;
private View mDataEnabledView;
+ private Switch mBatterySaverEnabled;
+ private View mBatterySaverEnabledView;
private CheckBox mDisableAtLimit;
private View mDisableAtLimitView;
@@ -354,6 +362,11 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
mDataEnabled.setOnCheckedChangeListener(mDataEnabledListener);
mNetworkSwitches.addView(mDataEnabledView);
+ mBatterySaverEnabled = new Switch(inflater.getContext());
+ mBatterySaverEnabledView = inflatePreference(inflater, mNetworkSwitches, mBatterySaverEnabled);
+ mBatterySaverEnabled.setOnCheckedChangeListener(mBatterySaverEnabledListener);
+ mNetworkSwitches.addView(mBatterySaverEnabledView);
+
mDisableAtLimit = new CheckBox(inflater.getContext());
mDisableAtLimit.setClickable(false);
mDisableAtLimit.setFocusable(false);
@@ -568,6 +581,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
@Override
public void onDestroy() {
mDataEnabledView = null;
+ mBatterySaverEnabledView = null;
mDisableAtLimitView = null;
mUidDetailProvider.clearCache();
@@ -705,23 +719,27 @@ private void updateBody() {
if (LOGD) Log.d(TAG, "updateBody() with currentTab=" + currentTab);
mDataEnabledView.setVisibility(isOwner ? View.VISIBLE : View.GONE);
+ mBatterySaverEnabledView.setVisibility(isOwner ? View.VISIBLE : View.GONE);
// TODO: remove mobile tabs when SIM isn't ready
final TelephonyManager tele = TelephonyManager.from(context);
if (TAB_MOBILE.equals(currentTab)) {
setPreferenceTitle(mDataEnabledView, R.string.data_usage_enable_mobile);
+ setPreferenceTitle(mBatterySaverEnabledView, R.string.data_usage_enable_batterysaver);
setPreferenceTitle(mDisableAtLimitView, R.string.data_usage_disable_mobile_limit);
mTemplate = buildTemplateMobileAll(getActiveSubscriberId(context));
} else if (TAB_3G.equals(currentTab)) {
setPreferenceTitle(mDataEnabledView, R.string.data_usage_enable_3g);
+ mBatterySaverEnabledView.setVisibility(View.GONE);
setPreferenceTitle(mDisableAtLimitView, R.string.data_usage_disable_3g_limit);
// TODO: bind mDataEnabled to 3G radio state
mTemplate = buildTemplateMobile3gLower(getActiveSubscriberId(context));
} else if (TAB_4G.equals(currentTab)) {
setPreferenceTitle(mDataEnabledView, R.string.data_usage_enable_4g);
+ mBatterySaverEnabledView.setVisibility(View.GONE);
setPreferenceTitle(mDisableAtLimitView, R.string.data_usage_disable_4g_limit);
// TODO: bind mDataEnabled to 4G radio state
mTemplate = buildTemplateMobile4g(getActiveSubscriberId(context));
@@ -729,12 +747,14 @@ private void updateBody() {
} else if (TAB_WIFI.equals(currentTab)) {
// wifi doesn't have any controls
mDataEnabledView.setVisibility(View.GONE);
+ mBatterySaverEnabledView.setVisibility(View.GONE);
mDisableAtLimitView.setVisibility(View.GONE);
mTemplate = buildTemplateWifiWildcard();
} else if (TAB_ETHERNET.equals(currentTab)) {
// ethernet doesn't have any controls
mDataEnabledView.setVisibility(View.GONE);
+ mBatterySaverEnabledView.setVisibility(View.GONE);
mDisableAtLimitView.setVisibility(View.GONE);
mTemplate = buildTemplateEthernet();
@@ -863,11 +883,24 @@ private boolean isMobileDataEnabled() {
}
}
+ private boolean isBatterySaverEnabled() {
+ final ContentResolver resolver = getActivity().getContentResolver();
+ return Settings.Global.getInt(resolver, Settings.Global.BATTERY_SAVER_OPTION, 0) != 0;
+ }
+
private void setMobileDataEnabled(boolean enabled) {
if (LOGD) Log.d(TAG, "setMobileDataEnabled()");
mConnService.setMobileDataEnabled(enabled);
mMobileDataEnabled = enabled;
- updatePolicy(false);
+ updatePolicy(true);
+ }
+
+ private void setBatterySaverModeEnabled(boolean enabled) {
+ if (LOGD) Log.d(TAG, "setBatterySaverModeEnabled()");
+ final Context context = getActivity();
+ BatterySaverHelper.setBatterySaverActive(context, enabled ? 1 : 0);
+ BatterySaverHelper.scheduleService(context);
+ updatePolicy(enabled);
}
private boolean isNetworkPolicyModifiable(NetworkPolicy policy) {
@@ -931,6 +964,7 @@ private void updatePolicy(boolean refreshCycle) {
if (TAB_MOBILE.equals(mCurrentTab)) {
mBinding = true;
mDataEnabled.setChecked(isMobileDataEnabled());
+ mBatterySaverEnabled.setChecked(isBatterySaverEnabled());
mBinding = false;
}
@@ -1043,8 +1077,20 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
ConfirmDataDisableFragment.show(DataUsageSummary.this);
}
}
+ }
+ };
- updatePolicy(false);
+ private OnCheckedChangeListener mBatterySaverEnabledListener = new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (mBinding) return;
+
+ final Context context = getActivity();
+ final boolean BatterySaverEnabled = isChecked;
+ final String currentTab = mCurrentTab;
+ if (TAB_MOBILE.equals(currentTab)) {
+ setBatterySaverModeEnabled(BatterySaverEnabled);
+ }
}
};
@@ -1188,8 +1234,8 @@ private void updateDetailData() {
final String rangePhrase = formatDateRange(context, start, end);
final int summaryRes;
- if (TAB_MOBILE.equals(mCurrentTab) || TAB_3G.equals(mCurrentApp)
- || TAB_4G.equals(mCurrentApp)) {
+ if (TAB_MOBILE.equals(mCurrentTab) || TAB_3G.equals(mCurrentTab)
+ || TAB_4G.equals(mCurrentTab)) {
summaryRes = R.string.data_usage_total_during_range_mobile;
} else {
summaryRes = R.string.data_usage_total_during_range;
@@ -1723,6 +1769,23 @@ public static void show(DataUsageSummary parent) {
dialog.show(parent.getFragmentManager(), TAG_CYCLE_EDITOR);
}
+ private void updatePicker(int cycleLength, int cycleDay, NumberPicker cycleDayPicker,
+ NumberPicker cycleWeekDayPicker,View cdEditor) {
+ if (cycleLength == CYCLE_MONTHLY) {
+ cdEditor.setVisibility(View.VISIBLE);
+ cycleWeekDayPicker.setVisibility(View.GONE);
+ cycleDayPicker.setVisibility(View.VISIBLE);
+ cycleDayPicker.setValue(cycleDay);
+ } else if (cycleLength == CYCLE_WEEKLY) {
+ cdEditor.setVisibility(View.VISIBLE);
+ cycleWeekDayPicker.setVisibility(View.VISIBLE);
+ cycleDayPicker.setVisibility(View.GONE);
+ cycleWeekDayPicker.setValue(cycleDay);
+ } else if (cycleLength == CYCLE_DAILY) {
+ cdEditor.setVisibility(View.GONE);
+ }
+ }
+
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Context context = getActivity();
@@ -1732,17 +1795,58 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
- final View view = dialogInflater.inflate(R.layout.data_usage_cycle_editor, null, false);
- final NumberPicker cycleDayPicker = (NumberPicker) view.findViewById(R.id.cycle_day);
-
final NetworkTemplate template = getArguments().getParcelable(EXTRA_TEMPLATE);
+ final int cycleLength = editor.getPolicyCycleLength(template);
final int cycleDay = editor.getPolicyCycleDay(template);
+ final View view = dialogInflater.inflate(R.layout.data_usage_cycle_editor, null, false);
+ final View cdEditor = view.findViewById(R.id.cycle_day_editor);
+
+ final NumberPicker cycleDayPicker = (NumberPicker) view.findViewById(R.id.cycle_day);
cycleDayPicker.setMinValue(1);
cycleDayPicker.setMaxValue(31);
- cycleDayPicker.setValue(cycleDay);
cycleDayPicker.setWrapSelectorWheel(true);
+ final NumberPicker cycleWeekDayPicker = (NumberPicker) view.findViewById(
+ R.id.cycle_weekday);
+ cycleWeekDayPicker.setMinValue(0);
+ cycleWeekDayPicker.setMaxValue(6);
+ cycleWeekDayPicker.setDisplayedValues(getResources().getStringArray(
+ R.array.data_usage_cycle_weekdays));
+ cycleWeekDayPicker.setWrapSelectorWheel(true);
+
+ final Spinner cycleLengthSpinner = (Spinner) view.findViewById(
+ R.id.cycle_lengths_spinner);
+ ArrayAdapter cycleLengthAdapter = ArrayAdapter.createFromResource(context,
+ R.array.data_usage_cycle_length,
+ android.R.layout.simple_spinner_item);
+ cycleLengthAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ cycleLengthSpinner.setAdapter(cycleLengthAdapter);
+ cycleLengthSpinner.setSelection(cycleLength);
+ cycleLengthSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
+
+ private int lastCycleLength = cycleLength;
+
+ @Override
+ public void onItemSelected(AdapterView> parent, View view,
+ int position, long id) {
+ if (position != lastCycleLength) {
+ editor.setPolicyCycleLength(template, position);
+ updatePicker(position, cycleDay, cycleDayPicker, cycleWeekDayPicker,
+ cdEditor);
+ lastCycleLength = position;
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {
+ // ignored
+ }
+ });
+
+ updatePicker(cycleLength, cycleDay, cycleDayPicker, cycleWeekDayPicker, cdEditor);
+
builder.setTitle(R.string.data_usage_cycle_editor_title);
builder.setView(view);
@@ -1752,8 +1856,17 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
public void onClick(DialogInterface dialog, int which) {
// clear focus to finish pending text edits
cycleDayPicker.clearFocus();
-
- final int cycleDay = cycleDayPicker.getValue();
+ cycleWeekDayPicker.clearFocus();
+
+ final int cycleDay;
+ final int cycleLength = editor.getPolicyCycleLength(template);
+ if (cycleLength == CYCLE_MONTHLY) {
+ cycleDay = cycleDayPicker.getValue();
+ } else if (cycleLength == CYCLE_WEEKLY) {
+ cycleDay = cycleWeekDayPicker.getValue();
+ } else {
+ cycleDay = 0;
+ }
final String cycleTimezone = new Time().timezone;
editor.setPolicyCycleDay(template, cycleDay, cycleTimezone);
target.updatePolicy(true);
diff --git a/src/com/android/settings/DebugIntentSender.java b/src/com/android/settings/DebugIntentSender.java
deleted file mode 100644
index 9fed94749e5..00000000000
--- a/src/com/android/settings/DebugIntentSender.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2006 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.widget.EditText;
-import android.widget.Button;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.text.TextUtils;
-import android.text.Spannable;
-import android.text.Selection;
-import android.net.Uri;
-
-/**
- * A simple activity that provides a UI for sending intents
- */
-public class DebugIntentSender extends Activity {
- private EditText mIntentField;
- private EditText mDataField;
- private EditText mAccountField;
- private EditText mResourceField;
- private Button mSendBroadcastButton;
- private Button mStartActivityButton;
- private View.OnClickListener mClicked = new View.OnClickListener() {
- public void onClick(View v) {
- if ((v == mSendBroadcastButton) ||
- (v == mStartActivityButton)) {
- String intentAction = mIntentField.getText().toString();
- String intentData = mDataField.getText().toString();
- String account = mAccountField.getText().toString();
- String resource = mResourceField.getText().toString();
-
- Intent intent = new Intent(intentAction);
- if (!TextUtils.isEmpty(intentData)) {
- intent.setData(Uri.parse(intentData));
- }
- intent.putExtra("account", account);
- intent.putExtra("resource", resource);
- if (v == mSendBroadcastButton) {
- sendBroadcast(intent);
- } else {
- startActivity(intent);
- }
-
- setResult(RESULT_OK);
- finish();
- }
- }
- };
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setContentView(R.layout.intent_sender);
-
- mIntentField = (EditText) findViewById(R.id.intent);
- mIntentField.setText(Intent.ACTION_SYNC);
- Selection.selectAll((Spannable) mIntentField.getText());
-
- mDataField = (EditText) findViewById(R.id.data);
- mDataField.setBackgroundResource(android.R.drawable.editbox_background);
-
- mAccountField = (EditText) findViewById(R.id.account);
- mResourceField = (EditText) findViewById(R.id.resource);
-
- mSendBroadcastButton = (Button) findViewById(R.id.sendbroadcast);
- mSendBroadcastButton.setOnClickListener(mClicked);
-
- mStartActivityButton = (Button) findViewById(R.id.startactivity);
- mStartActivityButton.setOnClickListener(mClicked);
- }
-}
diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java
index 3caa1b2d320..780dc6c2085 100644
--- a/src/com/android/settings/DevelopmentSettings.java
+++ b/src/com/android/settings/DevelopmentSettings.java
@@ -68,10 +68,13 @@
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.TextView;
+import android.widget.Toast;
import dalvik.system.VMRuntime;
import java.io.File;
+import com.android.settings.util.Helpers;
+
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -96,14 +99,17 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
private static final String ENABLE_ADB = "enable_adb";
private static final String ADB_NOTIFY = "adb_notify";
+ private static final String ADB_PARANOID = "adb_paranoid";
private static final String CLEAR_ADB_KEYS = "clear_adb_keys";
- private static final String ADB_TCPIP = "adb_over_network";
private static final String ENABLE_TERMINAL = "enable_terminal";
+ private static final String ADB_TCPIP = "adb_over_network";
+ private static final String RESTART_SYSTEMUI = "restart_systemui";
private static final String KEEP_SCREEN_ON = "keep_screen_on";
private static final String BT_HCI_SNOOP_LOG = "bt_hci_snoop_log";
private static final String SELECT_RUNTIME_KEY = "select_runtime";
private static final String SELECT_RUNTIME_PROPERTY = "persist.sys.dalvik.vm.lib";
private static final String ALLOW_MOCK_LOCATION = "allow_mock_location";
+ private static final String ALLOW_MOCK_SMS = "allow_mock_sms";
private static final String HDCP_CHECKING_KEY = "hdcp_checking";
private static final String HDCP_CHECKING_PROPERTY = "persist.sys.hdcp_checking";
private static final String LOCAL_BACKUP_PASSWORD = "local_backup_password";
@@ -142,6 +148,9 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
private static final String OPENGL_TRACES_KEY = "enable_opengl_traces";
+ private static final String ROOT_ACCESS_KEY = "root_access";
+ private static final String ROOT_ACCESS_PROPERTY = "persist.sys.root_access";
+
private static final String IMMEDIATELY_DESTROY_ACTIVITIES_KEY
= "immediately_destroy_activities";
private static final String APP_PROCESS_LIMIT_KEY = "app_process_limit";
@@ -154,8 +163,16 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
private static final String TERMINAL_APP_PACKAGE = "com.android.terminal";
+ private static final String DEVELOPMENT_TOOLS = "development_tools";
+
private static final String ADVANCED_REBOOT_KEY = "advanced_reboot";
+ private static final String DEVELOPMENT_SHORTCUT_KEY = "development_shortcut";
+
+ private static final String KEY_CHAMBER_OF_SECRETS = "chamber_of_secrets";
+ private static final String KEY_CHAMBER_OF_UNLOCKED_SECRETS =
+ "chamber_of_unlocked_secrets";
+
private static final int RESULT_DEBUG_APP = 1000;
private IWindowManager mWindowManager;
@@ -169,14 +186,17 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
private CheckBoxPreference mEnableAdb;
private CheckBoxPreference mAdbNotify;
+ private CheckBoxPreference mAdbParanoid;
private Preference mClearAdbKeys;
private CheckBoxPreference mEnableTerminal;
+ private Preference mRestartSystemUI;
private Preference mBugreport;
private CheckBoxPreference mBugreportInPower;
private CheckBoxPreference mAdbOverNetwork;
private CheckBoxPreference mKeepScreenOn;
private CheckBoxPreference mBtHciSnoopLog;
private CheckBoxPreference mAllowMockLocation;
+ private CheckBoxPreference mAllowMockSMS;
private PreferenceScreen mPassword;
private String mDebugApp;
@@ -211,10 +231,18 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
private ListPreference mAppProcessLimit;
private CheckBoxPreference mShowAllANRs;
- private CheckBoxPreference mExperimentalWebView;
+
+ private ListPreference mRootAccess;
+ private Object mSelectedRootValue;
+ private PreferenceScreen mDevelopmentTools;
private CheckBoxPreference mAdvancedReboot;
+ private CheckBoxPreference mDevelopmentShortcut;
+
+ private Preference mChamber;
+ private CheckBoxPreference mChamberUnlocked;
+
private final ArrayList mAllPrefs = new ArrayList();
private final ArrayList mResetCbPrefs
= new ArrayList();
@@ -229,6 +257,7 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
private Dialog mAdbKeysDialog;
private boolean mUnavailable;
+ private Dialog mRootDialog;
public DevelopmentSettings() {
super(RESTRICTIONS_PIN_SET);
@@ -255,7 +284,9 @@ public void onCreate(Bundle icicle) {
findPreference(DEBUG_DEBUGGING_CATEGORY_KEY);
mEnableAdb = findAndInitCheckboxPref(ENABLE_ADB);
- mAdbNotify = findAndInitCheckboxPref(ADB_NOTIFY);
+ mAdbNotify = (CheckBoxPreference) findPreference(ADB_NOTIFY);
+ mAllPrefs.add(mAdbNotify);
+ mAdbParanoid = findAndInitCheckboxPref(ADB_PARANOID);
mClearAdbKeys = findPreference(CLEAR_ADB_KEYS);
if (!SystemProperties.getBoolean("ro.adb.secure", false)) {
if (debugDebuggingCategory != null) {
@@ -268,28 +299,35 @@ public void onCreate(Bundle icicle) {
mEnableTerminal = null;
}
+ mRestartSystemUI = findPreference(RESTART_SYSTEMUI);
+
mBugreport = findPreference(BUGREPORT);
mBugreportInPower = findAndInitCheckboxPref(BUGREPORT_IN_POWER_KEY);
mAdbOverNetwork = findAndInitCheckboxPref(ADB_TCPIP);
mKeepScreenOn = findAndInitCheckboxPref(KEEP_SCREEN_ON);
mBtHciSnoopLog = findAndInitCheckboxPref(BT_HCI_SNOOP_LOG);
mAllowMockLocation = findAndInitCheckboxPref(ALLOW_MOCK_LOCATION);
+ mAllowMockSMS = findAndInitCheckboxPref(ALLOW_MOCK_SMS);
mPassword = (PreferenceScreen) findPreference(LOCAL_BACKUP_PASSWORD);
mAllPrefs.add(mPassword);
mAdvancedReboot = findAndInitCheckboxPref(ADVANCED_REBOOT_KEY);
+ mDevelopmentShortcut = findAndInitCheckboxPref(DEVELOPMENT_SHORTCUT_KEY);
if (!android.os.Process.myUserHandle().equals(UserHandle.OWNER)) {
disableForUser(mEnableAdb);
+ disableForUser(mAdbParanoid);
disableForUser(mClearAdbKeys);
disableForUser(mEnableTerminal);
disableForUser(mPassword);
disableForUser(mAdvancedReboot);
+ disableForUser(mDevelopmentShortcut);
}
mDebugAppPref = findPreference(DEBUG_APP_KEY);
mAllPrefs.add(mDebugAppPref);
mWaitForDebugger = findAndInitCheckboxPref(WAIT_FOR_DEBUGGER_KEY);
- mVerifyAppsOverUsb = findAndInitCheckboxPref(VERIFY_APPS_OVER_USB_KEY);
+ mVerifyAppsOverUsb = (CheckBoxPreference) findPreference(VERIFY_APPS_OVER_USB_KEY);
+ mAllPrefs.add(mVerifyAppsOverUsb);
if (!showVerifierSetting()) {
if (debugDebuggingCategory != null) {
debugDebuggingCategory.removePreference(mVerifyAppsOverUsb);
@@ -342,6 +380,32 @@ public void onCreate(Bundle icicle) {
mAllPrefs.add(hdcpChecking);
removePreferenceForProduction(hdcpChecking);
}
+
+ mRootAccess = (ListPreference) findPreference(ROOT_ACCESS_KEY);
+ mRootAccess.setOnPreferenceChangeListener(this);
+ if (!removeRootOptionsIfRequired()) {
+ mAllPrefs.add(mRootAccess);
+ }
+
+ mDevelopmentTools = (PreferenceScreen) findPreference(DEVELOPMENT_TOOLS);
+ mAllPrefs.add(mDevelopmentTools);
+
+ mChamber = (Preference) findPreference(KEY_CHAMBER_OF_SECRETS);
+ mAllPrefs.add(mChamber);
+ mChamberUnlocked =
+ findAndInitCheckboxPref(KEY_CHAMBER_OF_UNLOCKED_SECRETS);
+ mChamberUnlocked.setOnPreferenceChangeListener(this);
+
+ boolean chamberOpened = Settings.Secure.getInt(
+ getActivity().getContentResolver(),
+ Settings.Secure.CHAMBER_OF_SECRETS, 0) == 1;
+ mChamberUnlocked.setChecked(chamberOpened);
+
+ if (chamberOpened) {
+ removePreference(mChamber);
+ } else {
+ removePreference(mChamberUnlocked);
+ }
}
private ListPreference addListPreference(String prefKey) {
@@ -368,6 +432,18 @@ private CheckBoxPreference findAndInitCheckboxPref(String key) {
return pref;
}
+ private boolean removeRootOptionsIfRequired() {
+ // user builds don't get root, and eng always gets root
+ if (!(Build.IS_DEBUGGABLE || "eng".equals(Build.TYPE))) {
+ if (mRootAccess != null) {
+ getPreferenceScreen().removePreference(mRootAccess);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@@ -418,6 +494,12 @@ private void removePreference(Preference preference) {
mAllPrefs.remove(preference);
}
+ private void addPreference(Preference preference) {
+ getPreferenceScreen().addPreference(preference);
+ preference.setOnPreferenceChangeListener(this);
+ mAllPrefs.add(preference);
+ }
+
private void setPrefsEnabledState(boolean enabled) {
for (int i = 0; i < mAllPrefs.size(); i++) {
Preference pref = mAllPrefs.get(i);
@@ -482,6 +564,8 @@ private void updateAllOptions() {
Settings.Global.ADB_ENABLED, 0) != 0);
mAdbNotify.setChecked(Settings.Secure.getInt(cr,
Settings.Secure.ADB_NOTIFY, 1) != 0);
+ mAdbParanoid.setChecked(Settings.Secure.getInt(cr,
+ Settings.Secure.ADB_PARANOID, 0) != 0);
if (mEnableTerminal != null) {
updateCheckBox(mEnableTerminal,
context.getPackageManager().getApplicationEnabledSetting(TERMINAL_APP_PACKAGE)
@@ -494,8 +578,10 @@ private void updateAllOptions() {
updateCheckBox(mBtHciSnoopLog, Settings.Secure.getInt(cr,
Settings.Secure.BLUETOOTH_HCI_LOG, 0) != 0);
updateAdbOverNetwork();
- updateCheckBox(mAllowMockLocation, Settings.Secure.getInt(cr,
+ updateCheckBox(mAllowMockLocation, Settings.Secure.getInt(cr,
Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0);
+ updateCheckBox(mAllowMockSMS, Settings.Secure.getInt(cr,
+ Settings.Secure.ALLOW_MOCK_SMS, 0) != 0);
updateRuntimeValue();
updateHdcpValues();
updatePasswordSummary();
@@ -524,12 +610,9 @@ private void updateAllOptions() {
updateBugreportOptions();
updateForceRtlOptions();
updateWifiDisplayCertificationOptions();
+ updateRootAccessOptions();
updateAdvancedRebootOptions();
- }
-
- private void resetAdvancedRebootOptions() {
- Settings.Secure.putInt(getActivity().getContentResolver(),
- Settings.Secure.ADVANCED_REBOOT, 0);
+ updateDevelopmentShortcutOptions();
}
private void writeAdvancedRebootOptions() {
@@ -540,8 +623,52 @@ private void writeAdvancedRebootOptions() {
private void updateAdvancedRebootOptions() {
mAdvancedReboot.setChecked(Settings.Secure.getInt(getActivity().getContentResolver(),
- Settings.Secure.ADVANCED_REBOOT, 1) != 0);
- }
+ Settings.Secure.ADVANCED_REBOOT, 0) != 0);
+ }
+
+ private void resetDevelopmentShortcutOptions() {
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.DEVELOPMENT_SHORTCUT, 0);
+ }
+
+ private void writeDevelopmentShortcutOptions() {
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.DEVELOPMENT_SHORTCUT,
+ mDevelopmentShortcut.isChecked() ? 1 : 0);
+ }
+
+ private void updateDevelopmentShortcutOptions() {
+ mDevelopmentShortcut.setChecked(Settings.Secure.getInt(getActivity().getContentResolver(),
+ Settings.Secure.DEVELOPMENT_SHORTCUT, 0) != 0);
+ }
+
+ private void updateAdbOverNetwork() {
+ int port = Settings.Secure.getInt(getActivity().getContentResolver(),
+ Settings.Secure.ADB_PORT, 0);
+ boolean enabled = port > 0;
+
+ updateCheckBox(mAdbOverNetwork, enabled);
+
+ WifiInfo wifiInfo = null;
+
+ if (enabled) {
+ IWifiManager wifiManager = IWifiManager.Stub.asInterface(
+ ServiceManager.getService(Context.WIFI_SERVICE));
+ try {
+ wifiInfo = wifiManager.getConnectionInfo();
+ } catch (RemoteException e) {
+ Log.e(TAG, "wifiManager, getConnectionInfo()", e);
+ }
+ }
+
+ if (wifiInfo != null) {
+ String hostAddress = NetworkUtils.intToInetAddress(
+ wifiInfo.getIpAddress()).getHostAddress();
+ mAdbOverNetwork.setSummary(hostAddress + ":" + String.valueOf(port));
+ } else {
+ mAdbOverNetwork.setSummary(R.string.adb_over_network_summary);
+ }
+ }
private void resetDangerousOptions() {
mDontPokeProperties = true;
@@ -553,7 +680,10 @@ private void resetDangerousOptions() {
}
}
resetDebuggerOptions();
- resetAdvancedRebootOptions();
+ resetRootAccessOptions();
+ resetAdbNotifyOptions();
+ resetVerifyAppsOverUsbOptions();
+ resetDevelopmentShortcutOptions();
writeAnimationScaleOption(0, mWindowAnimationScale, null);
writeAnimationScaleOption(1, mTransitionAnimationScale, null);
writeAnimationScaleOption(2, mAnimatorDurationScale, null);
@@ -612,6 +742,50 @@ private void updateRuntimeValue() {
}
}
+ private void updateRootAccessOptions() {
+ String value = SystemProperties.get(ROOT_ACCESS_PROPERTY, "1");
+ mRootAccess.setValue(value);
+ mRootAccess.setSummary(getResources()
+ .getStringArray(R.array.root_access_entries)[Integer.valueOf(value)]);
+ }
+
+ /* package */ static boolean isRootForAppsEnabled() {
+ int value = SystemProperties.getInt(ROOT_ACCESS_PROPERTY, 1);
+ return value == 1 || value == 3;
+ }
+
+ private void writeRootAccessOptions(Object newValue) {
+ String oldValue = SystemProperties.get(ROOT_ACCESS_PROPERTY, "1");
+ SystemProperties.set(ROOT_ACCESS_PROPERTY, newValue.toString());
+ if (Integer.valueOf(newValue.toString()) < 2 && !oldValue.equals(newValue)
+ && "1".equals(SystemProperties.get("service.adb.root", "0"))) {
+ SystemProperties.set("service.adb.root", "0");
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.ADB_ENABLED, 0);
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.ADB_ENABLED, 1);
+ }
+ updateRootAccessOptions();
+ }
+
+ private void resetRootAccessOptions() {
+ String oldValue = SystemProperties.get(ROOT_ACCESS_PROPERTY, "1");
+ SystemProperties.set(ROOT_ACCESS_PROPERTY, "1");
+ if (!oldValue.equals("1") && "1".equals(SystemProperties.get("service.adb.root", "0"))) {
+ SystemProperties.set("service.adb.root", "0");
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.ADB_ENABLED, 0);
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.ADB_ENABLED, 1);
+ }
+ updateRootAccessOptions();
+ }
+
+ private void resetAdbNotifyOptions() {
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.ADB_NOTIFY, 1);
+ }
+
private void updateHdcpValues() {
ListPreference hdcpChecking = (ListPreference) findPreference(HDCP_CHECKING_KEY);
if (hdcpChecking != null) {
@@ -691,6 +865,11 @@ private void updateDebuggerOptions() {
}
}
+ private void resetVerifyAppsOverUsbOptions() {
+ Settings.Global.putInt(getActivity().getContentResolver(),
+ Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1);
+ }
+
private void updateVerifyAppsOverUsbOptions() {
updateCheckBox(mVerifyAppsOverUsb, Settings.Global.getInt(getActivity().getContentResolver(),
Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0);
@@ -1082,7 +1261,7 @@ private void updateAnimationScaleOptions() {
private void writeAnimationScaleOption(int which, ListPreference pref, Object newValue) {
try {
- float scale = newValue != null ? Float.parseFloat(newValue.toString()) : 1;
+ float scale = newValue != null ? Float.parseFloat(newValue.toString()) : 0.75f;
mWindowManager.setAnimationScale(which, scale);
updateAnimationScaleValue(which, pref);
} catch (RemoteException e) {
@@ -1185,7 +1364,9 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked != mLastEnabledState) {
if (isChecked) {
mDialogClicked = false;
- if (mEnableDialog != null) dismissDialogs();
+ if (mEnableDialog != null) {
+ dismissDialogs();
+ }
mEnableDialog = new AlertDialog.Builder(getActivity()).setMessage(
getActivity().getResources().getString(
R.string.dev_settings_warning_message))
@@ -1228,7 +1409,9 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
if (preference == mEnableAdb) {
if (mEnableAdb.isChecked()) {
mDialogClicked = false;
- if (mAdbDialog != null) dismissDialogs();
+ if (mAdbDialog != null) {
+ dismissDialogs();
+ }
mAdbDialog = new AlertDialog.Builder(getActivity()).setMessage(
getActivity().getResources().getString(R.string.adb_warning_message))
.setTitle(R.string.adb_warning_title)
@@ -1248,7 +1431,29 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
Settings.Secure.putInt(getActivity().getContentResolver(),
Settings.Secure.ADB_NOTIFY,
mAdbNotify.isChecked() ? 1 : 0);
- } else if (preference == mAdbOverNetwork) {
+ } else if (preference == mClearAdbKeys) {
+ if (mAdbKeysDialog != null) dismissDialogs();
+ mAdbKeysDialog = new AlertDialog.Builder(getActivity())
+ .setMessage(R.string.adb_keys_warning_message)
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ } else if (preference == mEnableTerminal) {
+ final PackageManager pm = getActivity().getPackageManager();
+ pm.setApplicationEnabledSetting(TERMINAL_APP_PACKAGE,
+ mEnableTerminal.isChecked() ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0);
+ } else if (preference == mRestartSystemUI) {
+ Helpers.restartSystemUI();
+ } else if (preference == mBugreportInPower) {
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.BUGREPORT_IN_POWER_MENU,
+ mBugreportInPower.isChecked() ? 1 : 0);
+ } else if (preference == mAdbParanoid) {
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.ADB_PARANOID,
+ mAdbParanoid.isChecked() ? 1 : 0);
+ } else if (preference == mAdbOverNetwork) {
if (mAdbOverNetwork.isChecked()) {
if (mAdbTcpDialog != null) {
dismissDialogs();
@@ -1266,22 +1471,6 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
Settings.Secure.ADB_PORT, -1);
updateAdbOverNetwork();
}
- } else if (preference == mClearAdbKeys) {
- if (mAdbKeysDialog != null) dismissDialogs();
- mAdbKeysDialog = new AlertDialog.Builder(getActivity())
- .setMessage(R.string.adb_keys_warning_message)
- .setPositiveButton(android.R.string.ok, this)
- .setNegativeButton(android.R.string.cancel, null)
- .show();
- } else if (preference == mEnableTerminal) {
- final PackageManager pm = getActivity().getPackageManager();
- pm.setApplicationEnabledSetting(TERMINAL_APP_PACKAGE,
- mEnableTerminal.isChecked() ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
- : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0);
- } else if (preference == mBugreportInPower) {
- Settings.Secure.putInt(getActivity().getContentResolver(),
- Settings.Secure.BUGREPORT_IN_POWER_MENU,
- mBugreportInPower.isChecked() ? 1 : 0);
} else if (preference == mKeepScreenOn) {
Settings.Global.putInt(getActivity().getContentResolver(),
Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
@@ -1293,6 +1482,10 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
Settings.Secure.putInt(getActivity().getContentResolver(),
Settings.Secure.ALLOW_MOCK_LOCATION,
mAllowMockLocation.isChecked() ? 1 : 0);
+ } else if (preference == mAllowMockSMS) {
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.ALLOW_MOCK_SMS,
+ mAllowMockSMS.isChecked() ? 1 : 0);
} else if (preference == mDebugAppPref) {
startActivityForResult(new Intent(getActivity(), AppPicker.class), RESULT_DEBUG_APP);
} else if (preference == mWaitForDebugger) {
@@ -1333,6 +1526,20 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
writeWifiDisplayCertificationOptions();
} else if (preference == mAdvancedReboot) {
writeAdvancedRebootOptions();
+ } else if (preference == mDevelopmentShortcut) {
+ writeDevelopmentShortcutOptions();
+ } else if (preference == mChamber) {
+ if (Settings.Secure.getInt(getActivity().getContentResolver(),
+ Settings.Secure.CHAMBER_OF_SECRETS, 0) == 0) {
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.CHAMBER_OF_SECRETS, 1);
+ Toast.makeText(getActivity(),
+ R.string.chamber_toast,
+ Toast.LENGTH_LONG).show();
+ getPreferenceScreen().removePreference(mChamber);
+ addPreference(mChamberUnlocked);
+ mChamberUnlocked.setChecked(true);
+ }
} else {
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
@@ -1413,6 +1620,30 @@ public void onClick(DialogInterface dialog, int which) {
} else if (preference == mAppProcessLimit) {
writeAppProcessLimitOptions(newValue);
return true;
+ } else if (preference == mRootAccess) {
+ if ("0".equals(SystemProperties.get(ROOT_ACCESS_PROPERTY, "1"))
+ && !"0".equals(newValue)) {
+ mSelectedRootValue = newValue;
+ mDialogClicked = false;
+ if (mRootDialog != null) {
+ dismissDialogs();
+ }
+ mRootDialog = new AlertDialog.Builder(getActivity())
+ .setMessage(getResources().getString(R.string.root_access_warning_message))
+ .setTitle(R.string.root_access_warning_title)
+ .setIconAttribute(android.R.attr.alertDialogIcon)
+ .setPositiveButton(android.R.string.yes, this)
+ .setNegativeButton(android.R.string.no, this).show();
+ mRootDialog.setOnDismissListener(this);
+ } else {
+ writeRootAccessOptions(newValue);
+ }
+ return true;
+ } else if (preference == mChamberUnlocked) {
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.CHAMBER_OF_SECRETS,
+ (Boolean) newValue ? 1 : 0);
+ return true;
}
return false;
}
@@ -1422,18 +1653,22 @@ private void dismissDialogs() {
mAdbDialog.dismiss();
mAdbDialog = null;
}
- if (mAdbTcpDialog != null) {
- mAdbTcpDialog.dismiss();
- mAdbTcpDialog = null;
- }
if (mAdbKeysDialog != null) {
mAdbKeysDialog.dismiss();
mAdbKeysDialog = null;
}
+ if (mAdbTcpDialog != null) {
+ mAdbTcpDialog.dismiss();
+ mAdbTcpDialog = null;
+ }
if (mEnableDialog != null) {
mEnableDialog.dismiss();
mEnableDialog = null;
}
+ if (mRootDialog != null) {
+ mRootDialog.dismiss();
+ mRootDialog = null;
+ }
}
public void onClick(DialogInterface dialog, int which) {
@@ -1445,17 +1680,11 @@ public void onClick(DialogInterface dialog, int which) {
mVerifyAppsOverUsb.setEnabled(true);
updateVerifyAppsOverUsbOptions();
updateBugreportOptions();
- } else {
- // Reset the toggle
- mEnableAdb.setChecked(false);
}
- } else if (dialog == mAdbTcpDialog) {
+ } else if (dialog == mAdbTcpDialog) {
if (which == DialogInterface.BUTTON_POSITIVE) {
Settings.Secure.putInt(getActivity().getContentResolver(),
Settings.Secure.ADB_PORT, 5555);
- } else {
- // Reset the toggle
- mAdbOverNetwork.setChecked(false);
}
} else if (dialog == mAdbKeysDialog) {
if (which == DialogInterface.BUTTON_POSITIVE) {
@@ -1474,9 +1703,14 @@ public void onClick(DialogInterface dialog, int which) {
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
mLastEnabledState = true;
setPrefsEnabledState(mLastEnabledState);
+ }
+
+ } else if (dialog == mRootDialog) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ writeRootAccessOptions(mSelectedRootValue);
} else {
- // Reset the toggle
- mEnabledSwitch.setChecked(false);
+ // Reset the option
+ writeRootAccessOptions("0");
}
}
}
@@ -1548,33 +1782,4 @@ private static boolean isPackageInstalled(Context context, String packageName) {
return false;
}
}
-
- private void updateAdbOverNetwork() {
- int port = Settings.Secure.getInt(getActivity().getContentResolver(),
- Settings.Secure.ADB_PORT, 0);
- boolean enabled = port > 0;
-
- updateCheckBox(mAdbOverNetwork, enabled);
-
- WifiInfo wifiInfo = null;
-
- if (enabled) {
- IWifiManager wifiManager = IWifiManager.Stub.asInterface(
- ServiceManager.getService(Context.WIFI_SERVICE));
- try {
- wifiInfo = wifiManager.getConnectionInfo();
- } catch (RemoteException e) {
- Log.e(TAG, "wifiManager, getConnectionInfo()", e);
- }
- }
-
- if (wifiInfo != null) {
- String hostAddress = NetworkUtils.intToInetAddress(
- wifiInfo.getIpAddress()).getHostAddress();
- mAdbOverNetwork.setSummary(hostAddress + ":" + String.valueOf(port));
- } else {
- mAdbOverNetwork.setSummary(R.string.adb_over_network_summary);
- }
- }
-
}
diff --git a/src/com/android/settings/DeviceInfoSettings.java b/src/com/android/settings/DeviceInfoSettings.java
index 486afab9d91..08e86c76b17 100644
--- a/src/com/android/settings/DeviceInfoSettings.java
+++ b/src/com/android/settings/DeviceInfoSettings.java
@@ -19,6 +19,9 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Bundle;
import android.os.SELinux;
@@ -26,15 +29,18 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.preference.Preference;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.util.Log;
import android.widget.Toast;
-import android.provider.Settings;
import java.io.BufferedReader;
import java.io.FileReader;
+import java.io.FileInputStream;
import java.io.IOException;
+import android.net.Uri;
+import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -44,6 +50,8 @@ public class DeviceInfoSettings extends RestrictedSettingsFragment {
private static final String FILENAME_PROC_VERSION = "/proc/version";
private static final String FILENAME_MSV = "/sys/board_properties/soc/msv";
+ private static final String FILENAME_PROC_MEMINFO = "/proc/meminfo";
+ private static final String FILENAME_PROC_CPUINFO = "/proc/cpuinfo";
private static final String KEY_CONTAINER = "container";
private static final String KEY_TEAM = "team";
@@ -65,9 +73,11 @@ public class DeviceInfoSettings extends RestrictedSettingsFragment {
private static final String KEY_EQUIPMENT_ID = "fcc_equipment_id";
private static final String PROPERTY_EQUIPMENT_ID = "ro.ril.fccid";
private static final String KEY_MOD_VERSION = "mod_version";
+// private static final String KEY_MOD_BUILD_DATE = "build_date";
+ private static final String KEY_DEVICE_CPU = "device_cpu";
+ private static final String KEY_DEVICE_MEMORY = "device_memory";
static final int TAPS_TO_BE_A_DEVELOPER = 7;
-
long[] mHits = new long[3];
int mDevHitCountdown;
Toast mDevHitToast;
@@ -92,10 +102,12 @@ public void onCreate(Bundle icicle) {
setStringSummary(KEY_DEVICE_MODEL, Build.MODEL + getMsvSuffix());
setValueSummary(KEY_EQUIPMENT_ID, PROPERTY_EQUIPMENT_ID);
setStringSummary(KEY_DEVICE_MODEL, Build.MODEL);
- setStringSummary(KEY_BUILD_NUMBER, Build.DISPLAY);
- findPreference(KEY_BUILD_NUMBER).setEnabled(true);
+ // setStringSummary(KEY_BUILD_NUMBER, Build.DISPLAY);
+ // findPreference(KEY_BUILD_NUMBER).setEnabled(true);
findPreference(KEY_KERNEL_VERSION).setSummary(getFormattedKernelVersion());
- setValueSummary(KEY_MOD_VERSION, "ro.omni.version");
+ setValueSummary(KEY_MOD_VERSION, "ro.amra.version");
+ findPreference(KEY_MOD_VERSION).setEnabled(true);
+
if (!SELinux.isSELinuxEnabled()) {
String status = getResources().getString(R.string.selinux_status_disabled);
@@ -109,6 +121,21 @@ public void onCreate(Bundle icicle) {
removePreferenceIfPropertyMissing(getPreferenceScreen(), KEY_SELINUX_STATUS,
PROPERTY_SELINUX_STATUS);
+ String cpuInfo = getCPUInfo();
+ String memInfo = getMemInfo();
+
+ if (cpuInfo != null) {
+ setStringSummary(KEY_DEVICE_CPU, cpuInfo);
+ } else {
+ getPreferenceScreen().removePreference(findPreference(KEY_DEVICE_CPU));
+ }
+
+ if (memInfo != null) {
+ setStringSummary(KEY_DEVICE_MEMORY, memInfo);
+ } else {
+ getPreferenceScreen().removePreference(findPreference(KEY_DEVICE_MEMORY));
+ }
+
// Remove Safety information preference if PROPERTY_URL_SAFETYLEGAL is not set
removePreferenceIfPropertyMissing(getPreferenceScreen(), "safetylegal",
PROPERTY_URL_SAFETYLEGAL);
@@ -184,6 +211,20 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
Log.e(LOG_TAG, "Unable to start activity " + intent.toString());
}
}
+ } else if (preference.getKey().equals(KEY_MOD_VERSION)) {
+ System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
+ mHits[mHits.length-1] = SystemClock.uptimeMillis();
+ if (mHits[0] >= (SystemClock.uptimeMillis()-500)) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.putExtra("is_bs", true);
+ intent.setClassName("android",
+ com.android.internal.app.PlatLogoActivity.class.getName());
+ try {
+ startActivity(intent);
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Unable to start activity " + intent.toString());
+ }
+ }
} else if (preference.getKey().equals(KEY_BUILD_NUMBER)) {
// Don't enable developer options for secondary users.
if (UserHandle.myUserId() != UserHandle.USER_OWNER) return true;
@@ -199,10 +240,6 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
getActivity().getSharedPreferences(DevelopmentSettings.PREF_FILE,
Context.MODE_PRIVATE).edit().putBoolean(
DevelopmentSettings.PREF_SHOW, true).apply();
-
- Settings.Secure.putInt(getActivity().getContentResolver(),
- Settings.Secure.DEVELOPER_OPTIONS_ENABLED, 1);
-
if (mDevHitToast != null) {
mDevHitToast.cancel();
}
@@ -348,4 +385,68 @@ private String getMsvSuffix() {
}
return "";
}
+
+ private String getMemInfo() {
+ String result = null;
+ BufferedReader reader = null;
+
+ try {
+ /* /proc/meminfo entries follow this format:
+ * MemTotal: 362096 kB
+ * MemFree: 29144 kB
+ * Buffers: 5236 kB
+ * Cached: 81652 kB
+ */
+ String firstLine = readLine(FILENAME_PROC_MEMINFO);
+ if (firstLine != null) {
+ String parts[] = firstLine.split("\\s+");
+ if (parts.length == 3) {
+ result = Long.parseLong(parts[1])/1024 + " MB";
+ }
+ }
+ } catch (IOException e) {}
+
+ return result;
+ }
+
+ private String getCPUInfo() {
+ String result = null;
+
+ try {
+ /* The expected /proc/cpuinfo output is as follows:
+ * Processor : ARMv7 Processor rev 2 (v7l)
+ * BogoMIPS : 272.62
+ */
+ String firstLine = readLine(FILENAME_PROC_CPUINFO);
+ if (firstLine != null) {
+ result = firstLine.split(":")[1].trim();
+ }
+ } catch (IOException e) {}
+
+ return result;
+ }
+
+ private boolean removePreferenceIfPackageNotInstalled(Preference preference) {
+ String intentUri = ((PreferenceScreen) preference).getIntent().toUri(1);
+ Pattern pattern = Pattern.compile("component=([^/]+)/");
+ Matcher matcher = pattern.matcher(intentUri);
+
+ String packageName = matcher.find() ? matcher.group(1) : null;
+ if(packageName != null) {
+ try {
+ PackageInfo pi = getPackageManager().getPackageInfo(packageName,
+ PackageManager.GET_ACTIVITIES);
+ if (!pi.applicationInfo.enabled) {
+ Log.e(LOG_TAG,"package "+packageName+" is disabled, hiding preference.");
+ getPreferenceScreen().removePreference(preference);
+ return true;
+ }
+ } catch (NameNotFoundException e) {
+ Log.e(LOG_TAG,"package "+packageName+" not installed, hiding preference.");
+ getPreferenceScreen().removePreference(preference);
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/src/com/android/settings/Display.java b/src/com/android/settings/Display.java
deleted file mode 100644
index fa293181205..00000000000
--- a/src/com/android/settings/Display.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2006 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.ActivityManagerNative;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.Spinner;
-import android.widget.TextView;
-
-
-public class Display extends Activity implements View.OnClickListener {
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- setContentView(R.layout.display);
-
- mFontSize = (Spinner) findViewById(R.id.fontSize);
- mFontSize.setOnItemSelectedListener(mFontSizeChanged);
- String[] states = new String[3];
- Resources r = getResources();
- states[0] = r.getString(R.string.small_font);
- states[1] = r.getString(R.string.medium_font);
- states[2] = r.getString(R.string.large_font);
- ArrayAdapter adapter = new ArrayAdapter(this,
- android.R.layout.simple_spinner_item, states);
- adapter.setDropDownViewResource(
- android.R.layout.simple_spinner_dropdown_item);
- mFontSize.setAdapter(adapter);
-
- mPreview = (TextView) findViewById(R.id.preview);
- mPreview.setText(r.getText(R.string.font_size_preview_text));
-
- Button save = (Button) findViewById(R.id.save);
- save.setText(r.getText(R.string.font_size_save));
- save.setOnClickListener(this);
-
- mTextSizeTyped = new TypedValue();
- TypedArray styledAttributes =
- obtainStyledAttributes(android.R.styleable.TextView);
- styledAttributes.getValue(android.R.styleable.TextView_textSize,
- mTextSizeTyped);
-
- DisplayMetrics metrics = getResources().getDisplayMetrics();
- mDisplayMetrics = new DisplayMetrics();
- mDisplayMetrics.density = metrics.density;
- mDisplayMetrics.heightPixels = metrics.heightPixels;
- mDisplayMetrics.scaledDensity = metrics.scaledDensity;
- mDisplayMetrics.widthPixels = metrics.widthPixels;
- mDisplayMetrics.xdpi = metrics.xdpi;
- mDisplayMetrics.ydpi = metrics.ydpi;
-
- styledAttributes.recycle();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- try {
- mCurConfig.updateFrom(
- ActivityManagerNative.getDefault().getConfiguration());
- } catch (RemoteException e) {
- }
- if (mCurConfig.fontScale < 1) {
- mFontSize.setSelection(0);
- } else if (mCurConfig.fontScale > 1) {
- mFontSize.setSelection(2);
- } else {
- mFontSize.setSelection(1);
- }
- updateFontScale();
- }
-
- private void updateFontScale() {
- mDisplayMetrics.scaledDensity = mDisplayMetrics.density *
- mCurConfig.fontScale;
-
- float size = mTextSizeTyped.getDimension(mDisplayMetrics);
- mPreview.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
- }
-
- public void onClick(View v) {
- try {
- ActivityManagerNative.getDefault().updatePersistentConfiguration(mCurConfig);
- } catch (RemoteException e) {
- }
- finish();
- }
-
- private Spinner.OnItemSelectedListener mFontSizeChanged
- = new Spinner.OnItemSelectedListener() {
- public void onItemSelected(android.widget.AdapterView av, View v,
- int position, long id) {
- if (position == 0) {
- mCurConfig.fontScale = .75f;
- } else if (position == 2) {
- mCurConfig.fontScale = 1.25f;
- } else {
- mCurConfig.fontScale = 1.0f;
- }
-
- updateFontScale();
- }
-
- public void onNothingSelected(android.widget.AdapterView av) {
- }
- };
-
- private Spinner mFontSize;
- private TextView mPreview;
- private TypedValue mTextSizeTyped;
- private DisplayMetrics mDisplayMetrics;
- private Configuration mCurConfig = new Configuration();
-}
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
index 33e34522af1..985f0297b8e 100644
--- a/src/com/android/settings/DisplaySettings.java
+++ b/src/com/android/settings/DisplaySettings.java
@@ -17,28 +17,39 @@
package com.android.settings;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-import static android.provider.Settings.System.SCREEN_OFF_ANIMATION;
import android.app.ActivityManagerNative;
import android.app.Dialog;
import android.app.admin.DevicePolicyManager;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.os.Bundle;
+import android.os.Handler;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
+import android.preference.PreferenceManager;
import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
import com.android.internal.view.RotationPolicy;
import com.android.settings.DreamSettings;
+import com.android.settings.Utils;
+import org.regulus.amrasettings.utils.DisplayRotation;
+
+import org.cyanogenmod.hardware.AdaptiveBacklight;
+import org.cyanogenmod.hardware.TapToWake;
import java.util.ArrayList;
@@ -48,36 +59,57 @@ public class DisplaySettings extends SettingsPreferenceFragment implements
/** If there is no setting in the provider, use this. */
private static final int FALLBACK_SCREEN_TIMEOUT_VALUE = 30000;
+ private static final int SCREEN_TIMEOUT_NEVER = Integer.MAX_VALUE;
private static final String KEY_SCREEN_TIMEOUT = "screen_timeout";
private static final String KEY_ACCELEROMETER = "accelerometer";
private static final String KEY_FONT_SIZE = "font_size";
- private static final String KEY_NOTIFICATION_LIGHT = "notification_light";
- private static final String KEY_BATTERY_LIGHT = "battery_light";
private static final String KEY_SCREEN_SAVER = "screensaver";
- private static final String KEY_SCREEN_OFF_ANIMATION = "screen_off_animation";
+ private static final String KEY_DISPLAY_ROTATION = "display_rotation";
+ private static final String KEY_ADAPTIVE_BACKLIGHT = "adaptive_backlight";
+ private static final String KEY_ADVANCED_DISPLAY_SETTINGS = "advanced_display_settings";
+ private static final String KEY_TAP_TO_WAKE = "double_tap_wake_gesture";
+
+ private static final String CATEGORY_LIGHTS = "lights_prefs";
+ private static final String KEY_NOTIFICATION_PULSE = "notification_pulse";
+ private static final String KEY_BATTERY_LIGHT = "battery_light";
private static final String KEY_WAKE_WHEN_PLUGGED_OR_UNPLUGGED = "wake_when_plugged_or_unplugged";
+ private static final String STATUS_BAR_BRIGHTNESS = "statusbar_brightness_slider";
+ private static final String KEY_SCREEN_COLOR_SETTINGS = "screencolor_settings";
private static final int DLG_GLOBAL_CHANGE_WARNING = 1;
private CheckBoxPreference mAccelerometer;
- private WarnedListPreference mFontSizePref;
- private Preference mNotificationLight;
- private Preference mChargingLight;
+ private FontDialogPreference mFontSizePref;
private CheckBoxPreference mWakeWhenPluggedOrUnplugged;
+ private CheckBoxPreference mStatusbarSliderPreference;
+
+ private PreferenceScreen mNotificationPulse;
+ private PreferenceScreen mBatteryPulse;
+ private PreferenceScreen mDisplayRotationPreference;
+ private PreferenceScreen mScreenColorSettings;
private final Configuration mCurConfig = new Configuration();
-
+
private ListPreference mScreenTimeoutPreference;
private Preference mScreenSaverPreference;
- private ListPreference mScreenOffAnimationPreference;
+ private CheckBoxPreference mAdaptiveBacklight;
+ private CheckBoxPreference mTapToWake;
+
+ private ContentObserver mAccelerometerRotationObserver =
+ new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateDisplayRotationPreferenceDescription();
+ }
+ };
private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
new RotationPolicy.RotationPolicyListener() {
@Override
public void onChange() {
- updateAccelerometerRotationCheckbox();
+ updateDisplayRotationPreferenceDescription();
}
};
@@ -85,18 +117,11 @@ public void onChange() {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ContentResolver resolver = getActivity().getContentResolver();
+ Resources res = getResources();
addPreferencesFromResource(R.xml.display_settings);
- mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);
- mAccelerometer.setPersistent(false);
- if (!RotationPolicy.isRotationSupported(getActivity())
- || RotationPolicy.isRotationLockToggleSupported(getActivity())) {
- // If rotation lock is supported, then we do not provide this option in
- // Display settings. However, is still available in Accessibility settings,
- // if the device supports rotation.
- getPreferenceScreen().removePreference(mAccelerometer);
- }
+ mDisplayRotationPreference = (PreferenceScreen) findPreference(KEY_DISPLAY_ROTATION);
mScreenSaverPreference = findPreference(KEY_SCREEN_SAVER);
if (mScreenSaverPreference != null
@@ -112,58 +137,111 @@ && getResources().getBoolean(
mScreenTimeoutPreference.setOnPreferenceChangeListener(this);
disableUnusableTimeouts(mScreenTimeoutPreference);
updateTimeoutPreferenceDescription(currentTimeout);
+ updateDisplayRotationPreferenceDescription();
- mScreenOffAnimationPreference = (ListPreference) findPreference(KEY_SCREEN_OFF_ANIMATION);
- final int currentAnimation = Settings.System.getInt(resolver, SCREEN_OFF_ANIMATION,
- 1 /* CRT-off */);
- mScreenOffAnimationPreference.setValue(String.valueOf(currentAnimation));
- mScreenOffAnimationPreference.setOnPreferenceChangeListener(this);
- updateScreenOffAnimationPreferenceDescription(currentAnimation);
-
- mFontSizePref = (WarnedListPreference) findPreference(KEY_FONT_SIZE);
+ mFontSizePref = (FontDialogPreference) findPreference(KEY_FONT_SIZE);
mFontSizePref.setOnPreferenceChangeListener(this);
mFontSizePref.setOnPreferenceClickListener(this);
- mNotificationLight = (Preference) findPreference(KEY_NOTIFICATION_LIGHT);
- if (mNotificationLight != null
- && getResources().getBoolean(
- com.android.internal.R.bool.config_intrusiveNotificationLed) == false) {
- getPreferenceScreen().removePreference(mNotificationLight);
+
+ mStatusbarSliderPreference = (CheckBoxPreference) findPreference(STATUS_BAR_BRIGHTNESS);
+ mStatusbarSliderPreference.setChecked((Settings.System.getInt(getActivity().getApplicationContext().getContentResolver(),
+ Settings.System.STATUSBAR_BRIGHTNESS_SLIDER, 0) == 1));
+
+ mAdaptiveBacklight = (CheckBoxPreference) findPreference(KEY_ADAPTIVE_BACKLIGHT);
+ if (!isAdaptiveBacklightSupported()) {
+ getPreferenceScreen().removePreference(mAdaptiveBacklight);
+ mAdaptiveBacklight = null;
}
- mChargingLight = (Preference) findPreference(KEY_BATTERY_LIGHT);
- if (mChargingLight != null
- && getResources().getBoolean(
- com.android.internal.R.bool.config_intrusiveBatteryLed) == false) {
- getPreferenceScreen().removePreference(mChargingLight);
+ mTapToWake = (CheckBoxPreference) findPreference(KEY_TAP_TO_WAKE);
+ if (!isTapToWakeSupported()) {
+ getPreferenceScreen().removePreference(mTapToWake);
+ mTapToWake = null;
}
- // Default value for wake-on-plug behavior from config.xml
- boolean wakeUpWhenPluggedOrUnpluggedConfig = getResources().getBoolean(
- com.android.internal.R.bool.config_unplugTurnsOnScreen);
+
+ Utils.updatePreferenceToSpecificActivityFromMetaDataOrRemove(getActivity(),
+ getPreferenceScreen(), KEY_ADVANCED_DISPLAY_SETTINGS);
mWakeWhenPluggedOrUnplugged =
(CheckBoxPreference) findPreference(KEY_WAKE_WHEN_PLUGGED_OR_UNPLUGGED);
- mWakeWhenPluggedOrUnplugged.setChecked(Settings.Global.getInt(resolver,
- Settings.Global.WAKE_WHEN_PLUGGED_OR_UNPLUGGED,
- (wakeUpWhenPluggedOrUnpluggedConfig ? 1 : 0)) == 1);
- }
- private void updateScreenOffAnimationPreferenceDescription(int currentAnim) {
- ListPreference preference = mScreenOffAnimationPreference;
- String summary;
- if (currentAnim < 0) {
- // Unsupported value
- summary = "";
+ boolean hasNotificationLed = res.getBoolean(
+ com.android.internal.R.bool.config_intrusiveNotificationLed);
+ boolean hasBatteryLed = res.getBoolean(
+ com.android.internal.R.bool.config_intrusiveBatteryLed);
+ PreferenceCategory lightPrefs = (PreferenceCategory) findPreference(CATEGORY_LIGHTS);
+
+ if (hasNotificationLed || hasBatteryLed) {
+ mBatteryPulse = (PreferenceScreen) findPreference(KEY_BATTERY_LIGHT);
+ mNotificationPulse = (PreferenceScreen) findPreference(KEY_NOTIFICATION_PULSE);
+
+ // Battery light is only for primary user
+ if (UserHandle.myUserId() != UserHandle.USER_OWNER || !hasBatteryLed) {
+ lightPrefs.removePreference(mBatteryPulse);
+ mBatteryPulse = null;
+ }
+
+ if (!hasNotificationLed) {
+ lightPrefs.removePreference(mNotificationPulse);
+ mNotificationPulse = null;
+ }
} else {
- final CharSequence[] entries = preference.getEntries();
- final CharSequence[] values = preference.getEntryValues();
- if (entries == null || entries.length == 0) {
- summary = "";
+ getPreferenceScreen().removePreference(lightPrefs);
+ }
+
+ mScreenColorSettings = (PreferenceScreen) findPreference(KEY_SCREEN_COLOR_SETTINGS);
+ if (!isPostProcessingSupported()) {
+ getPreferenceScreen().removePreference(mScreenColorSettings);
+ }
+ }
+
+ private void updateDisplayRotationPreferenceDescription() {
+ if (mDisplayRotationPreference == null) {
+ // The preference was removed, do nothing
+ return;
+ }
+
+ // We have a preference, lets update the summary
+ boolean rotationEnabled = Settings.System.getInt(getContentResolver(),
+ Settings.System.ACCELEROMETER_ROTATION, 0) != 0;
+
+ if (!rotationEnabled) {
+ mDisplayRotationPreference.setSummary(R.string.display_rotation_disabled);
+ return;
+ }
+
+ StringBuilder summary = new StringBuilder();
+ int mode = Settings.System.getInt(getContentResolver(),
+ Settings.System.ACCELEROMETER_ROTATION_ANGLES,
+ DisplayRotation.ROTATION_0_MODE
+ | DisplayRotation.ROTATION_90_MODE
+ | DisplayRotation.ROTATION_270_MODE);
+ ArrayList rotationList = new ArrayList();
+ String delim = "";
+
+ if ((mode & DisplayRotation.ROTATION_0_MODE) != 0) {
+ rotationList.add("0");
+ }
+ if ((mode & DisplayRotation.ROTATION_90_MODE) != 0) {
+ rotationList.add("90");
+ }
+ if ((mode & DisplayRotation.ROTATION_180_MODE) != 0) {
+ rotationList.add("180");
+ }
+ if ((mode & DisplayRotation.ROTATION_270_MODE) != 0) {
+ rotationList.add("270");
+ }
+ for (int i = 0; i < rotationList.size(); i++) {
+ summary.append(delim).append(rotationList.get(i));
+ if ((rotationList.size() - i) > 2) {
+ delim = ", ";
} else {
- summary = entries[currentAnim].toString();
+ delim = " & ";
}
}
- preference.setSummary(summary);
+ summary.append(" " + getString(R.string.display_rotation_unit));
+ mDisplayRotationPreference.setSummary(summary);
}
private void updateTimeoutPreferenceDescription(long currentTimeout) {
@@ -206,7 +284,7 @@ private void disableUnusableTimeouts(ListPreference screenTimeoutPreference) {
ArrayList revisedValues = new ArrayList();
for (int i = 0; i < values.length; i++) {
long timeout = Long.parseLong(values[i].toString());
- if (timeout <= maxTimeout) {
+ if (timeout <= maxTimeout || timeout == SCREEN_TIMEOUT_NEVER) {
revisedEntries.add(entries[i]);
revisedValues.add(values[i]);
}
@@ -233,44 +311,37 @@ private void disableUnusableTimeouts(ListPreference screenTimeoutPreference) {
screenTimeoutPreference.setEnabled(revisedEntries.size() > 0);
}
- int floatToIndex(float val) {
- String[] indices = getResources().getStringArray(R.array.entryvalues_font_size);
- float lastVal = Float.parseFloat(indices[0]);
- for (int i=1; i homeActivities = new ArrayList();
ComponentName currentDefaultHome = mPm.getHomeActivities(homeActivities);
+ Intent prefsIntent = new Intent(Intent.ACTION_MAIN);
+ prefsIntent.addCategory("com.cyanogenmod.category.LAUNCHER_PREFERENCES");
+ List prefsActivities = mPm.queryIntentActivities(prefsIntent, 0);
+
Context context = getActivity();
mCurrentHome = null;
mPrefGroup.removeAll();
@@ -157,13 +173,23 @@ void buildHomeActivitiesList() {
for (int i = 0; i < homeActivities.size(); i++) {
final ResolveInfo candidate = homeActivities.get(i);
final ActivityInfo info = candidate.activityInfo;
+ Intent resolvedPrefsIntent = null;
ComponentName activityName = new ComponentName(info.packageName, info.name);
mHomeComponentSet[i] = activityName;
+
+ for (ResolveInfo prefInfo : prefsActivities) {
+ if (info.packageName.equals(prefInfo.activityInfo.packageName)) {
+ resolvedPrefsIntent = new Intent(prefsIntent);
+ resolvedPrefsIntent.setPackage(info.packageName);
+ break;
+ }
+ }
+
try {
Drawable icon = info.loadIcon(mPm);
CharSequence name = info.loadLabel(mPm);
HomeAppPreference pref = new HomeAppPreference(context, activityName, prefIndex,
- icon, name, this, info);
+ icon, name, this, info, resolvedPrefsIntent);
mPrefs.add(pref);
mPrefGroup.addPreference(pref);
pref.setEnabled(true);
@@ -195,6 +221,8 @@ public void onCreate(Bundle savedInstanceState) {
Bundle args = getArguments();
mShowNotice = (args != null) && args.getBoolean(HOME_SHOW_NOTICE, false);
+
+ setHasOptionsMenu(true);
}
@Override
@@ -203,19 +231,40 @@ public void onResume() {
buildHomeActivitiesList();
}
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ HomeAppPreference selectedPref = null;
+
+ for (HomeAppPreference pref : mPrefs) {
+ if (pref.isChecked) {
+ selectedPref = pref;
+ break;
+ }
+ }
+
+ super.onCreateOptionsMenu(menu, inflater);
+
+ if (selectedPref != null && selectedPref.prefsIntent != null) {
+ menu.add(Menu.NONE, Menu.NONE, Menu.NONE, R.string.settings_label)
+ .setIntent(selectedPref.prefsIntent)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ }
+ }
+
class HomeAppPreference extends Preference {
ComponentName activityName;
int index;
HomeSettings fragment;
final ColorFilter grayscaleFilter;
boolean isChecked;
+ final Intent prefsIntent;
boolean isSystem;
String uninstallTarget;
public HomeAppPreference(Context context, ComponentName activity,
int i, Drawable icon, CharSequence title,
- HomeSettings parent, ActivityInfo info) {
+ HomeSettings parent, ActivityInfo info, Intent prefsIntent) {
super(context);
setLayoutResource(R.layout.preference_home_app);
setIcon(icon);
@@ -223,6 +272,7 @@ public HomeAppPreference(Context context, ComponentName activity,
activityName = activity;
fragment = parent;
index = i;
+ this.prefsIntent = prefsIntent;
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(0f);
@@ -287,6 +337,7 @@ void setChecked(boolean state) {
if (state != isChecked) {
isChecked = state;
notifyChanged();
+ getActivity().invalidateOptionsMenu();
}
}
}
diff --git a/src/com/android/settings/HostnamePreference.java b/src/com/android/settings/HostnamePreference.java
new file mode 100644
index 00000000000..e44ea17e97f
--- /dev/null
+++ b/src/com/android/settings/HostnamePreference.java
@@ -0,0 +1,111 @@
+package com.android.settings;
+
+import android.content.Context;
+import android.os.SystemProperties;
+import android.preference.EditTextPreference;
+import android.provider.Settings;
+import android.text.InputFilter;
+import android.text.Spanned;
+import android.util.AttributeSet;
+import android.util.Log;
+
+public class HostnamePreference extends EditTextPreference {
+
+ private static final String TAG = "HostnamePreference";
+
+ private static final String PROP_HOSTNAME = "net.hostname";
+
+ private final String DEFAULT_HOSTNAME;
+
+ InputFilter mHostnameInputFilter = new InputFilter() {
+ @Override
+ public CharSequence filter(CharSequence source, int start, int end,
+ Spanned dest, int dstart, int dend) {
+
+ if (source.length() == 0)
+ return null;
+
+ // remove any character that is not alphanumeric, period, or hyphen
+ return source.subSequence(start, end).toString().replaceAll("[^-.a-zA-Z0-9]", "");
+ }
+ };
+
+ public HostnamePreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ // determine the default hostname
+ String id = Settings.Secure.getString(getContext().getContentResolver(),
+ Settings.Secure.ANDROID_ID);
+ if (id != null && id.length() > 0) {
+ DEFAULT_HOSTNAME = "android-".concat(id);
+ } else {
+ DEFAULT_HOSTNAME = "";
+ }
+
+ setSummary(getText());
+ getEditText().setFilters(new InputFilter[] { mHostnameInputFilter });
+ getEditText().setHint(DEFAULT_HOSTNAME);
+ }
+
+ public HostnamePreference(Context context, AttributeSet attrs) {
+ this(context, attrs, com.android.internal.R.attr.editTextPreferenceStyle);
+ }
+
+ public HostnamePreference(Context context) {
+ this(context, null);
+ }
+
+ @Override
+ protected void onDialogClosed(boolean positiveResult) {
+ if (positiveResult) {
+ String hostname = getEditText().getText().toString();
+
+ // remove any preceding or succeeding periods or hyphens
+ hostname = hostname.replaceAll("(?:\\.|-)+$", "");
+ hostname = hostname.replaceAll("^(?:\\.|-)+", "");
+
+ if (hostname.length() == 0) {
+ if (DEFAULT_HOSTNAME.length() != 0) {
+ // if no hostname is given, use the default
+ hostname = DEFAULT_HOSTNAME;
+ } else {
+ // if no other name can be determined
+ // fall back on the current hostname
+ hostname = getText();
+ }
+ }
+ setText(hostname);
+ }
+ }
+
+ @Override
+ public void setText(String text) {
+ if (text == null) {
+ Log.e(TAG, "tried to set null hostname, request ignored");
+ return;
+ } else if (text.length() == 0) {
+ Log.w(TAG, "setting empty hostname");
+ } else {
+ Log.i(TAG, "hostname has been set: " + text);
+ }
+ SystemProperties.set(PROP_HOSTNAME, text);
+ persistHostname(text);
+ setSummary(text);
+ }
+
+ @Override
+ public String getText() {
+ return SystemProperties.get(PROP_HOSTNAME);
+ }
+
+ @Override
+ public void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+ String hostname = getText();
+ persistHostname(hostname);
+ }
+
+ public void persistHostname(String hostname) {
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.DEVICE_HOSTNAME, hostname);
+ }
+}
diff --git a/src/com/android/settings/IntervalSeekBar.java b/src/com/android/settings/IntervalSeekBar.java
new file mode 100644
index 00000000000..5fbdb81d2d4
--- /dev/null
+++ b/src/com/android/settings/IntervalSeekBar.java
@@ -0,0 +1,87 @@
+package com.android.settings;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.SeekBar;
+
+/**
+ * Custom SeekBar that allows setting both a minimum and maximum value.
+ * This also handles floating point values (to 2 decimal places) through
+ * integer conversions.
+ */
+public class IntervalSeekBar extends SeekBar {
+ private float mMin;
+ private float mMax;
+ private float mDefault;
+ private float mMultiplier;
+
+ public IntervalSeekBar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ TypedArray seekBarType = context.obtainStyledAttributes(attrs,
+ R.styleable.IntervalSeekBar, 0, 0);
+
+ mMax = seekBarType.getFloat(R.styleable.IntervalSeekBar_max, 1.5f);
+ mMin = seekBarType.getFloat(R.styleable.IntervalSeekBar_min, 0.5f);
+ mDefault = seekBarType.getFloat(R.styleable.IntervalSeekBar_defaultValue, 1.0f);
+
+ int digits = seekBarType.getInt(R.styleable.IntervalSeekBar_digits, 0);
+ mMultiplier = (float) Math.pow(10, digits);
+
+ if (mMin > mMax) {
+ float temp = mMax;
+ mMax = mMin;
+ mMin = temp;
+ }
+
+ setMax(convertFloatToProgress(mMax));
+ setProgressFloat(mDefault);
+
+ seekBarType.recycle();
+ }
+
+ /*
+ * Converts from SeekBar units (which the SeekBar uses), to scale units
+ * (which are saved).
+ * This operation is the inverse of setFontScaling.
+ */
+ public float getProgressFloat() {
+ return (getProgress() / mMultiplier) + mMin;
+ }
+
+ /*
+ * Converts from scale units (which are saved), to SeekBar units
+ * (which the SeekBar uses). This also sets the SeekBar progress.
+ * This operation is the inverse of getProgressFloat.
+ */
+ public void setProgressFloat(float progress) {
+ setProgress(convertFloatToProgress(progress));
+ }
+
+ private int convertFloatToProgress(float value) {
+ return Math.round((value - mMin) * mMultiplier);
+ }
+
+ public float getMinimum() {
+ return mMin;
+ }
+
+ public float getMaximum() {
+ return mMax;
+ }
+
+ public float getDefault() {
+ return mDefault;
+ }
+
+ public void setMaximum(float max) {
+ mMax = max;
+ setMax(convertFloatToProgress(mMax));
+ }
+
+ public void setMinimum(float min) {
+ mMin = min;
+ }
+}
diff --git a/src/com/android/settings/KeyguardAppWidgetPickActivity.java b/src/com/android/settings/KeyguardAppWidgetPickActivity.java
index 7e801be0fc9..a15b2ba5fed 100644
--- a/src/com/android/settings/KeyguardAppWidgetPickActivity.java
+++ b/src/com/android/settings/KeyguardAppWidgetPickActivity.java
@@ -123,6 +123,9 @@ protected void onCreate(Bundle savedInstanceState) {
mAppWidgetAdapter = new AppWidgetAdapter(this, mItems);
mGridView.setAdapter(mAppWidgetAdapter);
mGridView.setOnItemClickListener(this);
+ mGridView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
mLockPatternUtils = new LockPatternUtils(this); // TEMP-- we want to delete this
}
diff --git a/src/com/android/settings/RingerVolumePreference.java b/src/com/android/settings/RingerVolumePreference.java
index 5d4c85614ff..557d79c2a9b 100644
--- a/src/com/android/settings/RingerVolumePreference.java
+++ b/src/com/android/settings/RingerVolumePreference.java
@@ -20,12 +20,15 @@
import com.android.internal.telephony.TelephonyIntents;
+import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.DialogInterface;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.net.Uri;
@@ -34,6 +37,7 @@
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
+import android.preference.CheckBoxPreference;
import android.preference.VolumePreference;
import android.provider.Settings;
import android.provider.Settings.System;
@@ -57,6 +61,11 @@ public class RingerVolumePreference extends VolumePreference {
private static final int MSG_RINGER_MODE_CHANGED = 101;
private SeekBarVolumizer [] mSeekBarVolumizer;
+ private CheckBox mSafeHeadsetVolume;
+
+ // To track whether a confirmation dialog was clicked.
+ private boolean mDialogClicked;
+ private Dialog mWaiverDialog;
// These arrays must all match in length and order
private static final int[] SEEKBAR_ID = new int[] {
@@ -164,6 +173,13 @@ public RingerVolumePreference(Context context, AttributeSet attrs) {
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}
+ private static int getCurrentMutableStreams(Context c) {
+ final int defaultMuteStreams = ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
+ (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED));
+ return Settings.System.getInt(c.getContentResolver(),
+ Settings.System.MODE_RINGER_STREAMS_AFFECTED, defaultMuteStreams);
+ }
+
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
@@ -187,6 +203,9 @@ protected void onBindDialogView(View view) {
}
final CheckBox linkCheckBox = (CheckBox) view.findViewById(R.id.link_ring_and_volume);
+ final CheckBox linkMuteStates = (CheckBox) view.findViewById(R.id.link_mutes);
+ final CheckBox volumeKeysControlRingStream = (CheckBox) view.findViewById(R.id.volume_keys_control_ring_stream);
+ mSafeHeadsetVolume = (CheckBox) view.findViewById(R.id.safe_headset_volume);
final View ringerSection = view.findViewById(R.id.ringer_section);
final View notificationSection = view.findViewById(R.id.notification_section);
@@ -195,15 +214,42 @@ protected void onBindDialogView(View view) {
.findViewById(R.id.ringer_description_text);
if (Utils.isVoiceCapable(getContext())) {
+ if ((getCurrentMutableStreams(getContext()) & (1 << AudioSystem.STREAM_NOTIFICATION)) != 0) {
+ linkMuteStates.setChecked(true);
+ } else {
+ linkMuteStates.setChecked(false);
+ }
+
+ linkMuteStates.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+
+ int mutedStreams = getCurrentMutableStreams(getContext());
+
+ if (isChecked) {
+ mutedStreams |= (1 << AudioSystem.STREAM_NOTIFICATION);
+ } else {
+ mutedStreams &= ~(1 << AudioSystem.STREAM_NOTIFICATION);
+ }
+ Settings.System
+ .putInt(buttonView.getContext().getContentResolver(),
+ Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+ mutedStreams);
+ }
+ });
+
if (System.getInt(getContext().getContentResolver(),
System.VOLUME_LINK_NOTIFICATION, 1) == 1) {
linkCheckBox.setChecked(true);
notificationSection.setVisibility(View.GONE);
ringerDesc.setText(R.string.volume_ring_description);
+ linkMuteStates.setEnabled(false);
} else {
linkCheckBox.setChecked(false);
notificationSection.setVisibility(View.VISIBLE);
ringerDesc.setText(R.string.volume_ring_only_description);
+ linkMuteStates.setEnabled(true);
}
linkCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@@ -213,6 +259,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
notificationSection.setVisibility(View.GONE);
ringerDesc.setText(R.string.volume_ring_description);
+ linkMuteStates.setEnabled(false);
final int volume = mAudioManager.getStreamVolume(AudioSystem.STREAM_RING);
mAudioManager.setStreamVolume(AudioSystem.STREAM_NOTIFICATION, volume, 0);
Settings.System.putInt(buttonView.getContext().getContentResolver(),
@@ -220,6 +267,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
} else {
notificationSection.setVisibility(View.VISIBLE);
ringerDesc.setText(R.string.volume_ring_only_description);
+ linkMuteStates.setEnabled(true);
Settings.System.putInt(buttonView.getContext().getContentResolver(),
Settings.System.VOLUME_LINK_NOTIFICATION, 0);
}
@@ -227,11 +275,95 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
}
});
+
+ if (System.getInt(getContext().getContentResolver(),
+ System.VOLUME_KEYS_CONTROL_RING_STREAM, 1) == 1) {
+ volumeKeysControlRingStream.setChecked(true);
+ } else {
+ volumeKeysControlRingStream.setChecked(false);
+ }
+
+ volumeKeysControlRingStream.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ Settings.System.putInt(buttonView.getContext().getContentResolver(),
+ Settings.System.VOLUME_KEYS_CONTROL_RING_STREAM, isChecked ? 1 : 0);
+ }
+
+ });
+
} else {
ringerSection.setVisibility(View.GONE);
linkVolumesSection.setVisibility(View.GONE);
}
+ // Load safe headset setting
+ boolean safeMediaVolumeEnabled = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_safe_media_volume_enabled);
+ mSafeHeadsetVolume.setChecked(Settings.System.getInt(getContext().getContentResolver(),
+ Settings.System.SAFE_HEADSET_VOLUME, safeMediaVolumeEnabled ? 1 : 0) != 0);
+ mSafeHeadsetVolume.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (!isChecked) {
+ // User is trying to disable the feature, display the waiver
+ mDialogClicked = false;
+ if (mWaiverDialog != null) {
+ dismissDialog();
+ }
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setMessage(R.string.cyanogenmod_waiver_body);
+ builder.setTitle(R.string.cyanogenmod_waiver_title);
+ builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (dialog == mWaiverDialog) {
+ if (!mDialogClicked) {
+ mSafeHeadsetVolume.setChecked(true);
+ }
+ mWaiverDialog = null;
+ }
+ }
+ });
+
+ builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (dialog == mWaiverDialog) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ mDialogClicked = true;
+ Settings.System.putInt(getContext().getContentResolver(),
+ Settings.System.SAFE_HEADSET_VOLUME, 0);
+ }
+ }
+ }
+ });
+
+ mWaiverDialog = builder.show();
+ mWaiverDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ // Assuming that onClick gets called first
+ if (dialog == mWaiverDialog) {
+ if (!mDialogClicked) {
+ mSafeHeadsetVolume.setChecked(true);
+ }
+ mWaiverDialog = null;
+ }
+ }
+ });
+ } else {
+ Settings.System.putInt(getContext().getContentResolver(),
+ Settings.System.SAFE_HEADSET_VOLUME, 1);
+ }
+ }
+ });
+
// Load initial states from AudioManager
updateSlidersAndMutedStates();
@@ -267,19 +399,13 @@ public void onReceive(Context context, Intent intent) {
view.findViewById(SEEKBAR_SECTION_ID[i]).setVisibility(View.GONE);
}
}
- } else {
- // Disable ringer or notifications if required
- int id = -1;
- if (!Utils.isVoiceCapable(getContext())) {
- id = R.id.ringer_section;
- } else if (System.getInt(getContext().getContentResolver(),
- System.VOLUME_LINK_NOTIFICATION, 1) == 1) {
- id = R.id.notification_section;
- }
- if (id != -1){
- View hideSection = view.findViewById(id);
- hideSection.setVisibility(View.GONE);
- }
+ }
+ }
+
+ private void dismissDialog() {
+ if (mWaiverDialog != null) {
+ mWaiverDialog.dismiss();
+ mWaiverDialog = null;
}
}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 39db5747ed1..22a18cffc8d 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -22,6 +22,8 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.DialogInterface;
@@ -29,6 +31,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
@@ -37,14 +40,26 @@
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceGroup;
+import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.security.KeyStore;
import android.telephony.TelephonyManager;
import android.util.Log;
+import com.android.internal.util.beanstalk.DeviceUtils;
+
import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.R;
+
+import org.regulus.amrasettings.backup.BackupService;
+import org.regulus.amrasettings.backup.NumberPickerPreference;
+import java.io.File;
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
@@ -62,15 +77,25 @@ public class SecuritySettings extends RestrictedSettingsFragment
private static final String KEY_BIOMETRIC_WEAK_LIVELINESS = "biometric_weak_liveliness";
private static final String KEY_LOCK_ENABLED = "lockenabled";
private static final String KEY_VISIBLE_PATTERN = "visiblepattern";
+ private static final String KEY_VISIBLE_GESTURE = "visiblegesture";
private static final String KEY_SECURITY_CATEGORY = "security_category";
private static final String KEY_DEVICE_ADMIN_CATEGORY = "device_admin_category";
private static final String KEY_LOCK_AFTER_TIMEOUT = "lock_after_timeout";
private static final String KEY_OWNER_INFO_SETTINGS = "owner_info_settings";
private static final String KEY_ENABLE_WIDGETS = "keyguard_enable_widgets";
+ private static final String KEY_INTERFACE_SETTINGS = "lock_screen_settings";
+ private static final String KEY_TARGET_SETTINGS = "lockscreen_targets";
+ private static final String LOCKSCREEN_QUICK_UNLOCK_CONTROL = "quick_unlock_control";
+ private static final String LOCK_NUMPAD_RANDOM = "lock_numpad_random";
+ private static final String KEY_SHAKE_TO_SECURE = "shake_to_secure";
+ private static final String KEY_SHAKE_AUTO_TIMEOUT = "shake_auto_timeout";
+ private static final String LOCK_BEFORE_UNLOCK = "lock_before_unlock";
private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123;
private static final int CONFIRM_EXISTING_FOR_BIOMETRIC_WEAK_IMPROVE_REQUEST = 124;
private static final int CONFIRM_EXISTING_FOR_BIOMETRIC_WEAK_LIVELINESS_OFF = 125;
+ private static final int CONFIRM_EXISTING_FOR_TEMPORARY_INSECURE = 126;
+ private static final int DLG_SHAKE_WARN = 0;
// Misc Settings
private static final String KEY_SIM_LOCK = "sim_lock";
@@ -85,49 +110,60 @@ public class SecuritySettings extends RestrictedSettingsFragment
private static final String KEY_NOTIFICATION_ACCESS = "manage_notification_access";
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
- // Omni Additions
- private static final String BATTERY_AROUND_LOCKSCREEN_RING = "battery_around_lockscreen_ring";
- private static final String LOCKSCREEN_MAXIMIZE_WIDGETS = "lockscreen_maximize_widgets";
- private static final String LOCKSCREEN_QUICK_UNLOCK_CONTROL = "lockscreen_quick_unlock_control";
- private static final String LOCK_NUMPAD_RANDOM = "lock_numpad_random";
- private static final String MENU_UNLOCK_PREF = "menu_unlock";
+ // Amra Additions
+ private static final String KEY_APP_SECURITY_CATEGORY = "app_security";
+ private static final String KEY_SMS_SECURITY_CHECK_PREF = "sms_security_check_limit";
+
+ // MULTIUSER
+ public static final String ALLOW_MULTIUSER = "allow_multiuser";
+ private static final String KEY_BACKUP_CATEGORY = "backup_category";
private PackageManager mPM;
private DevicePolicyManager mDPM;
+ private PreferenceGroup mSecurityCategory;
+
private ChooseLockSettingsHelper mChooseLockSettingsHelper;
private LockPatternUtils mLockPatternUtils;
private ListPreference mLockAfter;
+ private ListPreference mLockNumpadRandom;
private CheckBoxPreference mBiometricWeakLiveliness;
private CheckBoxPreference mVisiblePattern;
+ private CheckBoxPreference mVisibleGesture;
private CheckBoxPreference mShowPassword;
private KeyStore mKeyStore;
private Preference mResetCredentials;
+ private CheckBoxPreference mAllowMultiuserPreference;
private CheckBoxPreference mToggleAppInstallation;
private DialogInterface mWarnInstallApps;
private CheckBoxPreference mToggleVerifyApps;
private CheckBoxPreference mPowerButtonInstantlyLocks;
- private CheckBoxPreference mEnableKeyguardWidgets;
+ private Preference mEnableKeyguardWidgets;
+
+ private CheckBoxPreference mQuickUnlockScreen;
+
+ private CheckBoxPreference mShakeToSecure;
+ private ListPreference mShakeTimer;
+
+ private CheckBoxPreference mLockBeforeUnlock;
private Preference mNotificationAccess;
+ private Preference mLockInterface;
+ private Preference mLockTargets;
private boolean mIsPrimary;
+ // Amra Additions
+ private ListPreference mSmsSecurityCheck;
+
public SecuritySettings() {
super(null /* Don't ask for restrictions pin on creation. */);
}
- // Omni Additions
- private CheckBoxPreference mLockRingBattery;
- private CheckBoxPreference mMaximizeKeyguardWidgets;
- private CheckBoxPreference mQuickUnlockScreen;
- private ListPreference mLockNumpadRandom;
- private CheckBoxPreference mMenuUnlock;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -148,6 +184,9 @@ private PreferenceScreen createPreferenceHierarchy() {
addPreferencesFromResource(R.xml.security_settings);
root = getPreferenceScreen();
+ // Add package manager to check if features are available
+ PackageManager pm = getPackageManager();
+
// Add options for lock/unlock screen
int resid = 0;
if (!mLockPatternUtils.isSecure()) {
@@ -177,11 +216,13 @@ private PreferenceScreen createPreferenceHierarchy() {
case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
resid = R.xml.security_settings_password;
break;
+ case DevicePolicyManager.PASSWORD_QUALITY_GESTURE_WEAK:
+ resid = R.xml.security_settings_gesture;
+ break;
}
}
addPreferencesFromResource(resid);
-
// Add options for device encryption
mIsPrimary = UserHandle.myUserId() == UserHandle.USER_OWNER;
@@ -217,27 +258,12 @@ private PreferenceScreen createPreferenceHierarchy() {
updateLockAfterPreferenceSummary();
}
- // Add the additional Omni settings
- mLockRingBattery = (CheckBoxPreference) root
- .findPreference(BATTERY_AROUND_LOCKSCREEN_RING);
- if (mLockRingBattery != null) {
- mLockRingBattery.setChecked(Settings.System.getInt(getContentResolver(),
- Settings.System.BATTERY_AROUND_LOCKSCREEN_RING, 0) == 1);
- }
-
- mMaximizeKeyguardWidgets = (CheckBoxPreference) root.findPreference(LOCKSCREEN_MAXIMIZE_WIDGETS);
- if (mMaximizeKeyguardWidgets != null) {
- mMaximizeKeyguardWidgets.setChecked(Settings.System.getInt(getContentResolver(),
- Settings.System.LOCKSCREEN_MAXIMIZE_WIDGETS, 0) == 1);
- }
-
- // Menu Unlock
- mMenuUnlock = (CheckBoxPreference) root.findPreference(MENU_UNLOCK_PREF);
- if (mMenuUnlock != null) {
- final boolean configDisabled = getResources().getBoolean
- (com.android.internal.R.bool.config_disableMenuKeyInLockScreen);
- mMenuUnlock.setChecked(Settings.System.getInt(getContentResolver(),
- Settings.System.MENU_UNLOCK_SCREEN, configDisabled ? 0 : 1) == 1);
+ mAllowMultiuserPreference = (CheckBoxPreference) root.findPreference(ALLOW_MULTIUSER);
+ mAllowMultiuserPreference.setEnabled(UserHandle.myUserId() == UserHandle.USER_OWNER);
+ mAllowMultiuserPreference.setChecked(Settings.System.getIntForUser(getContentResolver(),
+ Settings.System.ALLOW_MULTIUSER, 0, UserHandle.USER_OWNER) == 1);
+ if (Utils.isTablet(getActivity())) {
+ root.removePreference(mAllowMultiuserPreference);
}
// biometric weak liveliness
@@ -247,22 +273,42 @@ private PreferenceScreen createPreferenceHierarchy() {
// visible pattern
mVisiblePattern = (CheckBoxPreference) root.findPreference(KEY_VISIBLE_PATTERN);
+ // visible gesture
+ mVisibleGesture = (CheckBoxPreference) root.findPreference(KEY_VISIBLE_GESTURE);
+
// lock instantly on power key press
mPowerButtonInstantlyLocks = (CheckBoxPreference) root.findPreference(
KEY_POWER_INSTANTLY_LOCKS);
+ mSecurityCategory = (PreferenceGroup)
+ root.findPreference(KEY_SECURITY_CATEGORY);
+ if (mSecurityCategory != null) {
+ mLockInterface = findPreference(KEY_INTERFACE_SETTINGS);
+ mLockTargets = findPreference(KEY_TARGET_SETTINGS);
+ shouldEnableTargets();
+ }
+
// don't display visible pattern if biometric and backup is not pattern
if (resid == R.xml.security_settings_biometric_weak &&
mLockPatternUtils.getKeyguardStoredPasswordQuality() !=
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
- PreferenceGroup securityCategory = (PreferenceGroup)
- root.findPreference(KEY_SECURITY_CATEGORY);
- if (securityCategory != null && mVisiblePattern != null) {
- securityCategory.removePreference(root.findPreference(KEY_VISIBLE_PATTERN));
+ if (mSecurityCategory != null && mVisiblePattern != null) {
+ mSecurityCategory.removePreference(root.findPreference(KEY_VISIBLE_PATTERN));
+ }
+ if (mSecurityCategory != null && mVisibleGesture != null) {
+ mSecurityCategory.removePreference(root.findPreference(KEY_VISIBLE_GESTURE));
}
}
- // Lock Numpad Random
+ // Quick Unlock Screen Control
+ mQuickUnlockScreen = (CheckBoxPreference) root
+ .findPreference(LOCKSCREEN_QUICK_UNLOCK_CONTROL);
+ if (mQuickUnlockScreen != null) {
+ mQuickUnlockScreen.setChecked(Settings.System.getInt(getContentResolver(),
+ Settings.System.LOCKSCREEN_QUICK_UNLOCK_CONTROL, 0) == 1);
+ }
+
+ // Lock Numpad Random
mLockNumpadRandom = (ListPreference) root.findPreference(LOCK_NUMPAD_RANDOM);
if (mLockNumpadRandom != null) {
mLockNumpadRandom.setValue(String.valueOf(
@@ -272,6 +318,45 @@ private PreferenceScreen createPreferenceHierarchy() {
mLockNumpadRandom.setOnPreferenceChangeListener(this);
}
+ // Shake to secure
+ // Don't show if device admin requires security
+ boolean shakeEnabled = mLockPatternUtils.getRequestedMinimumPasswordLength()
+ == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ mShakeToSecure = (CheckBoxPreference) root
+ .findPreference(KEY_SHAKE_TO_SECURE);
+ if (mShakeToSecure != null) {
+ mShakeToSecure.setChecked(
+ Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.LOCK_SHAKE_TEMP_SECURE, 0) == 1);
+ mShakeToSecure.setOnPreferenceChangeListener(this);
+ if (!shakeEnabled) {
+ mSecurityCategory.removePreference(mShakeToSecure);
+ }
+ }
+
+ mShakeTimer = (ListPreference) root.findPreference(KEY_SHAKE_AUTO_TIMEOUT);
+ if (mShakeTimer != null) {
+ long shakeTimer = Settings.Secure.getLongForUser(getContentResolver(),
+ Settings.Secure.LOCK_SHAKE_SECURE_TIMER, 0,
+ UserHandle.USER_CURRENT);
+ mShakeTimer.setValue(String.valueOf(shakeTimer));
+ updateShakeTimerPreferenceSummary();
+ mShakeTimer.setOnPreferenceChangeListener(this);
+ if (!shakeEnabled) {
+ mSecurityCategory.removePreference(mShakeTimer);
+ }
+ }
+
+ // Lock before Unlock
+ mLockBeforeUnlock = (CheckBoxPreference) root
+ .findPreference(LOCK_BEFORE_UNLOCK);
+ if (mLockBeforeUnlock != null) {
+ mLockBeforeUnlock.setChecked(
+ Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.LOCK_BEFORE_UNLOCK, 0) == 1);
+ mLockBeforeUnlock.setOnPreferenceChangeListener(this);
+ }
+
// Append the rest of the settings
addPreferencesFromResource(R.xml.security_settings_misc);
@@ -289,16 +374,15 @@ private PreferenceScreen createPreferenceHierarchy() {
}
}
- // Enable or disable keyguard widget checkbox based on DPM state
- mEnableKeyguardWidgets = (CheckBoxPreference) root.findPreference(KEY_ENABLE_WIDGETS);
+ // Link to widget settings showing summary about the actual status
+ // and remove them on low memory devices
+ mEnableKeyguardWidgets = root.findPreference(KEY_ENABLE_WIDGETS);
if (mEnableKeyguardWidgets != null) {
if (ActivityManager.isLowRamDeviceStatic()
|| mLockPatternUtils.isLockScreenDisabled()) {
// Widgets take a lot of RAM, so disable them on low-memory devices
- PreferenceGroup securityCategory
- = (PreferenceGroup) root.findPreference(KEY_SECURITY_CATEGORY);
- if (securityCategory != null) {
- securityCategory.removePreference(root.findPreference(KEY_ENABLE_WIDGETS));
+ if (mSecurityCategory != null) {
+ mSecurityCategory.removePreference(root.findPreference(KEY_ENABLE_WIDGETS));
mEnableKeyguardWidgets = null;
}
} else {
@@ -307,21 +391,11 @@ private PreferenceScreen createPreferenceHierarchy() {
if (disabled) {
mEnableKeyguardWidgets.setSummary(
R.string.security_enable_widgets_disabled_summary);
- } else {
- mEnableKeyguardWidgets.setSummary("");
}
mEnableKeyguardWidgets.setEnabled(!disabled);
}
}
-
- mQuickUnlockScreen = (CheckBoxPreference) root.findPreference(LOCKSCREEN_QUICK_UNLOCK_CONTROL);
- if (mQuickUnlockScreen != null) {
- mQuickUnlockScreen.setChecked(Settings.System.getInt(getContentResolver(),
- Settings.System.LOCKSCREEN_QUICK_UNLOCK_CONTROL, 0) == 1);
- mQuickUnlockScreen.setOnPreferenceChangeListener(this);
- }
-
// Show password
mShowPassword = (CheckBoxPreference) root.findPreference(KEY_SHOW_PASSWORD);
mResetCredentials = root.findPreference(KEY_RESET_CREDENTIALS);
@@ -368,6 +442,22 @@ private PreferenceScreen createPreferenceHierarchy() {
}
}
+ // App security settings
+ addPreferencesFromResource(R.xml.security_settings_app_amra);
+ mSmsSecurityCheck = (ListPreference) root.findPreference(KEY_SMS_SECURITY_CHECK_PREF);
+ // Determine options based on device telephony support
+ if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ mSmsSecurityCheck = (ListPreference) root.findPreference(KEY_SMS_SECURITY_CHECK_PREF);
+ mSmsSecurityCheck.setOnPreferenceChangeListener(this);
+ int smsSecurityCheck = Integer.valueOf(mSmsSecurityCheck.getValue());
+ updateSmsSecuritySummary(smsSecurityCheck);
+ } else {
+ // No telephony, remove dependent options
+ PreferenceGroup appCategory = (PreferenceGroup)
+ root.findPreference(KEY_APP_SECURITY_CATEGORY);
+ appCategory.removePreference(mSmsSecurityCheck);
+ }
+
mNotificationAccess = findPreference(KEY_NOTIFICATION_ACCESS);
if (mNotificationAccess != null) {
final int total = NotificationAccessSettings.getListenersCount(mPM);
@@ -410,6 +500,35 @@ private boolean isNonMarketAppsAllowed() {
Settings.Global.INSTALL_NON_MARKET_APPS, 0) > 0;
}
+ private LockPatternUtils lockPatternUtils() {
+ if (mLockPatternUtils == null) {
+ mLockPatternUtils = new LockPatternUtils(getActivity());
+ }
+ return mLockPatternUtils;
+ }
+
+ private void shouldEnableTargets() {
+ final boolean shakeToSecure = Settings.Secure.getInt(
+ getContentResolver(),
+ Settings.Secure.LOCK_SHAKE_TEMP_SECURE, 0) == 1;
+ final boolean lockBeforeUnlock = Settings.Secure.getInt(
+ getContentResolver(),
+ Settings.Secure.LOCK_BEFORE_UNLOCK, 0) == 1;
+
+ final boolean shouldEnableTargets = (shakeToSecure || lockBeforeUnlock)
+ || !lockPatternUtils().isSecure();
+ if (mLockInterface != null && mLockTargets != null) {
+ if (!DeviceUtils.isPhone(getActivity())) {
+ // Nothing for tablets and large screen devices
+ mSecurityCategory.removePreference(mLockInterface);
+ } else {
+ mSecurityCategory.removePreference(mLockTargets);
+ }
+ mLockInterface.setEnabled(shouldEnableTargets);
+ mLockTargets.setEnabled(shouldEnableTargets);
+ }
+ }
+
private void setNonMarketAppsAllowed(boolean enabled) {
final UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
if (um.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)) {
@@ -468,6 +587,13 @@ public void onDestroy() {
}
}
+ private void updateSmsSecuritySummary(int selection) {
+ String message = selection > 0
+ ? getString(R.string.sms_security_check_limit_summary, selection)
+ : getString(R.string.sms_security_check_limit_summary_none);
+ mSmsSecurityCheck.setSummary(message);
+ }
+
private void setupLockAfterPreference() {
// Compatible with pre-Froyo
long currentTimeout = Settings.Secure.getLong(getContentResolver(),
@@ -501,6 +627,23 @@ private void updateLockAfterPreferenceSummary() {
mLockAfter.setSummary(getString(R.string.lock_after_timeout_summary, entries[best]));
}
+ private void updateShakeTimerPreferenceSummary() {
+ // Update summary message with current value
+ long shakeTimer = Settings.Secure.getLongForUser(getContentResolver(),
+ Settings.Secure.LOCK_SHAKE_SECURE_TIMER, 0,
+ UserHandle.USER_CURRENT);
+ final CharSequence[] entries = mShakeTimer.getEntries();
+ final CharSequence[] values = mShakeTimer.getEntryValues();
+ int best = 0;
+ for (int i = 0; i < values.length; i++) {
+ long timeout = Long.valueOf(values[i].toString());
+ if (shakeTimer >= timeout) {
+ best = i;
+ }
+ }
+ mShakeTimer.setSummary(entries[best]);
+ }
+
private void disableUnusableTimeouts(long maxTimeout) {
final CharSequence[] entries = mLockAfter.getEntries();
final CharSequence[] values = mLockAfter.getEntryValues();
@@ -560,8 +703,12 @@ public void onResume() {
}
if (mEnableKeyguardWidgets != null) {
- mEnableKeyguardWidgets.setChecked(lockPatternUtils.getWidgetsEnabled());
- }
+ if (!lockPatternUtils.getWidgetsEnabled()) {
+ mEnableKeyguardWidgets.setSummary(R.string.disabled);
+ } else {
+ mEnableKeyguardWidgets.setSummary(R.string.enabled);
+ }
+ }
}
@Override
@@ -610,25 +757,15 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
lockPatternUtils.setLockPatternEnabled(isToggled(preference));
} else if (KEY_VISIBLE_PATTERN.equals(key)) {
lockPatternUtils.setVisiblePatternEnabled(isToggled(preference));
+ } else if (KEY_VISIBLE_GESTURE.equals(key)) {
+ lockPatternUtils.setVisibleGestureEnabled(isToggled(preference));
} else if (KEY_POWER_INSTANTLY_LOCKS.equals(key)) {
lockPatternUtils.setPowerButtonInstantlyLocks(isToggled(preference));
- } else if (KEY_ENABLE_WIDGETS.equals(key)) {
- lockPatternUtils.setWidgetsEnabled(mEnableKeyguardWidgets.isChecked());
- } else if (preference == mLockRingBattery) {
- Settings.System.putInt(getActivity().getApplicationContext().getContentResolver(),
- Settings.System.BATTERY_AROUND_LOCKSCREEN_RING, isToggled(preference) ? 1 : 0);
- } else if (preference == mMaximizeKeyguardWidgets) {
- Settings.System.putInt(getActivity().getApplicationContext().getContentResolver(),
- Settings.System.LOCKSCREEN_MAXIMIZE_WIDGETS, isToggled(preference) ? 1 : 0);
- } else if (preference == mQuickUnlockScreen) {
- Settings.System.putInt(getActivity().getApplicationContext().getContentResolver(),
- Settings.System.LOCKSCREEN_QUICK_UNLOCK_CONTROL, isToggled(preference) ? 1 : 0);
- } else if (preference == mMenuUnlock) {
- Settings.System.putInt(getActivity().getApplicationContext().getContentResolver(),
- Settings.System.MENU_UNLOCK_SCREEN, isToggled(preference) ? 1 : 0);
} else if (preference == mShowPassword) {
Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD,
mShowPassword.isChecked() ? 1 : 0);
+ } else if (mAllowMultiuserPreference == preference) {
+ handleMultiUserClick();
} else if (preference == mToggleAppInstallation) {
if (mToggleAppInstallation.isChecked()) {
mToggleAppInstallation.setChecked(false);
@@ -639,6 +776,10 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
} else if (KEY_TOGGLE_VERIFY_APPLICATIONS.equals(key)) {
Settings.Global.putInt(getContentResolver(), Settings.Global.PACKAGE_VERIFIER_ENABLE,
mToggleVerifyApps.isChecked() ? 1 : 0);
+ } else if (preference == mQuickUnlockScreen) {
+ Settings.System.putInt(getActivity().getApplicationContext().getContentResolver(),
+ Settings.System.LOCKSCREEN_QUICK_UNLOCK_CONTROL,
+ isToggled(preference) ? 1 : 0);
} else {
// If we didn't handle it, let preferences handle it.
return super.onPreferenceTreeClick(preferenceScreen, preference);
@@ -668,6 +809,15 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
// Setting the mBiometricWeakLiveliness checked value to false is handled when onResume
// is called by grabbing the value from lockPatternUtils. We can't set it here
// because mBiometricWeakLiveliness could be null
+ } else if (requestCode == CONFIRM_EXISTING_FOR_TEMPORARY_INSECURE &&
+ resultCode == Activity.RESULT_OK) {
+ // Enable shake to secure
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.LOCK_SHAKE_TEMP_SECURE, 1);
+ if (mShakeToSecure != null) {
+ mShakeToSecure.setChecked(true);
+ shouldEnableTargets();
+ }
return;
}
createPreferenceHierarchy();
@@ -684,12 +834,42 @@ public boolean onPreferenceChange(Preference preference, Object value) {
Log.e("SecuritySettings", "could not persist lockAfter timeout setting", e);
}
updateLockAfterPreferenceSummary();
- } else if (preference == mLockNumpadRandom) {
+ } else if (preference == mSmsSecurityCheck) {
+ int smsSecurityCheck = Integer.valueOf((String) value);
+ Settings.Global.putInt(getContentResolver(),
+ Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT, smsSecurityCheck);
+ updateSmsSecuritySummary(smsSecurityCheck);
+ } else if (preference == mLockNumpadRandom) {
Settings.Secure.putInt(getContentResolver(),
Settings.Secure.LOCK_NUMPAD_RANDOM,
Integer.valueOf((String) value));
mLockNumpadRandom.setValue(String.valueOf(value));
mLockNumpadRandom.setSummary(mLockNumpadRandom.getEntry());
+ } else if (preference == mShakeToSecure) {
+ boolean checked = ((Boolean) value);
+ if (checked) {
+ // Uncheck until confirmed
+ mShakeToSecure.setChecked(false);
+ showDialogInner(DLG_SHAKE_WARN);
+ } else {
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.LOCK_SHAKE_TEMP_SECURE, 0);
+ shouldEnableTargets();
+ }
+ } else if (preference == mShakeTimer) {
+ int shakeTime = Integer.parseInt((String) value);
+ try {
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.LOCK_SHAKE_SECURE_TIMER, shakeTime);
+ } catch (NumberFormatException e) {
+ Log.e("SecuritySettings", "could not persist lockAfter timeout setting", e);
+ }
+ updateShakeTimerPreferenceSummary();
+ } else if (preference == mLockBeforeUnlock) {
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.LOCK_BEFORE_UNLOCK,
+ ((Boolean) value) ? 1 : 0);
+ shouldEnableTargets();
}
return true;
}
@@ -699,9 +879,89 @@ protected int getHelpResource() {
return R.string.help_url_security;
}
+ private void handleMultiUserClick() {
+ Settings.System.putIntForUser(getContentResolver(),
+ Settings.System.ALLOW_MULTIUSER, (mAllowMultiuserPreference.isChecked() ? 1 : 0), UserHandle.USER_OWNER);
+ }
+
public void startBiometricWeakImprove(){
Intent intent = new Intent();
intent.setClassName("com.android.facelock", "com.android.facelock.AddToSetup");
startActivity(intent);
}
+
+ private void showDialogInner(int id) {
+ DialogFragment newFragment = MyAlertDialogFragment.newInstance(id);
+ newFragment.setTargetFragment(this, 0);
+ newFragment.show(getFragmentManager(), "dialog " + id);
+ }
+
+
+ public static class MyAlertDialogFragment extends DialogFragment {
+
+ public static MyAlertDialogFragment newInstance(int id) {
+ MyAlertDialogFragment frag = new MyAlertDialogFragment();
+ Bundle args = new Bundle();
+ args.putInt("id", id);
+ frag.setArguments(args);
+ return frag;
+ }
+
+ SecuritySettings getOwner() {
+ return (SecuritySettings) getTargetFragment();
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ int id = getArguments().getInt("id");
+ switch (id) {
+ case DLG_SHAKE_WARN:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.shake_to_secure_dlg_title)
+ .setMessage(R.string.shake_to_secure_dlg_message)
+ .setNegativeButton(R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ disableShakeLock();
+ }
+ })
+ .setPositiveButton(R.string.dlg_ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ ChooseLockSettingsHelper helper =
+ new ChooseLockSettingsHelper(
+ getOwner().getActivity(), getOwner());
+ if (!helper.launchConfirmationActivity(
+ getOwner().CONFIRM_EXISTING_FOR_TEMPORARY_INSECURE,
+ null, null)) {
+ // We just want the return data here
+ // this boolean may return something useful one day.
+ }
+ }
+ })
+ .create();
+ }
+ throw new IllegalArgumentException("unknown id " + id);
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ int id = getArguments().getInt("id");
+ switch (id) {
+ case DLG_SHAKE_WARN:
+ disableShakeLock();
+ break;
+ default:
+ // N/A at the moment
+ }
+ }
+
+ private void disableShakeLock() {
+ if (getOwner().mShakeToSecure != null) {
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.LOCK_SHAKE_TEMP_SECURE, 0);
+ getOwner().mShakeToSecure.setChecked(false);
+ }
+ }
+ }
}
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index d8f76759b2d..a4d2c8369c7 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -24,6 +24,7 @@
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.admin.DevicePolicyManager;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -31,9 +32,13 @@
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
+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.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.nfc.NfcAdapter;
import android.os.Bundle;
@@ -60,17 +65,22 @@
import android.widget.TextView;
import com.android.internal.util.ArrayUtils;
+import com.android.settings.ActivityPicker;
import com.android.settings.accessibility.AccessibilitySettings;
+import com.android.settings.accessibility.CaptionPropertiesFragment;
import com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment;
-import com.android.settings.accessibility.ToggleCaptioningPreferenceFragment;
import com.android.settings.accounts.AccountSyncSettings;
import com.android.settings.accounts.AuthenticatorHelper;
import com.android.settings.accounts.ManageAccountsSettings;
import com.android.settings.applications.AppOpsSummary;
import com.android.settings.applications.ManageApplications;
import com.android.settings.applications.ProcessStatsUi;
+import org.regulus.amrasettings.blacklist.BlacklistSettings;
import com.android.settings.bluetooth.BluetoothEnabler;
import com.android.settings.bluetooth.BluetoothSettings;
+import org.regulus.amrasettings.buttonsettings.ButtonSettings;
+import org.regulus.amrasettings.MoreDeviceSettings;
+import org.regulus.amrasettings.superuser.PolicyNativeFragment;
import com.android.settings.deviceinfo.Memory;
import com.android.settings.deviceinfo.UsbSettings;
import com.android.settings.fuelgauge.PowerUsageSummary;
@@ -80,10 +90,18 @@
import com.android.settings.inputmethod.UserDictionaryList;
import com.android.settings.location.LocationSettings;
import com.android.settings.nfc.AndroidBeam;
+import org.regulus.amrasettings.battery.BatteryIconStyle;
+import org.regulus.amrasettings.quiethours.QuietHours;
+import org.regulus.amrasettings.displayrotation.DisplayRotation;
+import org.regulus.amrasettings.quicksettings.QuickSettingsTiles;
import com.android.settings.nfc.PaymentSettings;
import com.android.settings.print.PrintJobSettingsFragment;
import com.android.settings.print.PrintServiceSettingsFragment;
import com.android.settings.print.PrintSettingsFragment;
+import org.regulus.amrasettings.profiles.AppGroupConfig;
+import org.regulus.amrasettings.profiles.ProfileConfig;
+import org.regulus.amrasettings.profiles.ProfileEnabler;
+import org.regulus.amrasettings.profiles.ProfilesSettings;
import com.android.settings.tts.TextToSpeechSettings;
import com.android.settings.users.UserSettings;
import com.android.settings.vpn2.VpnSettings;
@@ -92,7 +110,9 @@
import com.android.settings.wifi.WifiEnabler;
import com.android.settings.wifi.WifiSettings;
import com.android.settings.wifi.p2p.WifiP2pSettings;
-import com.android.settings.slim.QuietHours;
+
+import org.regulus.amrasettings.themetoggle.ThemeToggle;
+import org.regulus.amrasettings.themetoggle.ThemeToggleSettings;
import java.util.ArrayList;
import java.util.Collections;
@@ -122,6 +142,11 @@ public class Settings extends PreferenceActivity
private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
+ private static final String ACTION_PERFORMANCE =
+ "org.regulus.amra.amracontrol.activities.PerformanceActivity";
+ private static final String ACTION_DEVICE_CONTROL =
+ "org.regulus.amra.amracontrol.activities.MainActivity";
+
static final int DIALOG_ONLY_ONE_HOME = 1;
private static boolean sShowNoHomeNotice = false;
@@ -133,6 +158,9 @@ public class Settings extends PreferenceActivity
private Header mParentHeader;
private boolean mInLocalHeaderSwitch;
+ private int mCurrentState = 0;
+ private boolean mAttached;
+
// Show only these settings for restricted users
private int[] SETTINGS_FOR_RESTRICTED = {
R.id.wireless_section,
@@ -159,7 +187,10 @@ public class Settings extends PreferenceActivity
R.id.accessibility_settings,
R.id.print_settings,
R.id.nfc_payment_settings,
- R.id.home_settings
+ R.id.home_settings,
+ R.id.lock_screen_settings,
+ R.id.privacy_settings_amra,
+ R.id.button_settings
};
private SharedPreferences mDevelopmentPreferences;
@@ -260,38 +291,46 @@ protected void onSaveInstanceState(Bundle outState) {
public void onResume() {
super.onResume();
- mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- invalidateHeaders();
+ if (!mAttached) {
+ mAttached = true;
+ mDevelopmentPreferencesListener =
+ new SharedPreferences.OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(
+ SharedPreferences sharedPreferences, String key) {
+ invalidateHeaders();
+ }
+ };
+ mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
+ mDevelopmentPreferencesListener);
+
+ ListAdapter listAdapter = getListAdapter();
+ if (listAdapter instanceof HeaderAdapter) {
+ ((HeaderAdapter) listAdapter).resume();
}
- };
- mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
- mDevelopmentPreferencesListener);
+ invalidateHeaders();
- ListAdapter listAdapter = getListAdapter();
- if (listAdapter instanceof HeaderAdapter) {
- ((HeaderAdapter) listAdapter).resume();
+ registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
- invalidateHeaders();
-
- registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
@Override
public void onPause() {
super.onPause();
- unregisterReceiver(mBatteryInfoReceiver);
+ if (mAttached) {
+ mAttached = false;
+ unregisterReceiver(mBatteryInfoReceiver);
- ListAdapter listAdapter = getListAdapter();
- if (listAdapter instanceof HeaderAdapter) {
- ((HeaderAdapter) listAdapter).pause();
- }
+ ListAdapter listAdapter = getListAdapter();
+ if (listAdapter instanceof HeaderAdapter) {
+ ((HeaderAdapter) listAdapter).pause();
+ }
- mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
- mDevelopmentPreferencesListener);
- mDevelopmentPreferencesListener = null;
+ mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
+ mDevelopmentPreferencesListener);
+ mDevelopmentPreferencesListener = null;
+ }
}
@Override
@@ -327,12 +366,13 @@ public boolean onIsMultiPane() {
ManageApplications.class.getName(),
ProcessStatsUi.class.getName(),
NotificationStation.class.getName(),
+ AppOpsSummary.class.getName(),
LocationSettings.class.getName(),
SecuritySettings.class.getName(),
PrivacySettings.class.getName(),
DeviceAdminSettings.class.getName(),
AccessibilitySettings.class.getName(),
- ToggleCaptioningPreferenceFragment.class.getName(),
+ CaptionPropertiesFragment.class.getName(),
TextToSpeechSettings.class.getName(),
Memory.class.getName(),
DevelopmentSettings.class.getName(),
@@ -352,15 +392,28 @@ public boolean onIsMultiPane() {
TrustedCredentialsSettings.class.getName(),
PaymentSettings.class.getName(),
KeyboardLayoutPickerFragment.class.getName(),
- QuietHours.class.getName()
+ org.regulus.amrasettings.blacklist.BlacklistSettings.class.getName(),
+ ApnSettings.class.getName(),
+ org.regulus.amrasettings.quiethours.QuietHours.class.getName(),
+ org.regulus.amrasettings.quicksettings.QuickSettingsTiles.class.getName(),
+ org.regulus.amrasettings.battery.BatteryIconStyle.class.getName(),
+ org.regulus.amrasettings.displayrotation.DisplayRotation.class.getName(),
+ HomeSettings.class.getName(),
+ org.regulus.amrasettings.buttonsettings.ButtonSettings.class.getName(),
+ org.regulus.amrasettings.MoreDeviceSettings.class.getName(),
+ org.regulus.amrasettings.profiles.ProfilesSettings.class.getName(),
+ PolicyNativeFragment.class.getName(),
+ org.regulus.amrasettings.PrivacySettings.class.getName(),
+ org.regulus.amrasettings.themetoggle.ThemeToggleSettings.class.getName(),
+ org.regulus.amrasettings.theme.ThemeSettings.class.getName()
};
@Override
protected boolean isValidFragment(String fragmentName) {
// Almost all fragments are wrapped in this,
// except for a few that have their own activities.
- for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
- if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
+ for (String ENTRY_FRAGMENT : ENTRY_FRAGMENTS) {
+ if (ENTRY_FRAGMENT.equals(fragmentName)) return true;
}
return false;
}
@@ -497,27 +550,43 @@ public Header onGetInitialHeader() {
return mFirstHeader;
}
+ @Override
+ public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
+ CharSequence titleText, CharSequence shortTitleText) {
+ Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
+ titleText, shortTitleText);
+ onBuildStartFragmentIntentHelper(fragmentName, intent);
+ return intent;
+ }
+
@Override
public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
int titleRes, int shortTitleRes) {
Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
titleRes, shortTitleRes);
+ onBuildStartFragmentIntentHelper(fragmentName, intent);
+ return intent;
+ }
+ private void onBuildStartFragmentIntentHelper(String fragmentName, Intent intent) {
// Some fragments want split ActionBar; these should stay in sync with
// uiOptions for fragments also defined as activities in manifest.
if (WifiSettings.class.getName().equals(fragmentName) ||
WifiP2pSettings.class.getName().equals(fragmentName) ||
+ BlacklistSettings.class.getName().equals(fragmentName) ||
BluetoothSettings.class.getName().equals(fragmentName) ||
DreamSettings.class.getName().equals(fragmentName) ||
+ ProfilesSettings.class.getName().equals(fragmentName) ||
+ ProfileConfig.class.getName().equals(fragmentName) ||
+ AppGroupConfig.class.getName().equals(fragmentName) ||
+ HomeSettings.class.getName().equals(fragmentName) ||
LocationSettings.class.getName().equals(fragmentName) ||
ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName) ||
PrintSettingsFragment.class.getName().equals(fragmentName) ||
PrintServiceSettingsFragment.class.getName().equals(fragmentName)) {
intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
}
-
intent.setClass(this, SubSettings.class);
- return intent;
}
/**
@@ -532,9 +601,7 @@ public void onBuildHeaders(List headers) {
}
private void updateHeaderList(List target) {
- final boolean showDev = mDevelopmentPreferences.getBoolean(
- DevelopmentSettings.PREF_SHOW,
- android.os.Build.TYPE.equals("eng"));
+ final boolean showDev = (UserHandle.myUserId() == UserHandle.USER_OWNER);;
int i = 0;
final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
@@ -572,6 +639,14 @@ private void updateHeaderList(List target) {
if (!mBatteryPresent) {
target.remove(i);
}
+ } else if (id == R.id.display_settings) {
+ final Resources res = getResources();
+ boolean hasLed =
+ res.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed)
+ || res.getBoolean(com.android.internal.R.bool.config_intrusiveBatteryLed);
+ if (hasLed) {
+ header.titleRes = R.string.display_lights_settings_title;
+ }
} else if (id == R.id.account_settings) {
int headerIndex = i + 1;
i = insertAccountsHeaders(target, headerIndex);
@@ -591,8 +666,9 @@ private void updateHeaderList(List target) {
} else {
// Only show if NFC is on and we have the HCE feature
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
- if (adapter == null || !adapter.isEnabled() || !getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
+ if (adapter == null || !adapter.isEnabled()
+ || !getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
target.remove(i);
if (adapter == null) {
Log.e(LOG_TAG, "NFC feature advertised but the default adapter is NULL!");
@@ -611,11 +687,6 @@ private void updateHeaderList(List target) {
if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
target.remove(i);
}
- } else if (id == R.id.button_settings) {
- boolean hasButtonsettings = getResources().getBoolean(R.bool.config_device_has_button_settings);
- if (!hasButtonsettings){
- target.remove(i);
- }
} else if (id == R.id.supersu_settings) {
// Embedding into Settings is supported from SuperSU v1.85 and up
boolean supported = false;
@@ -710,40 +781,51 @@ public int compare(Header h1, Header h2) {
}
private boolean updateHomeSettingHeaders(Header header) {
- // Once we decide to show Home settings, keep showing it forever
- SharedPreferences sp = getSharedPreferences(HomeSettings.HOME_PREFS, Context.MODE_PRIVATE);
- if (sp.getBoolean(HomeSettings.HOME_PREFS_DO_SHOW, false)) {
- return true;
- }
-
try {
+ PackageManager pm = getPackageManager();
final ArrayList homeApps = new ArrayList();
- getPackageManager().getHomeActivities(homeApps);
+ pm.getHomeActivities(homeApps);
+
if (homeApps.size() < 2) {
- // When there's only one available home app, omit this settings
- // category entirely at the top level UI. If the user just
- // uninstalled the penultimate home app candidiate, we also
- // now tell them about why they aren't seeing 'Home' in the list.
- if (sShowNoHomeNotice) {
- sShowNoHomeNotice = false;
- NoHomeDialogFragment.show(this);
+ Intent prefsIntent = new Intent(Intent.ACTION_MAIN);
+ prefsIntent.addCategory("com.cyanogenmod.category.LAUNCHER_PREFERENCES");
+ List prefsActivities = pm.queryIntentActivities(prefsIntent, 0);
+
+ boolean hasAtleastOneSettings = false;
+ for (ResolveInfo info : homeApps) {
+ for (ResolveInfo activityInfo : prefsActivities) {
+ if (info.activityInfo.packageName
+ .equals(activityInfo.activityInfo.packageName)) {
+ hasAtleastOneSettings = true;
+ break;
+ }
+ }
}
- return false;
- } else {
- // Okay, we're allowing the Home settings category. Tell it, when
- // invoked via this front door, that we'll need to be told about the
- // case when the user uninstalls all but one home app.
- if (header.fragmentArguments == null) {
- header.fragmentArguments = new Bundle();
+ if (!hasAtleastOneSettings) {
+ // When there's only one available home app, omit this settings
+ // category entirely at the top level UI. If the user just
+ // uninstalled the penultimate home app candidiate, we also
+ // now tell them about why they aren't seeing 'Home' in the list.
+ if (sShowNoHomeNotice) {
+ sShowNoHomeNotice = false;
+ NoHomeDialogFragment.show(this);
+ }
+ return false;
}
- header.fragmentArguments.putBoolean(HomeSettings.HOME_SHOW_NOTICE, true);
}
+
+ // Okay, we're allowing the Home settings category. Tell it, when
+ // invoked via this front door, that we'll need to be told about the
+ // case when the user uninstalls all but one home app.
+ if (header.fragmentArguments == null) {
+ header.fragmentArguments = new Bundle();
+ }
+ header.fragmentArguments.putBoolean(HomeSettings.HOME_SHOW_NOTICE, true);
} catch (Exception e) {
// Can't look up the home activity; bail on configuring the icon
Log.w(LOG_TAG, "Problem looking up home activity!", e);
}
- sp.edit().putBoolean(HomeSettings.HOME_PREFS_DO_SHOW, true).apply();
return true;
}
@@ -804,6 +886,8 @@ private static class HeaderAdapter extends ArrayAdapter {
private final WifiEnabler mWifiEnabler;
private final BluetoothEnabler mBluetoothEnabler;
+ private final ProfileEnabler mProfileEnabler;
+ public static ThemeToggle mThemeToggle;
private AuthenticatorHelper mAuthHelper;
private DevicePolicyManager mDevicePolicyManager;
@@ -819,9 +903,13 @@ private static class HeaderViewHolder {
private LayoutInflater mInflater;
static int getHeaderType(Header header) {
- if (header.fragment == null && header.intent == null) {
+ if (header.fragment == null && header.intent == null && header.id != R.id.themetoggle_settings) {
return HEADER_TYPE_CATEGORY;
- } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
+ } else if (header.id == R.id.wifi_settings
+ || header.id == R.id.bluetooth_settings
+ || header.id == R.id.profiles_settings) {
+ return HEADER_TYPE_SWITCH;
+ } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings || header.id == R.id.themetoggle_settings) {
return HEADER_TYPE_SWITCH;
} else if (header.id == R.id.security_settings) {
return HEADER_TYPE_BUTTON;
@@ -867,7 +955,9 @@ public HeaderAdapter(Context context, List objects,
// Switches inflated from their layouts. Must be done before adapter is set in super
mWifiEnabler = new WifiEnabler(context, new Switch(context));
mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
+ mProfileEnabler = new ProfileEnabler(context, new Switch(context));
mDevicePolicyManager = dpm;
+ mThemeToggle = new ThemeToggle(context, new Switch(context));
}
@Override
@@ -877,7 +967,7 @@ public View getView(int position, View convertView, ViewGroup parent) {
int headerType = getHeaderType(header);
View view = null;
- if (convertView == null) {
+ if (convertView == null || headerType == HEADER_TYPE_SWITCH) {
holder = new HeaderViewHolder();
switch (headerType) {
case HEADER_TYPE_CATEGORY:
@@ -936,8 +1026,12 @@ public View getView(int position, View convertView, ViewGroup parent) {
// Would need a different treatment if the main menu had more switches
if (header.id == R.id.wifi_settings) {
mWifiEnabler.setSwitch(holder.switch_);
- } else {
+ } else if (header.id == R.id.bluetooth_settings) {
mBluetoothEnabler.setSwitch(holder.switch_);
+ } else if (header.id == R.id.profiles_settings) {
+ mProfileEnabler.setSwitch(holder.switch_);
+ } else if (header.id == R.id.themetoggle_settings) {
+ mThemeToggle.setSwitch(holder.switch_);
}
updateCommonHeaderView(header, holder);
break;
@@ -1011,11 +1105,15 @@ private void setHeaderIcon(HeaderViewHolder holder, Drawable icon) {
public void resume() {
mWifiEnabler.resume();
mBluetoothEnabler.resume();
+ mProfileEnabler.resume();
+ mThemeToggle.resume();
}
public void pause() {
mWifiEnabler.pause();
mBluetoothEnabler.pause();
+ mProfileEnabler.pause();
+ mThemeToggle.pause();
}
}
@@ -1026,6 +1124,19 @@ public void onHeaderClick(Header header, int position) {
revert = true;
}
+ // a temp hack while we prepare to switch
+ // to the new theme chooser.
+ if (header.id == R.id.theme_settings) {
+ try {
+ Intent intent = new Intent();
+ intent.setClassName("com.tmobile.themechooser", "com.tmobile.themechooser.ThemeChooser");
+ startActivity(intent);
+ return;
+ } catch(ActivityNotFoundException e) {
+ // Do nothing, we will launch the submenu
+ }
+ }
+
super.onHeaderClick(header, position);
if (revert && mLastHeader != null) {
@@ -1078,10 +1189,33 @@ public void onAccountsUpdated(Account[] accounts) {
invalidateHeaders();
}
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ if (newConfig.uiThemeMode != mCurrentState && HeaderAdapter.mThemeToggle != null) {
+ mCurrentState = newConfig.uiThemeMode;
+ HeaderAdapter.mThemeToggle.setSwitchState();
+ }
+ }
+
public static void requestHomeNotice() {
sShowNoHomeNotice = true;
}
+ /**
+ * Checks if a specific action exists.
+ * @param actionName The action as string
+ * @return if the action exists.
+ */
+ private boolean actionExists(String actionName) {
+ Intent i = new Intent();
+ i.setAction(actionName);
+ List list = getPackageManager().queryIntentActivities(i,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ return list.size() > 0;
+ }
+
/*
* Settings subclasses for launching independently.
*/
@@ -1100,12 +1234,6 @@ public static class SpellCheckersSettingsActivity extends Settings { /* empty */
public static class LocalePickerActivity extends Settings { /* empty */ }
public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
public static class SoundSettingsActivity extends Settings { /* empty */ }
- public static class QuietHoursSettingsActivity extends Settings { /* empty */ }
- public static class BarsSettingsActivity extends Settings { /* empty */ }
- public static class MenusSettingsActivity extends Settings { /* empty */ }
- public static class NotificationPanelSettingsActivity extends Settings { /* empty */ }
- public static class MoreInterfaceSettingsActivity extends Settings { /* empty */ }
- public static class ActiveDisplaySettingsActivity extends Settings { /* empty */ }
public static class DisplaySettingsActivity extends Settings { /* empty */ }
public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
public static class ApplicationSettingsActivity extends Settings { /* empty */ }
@@ -1147,5 +1275,21 @@ public static class TrustedCredentialsSettingsActivity extends Settings { /* emp
public static class PaymentSettingsActivity extends Settings { /* empty */ }
public static class PrintSettingsActivity extends Settings { /* empty */ }
public static class PrintJobSettingsActivity extends Settings { /* empty */ }
+ public static class ApnSettingsActivity extends Settings { /* empty */ }
+ public static class ApnEditorActivity extends Settings { /* empty */ }
+ /* AmraSettings */
+ public static class AmraSettingsActivity extends Settings { /* empty */ }
+ public static class BlacklistSettingsActivity extends Settings { /* empty */ }
+ public static class ProfilesSettingsActivity extends Settings { /* empty */ }
+ public static class ThemeToggleSettingsActivity extends Settings { /* empty */ }
+ public static class AnimationInterfaceSettingsActivity extends Settings { /* empty */ }
+ public static class AboutActivity extends Settings { /* empty */ }
+ public static class RamBarActivity extends Settings { /* empty */ }
+ public static class QuietHoursSettingsActivity extends Settings { /* empty */ }
+ public static class QuickSettingsTilesSettingsActivity extends Settings { /* empty */ }
+ public static class BatteryIconStyleSettingsActivity extends Settings { /* empty */ }
+ public static class DisplayRotationSettingsActivity extends Settings { /* empty */ }
public static class PerformanceSettingsActivity extends Settings { /* empty */ }
+ public static class ThemeSettingsActivity extends Settings { /* empty */ }
+
}
diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java
index 0a382b57892..0324a8d28be 100644
--- a/src/com/android/settings/SettingsPreferenceFragment.java
+++ b/src/com/android/settings/SettingsPreferenceFragment.java
@@ -23,9 +23,12 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Bundle;
+import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
@@ -49,6 +52,11 @@ public class SettingsPreferenceFragment extends PreferenceFragment implements Di
private String mHelpUrl;
+ protected Context mContext;
+
+ // Need to use AOKP Custom system animation
+ protected ContentResolver mContentRes;
+
// Cache the content resolver for async callbacks
private ContentResolver mContentResolver;
@@ -56,6 +64,11 @@ public class SettingsPreferenceFragment extends PreferenceFragment implements Di
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ mContext = getActivity().getApplicationContext();
+
+ // Need to use AOKP Custom system animation
+ mContentRes = getActivity().getContentResolver();
+
// Prepare help url and enable menu if necessary
int helpResource = getHelpResource();
if (helpResource != 0) {
@@ -318,4 +331,31 @@ public boolean startFragment(
}
}
+ // Need to AOKP Custom system animation
+ public void setTitle(int resId) {
+ getActivity().setTitle(resId);
+ }
+
+ public boolean isPackageInstalled(String packageName) {
+ if (packageName != null) {
+ try {
+ PackageInfo pi = getPackageManager().getPackageInfo(packageName, 0);
+ if (!pi.applicationInfo.enabled) {
+ return false;
+ }
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ protected boolean isCheckBoxPrefernceChecked(Preference p) {
+ if(p instanceof CheckBoxPreference) {
+ return ((CheckBoxPreference) p).isChecked();
+ } else {
+ return false;
+ }
+ }
}
diff --git a/src/com/android/settings/SmsDefaultDialog.java b/src/com/android/settings/SmsDefaultDialog.java
index d9a6c5f3790..3a3848ba4f7 100644
--- a/src/com/android/settings/SmsDefaultDialog.java
+++ b/src/com/android/settings/SmsDefaultDialog.java
@@ -64,7 +64,7 @@ public void onClick(DialogInterface dialog, int which) {
private boolean buildDialog(String packageName) {
TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
- if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE) {
+ if (!tm.isSmsCapable()) {
// No phone, no SMS
return false;
}
diff --git a/src/com/android/settings/SoundSettings.java b/src/com/android/settings/SoundSettings.java
index 0564cb91864..5adf9a0cd45 100644
--- a/src/com/android/settings/SoundSettings.java
+++ b/src/com/android/settings/SoundSettings.java
@@ -18,6 +18,7 @@
import com.android.settings.bluetooth.DockEventReceiver;
+import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.bluetooth.BluetoothDevice;
@@ -31,25 +32,35 @@
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.media.AudioManager;
+import android.media.Ringtone;
import android.media.RingtoneManager;
import android.media.audiofx.AudioEffect;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.os.SystemProperties;
import android.os.Vibrator;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
+import android.preference.PreferenceCategory;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.provider.MediaStore;
import android.provider.Settings;
import android.telephony.TelephonyManager;
+import android.text.format.DateFormat;
import android.util.Log;
+import android.view.VolumePanel;
+import java.util.Date;
+import java.util.Calendar;
import java.util.List;
+import org.regulus.amrasettings.utils.SeekBarPreference;
+import org.regulus.amrasettings.utils.SeekBarPreferenceAmra;
+
public class SoundSettings extends SettingsPreferenceFragment implements
Preference.OnPreferenceChangeListener {
private static final String TAG = "SoundSettings";
@@ -59,45 +70,68 @@ public class SoundSettings extends SettingsPreferenceFragment implements
/** If there is no setting in the provider, use this. */
private static final int FALLBACK_EMERGENCY_TONE_VALUE = 0;
+ private static final String KEY_VOLUME_OVERLAY = "volume_overlay";
+ private static final String KEY_RING_MODE = "ring_mode";
private static final String KEY_VIBRATE = "vibrate_when_ringing";
private static final String KEY_RING_VOLUME = "ring_volume";
+ private static final String KEY_INCREASING_RING = "increasing_ring";
private static final String KEY_MUSICFX = "musicfx";
- private static final String KEY_DTMF_TONE = "dtmf_tone";
- private static final String KEY_SOUND_EFFECTS = "sound_effects";
- private static final String KEY_HAPTIC_FEEDBACK = "haptic_feedback";
+ private static final String KEY_DTMF_TONE = Settings.System.DTMF_TONE_WHEN_DIALING;
+ private static final String KEY_SOUND_EFFECTS = Settings.System.SOUND_EFFECTS_ENABLED;
+ private static final String KEY_HAPTIC_FEEDBACK = Settings.System.HAPTIC_FEEDBACK_ENABLED;
private static final String KEY_EMERGENCY_TONE = "emergency_tone";
private static final String KEY_SOUND_SETTINGS = "sound_settings";
- private static final String KEY_LOCK_SOUNDS = "lock_sounds";
- private static final String KEY_VOLUME_ADJUST_SOUNDS = "volume_adjust_sounds";
+ private static final String KEY_LOCK_SOUNDS = Settings.System.LOCKSCREEN_SOUNDS_ENABLED;
private static final String KEY_RINGTONE = "ringtone";
private static final String KEY_NOTIFICATION_SOUND = "notification_sound";
- private static final String KEY_ALARM_SOUND = "alarm_sound";
private static final String KEY_CATEGORY_CALLS = "category_calls_and_notification";
private static final String KEY_DOCK_CATEGORY = "dock_category";
private static final String KEY_DOCK_AUDIO_SETTINGS = "dock_audio";
private static final String KEY_DOCK_SOUNDS = "dock_sounds";
private static final String KEY_DOCK_AUDIO_MEDIA_ENABLED = "dock_audio_media_enabled";
- private static final String KEY_VOLUME_PANEL_STYLE = "volume_panel_style";
+ private static final String KEY_QUIET_HOURS = "quiet_hours";
+ private static final String KEY_CONVERT_SOUND_TO_VIBRATE =
+ Settings.System.NOTIFICATION_CONVERT_SOUND_TO_VIBRATION;
+ private static final String KEY_VIBRATE_DURING_CALLS =
+ Settings.System.NOTIFICATION_VIBRATE_DURING_ALERTS_DISABLED;
+ private static final String KEY_VOLUME_ADJUST_SOUNDS = "volume_adjust_sounds_enabled";
+ private static final String KEY_CAMERA_SOUNDS = "camera_click_sound";
+ private static final String PROP_CAMERA_SOUND = "persist.sys.camera-sound";
+ private static final String KEY_VIBRATION_DURATION = "vibration_duration";
+ private static final String KEY_VOLUME_PANEL_TIMEOUT = "volume_panel_timeout";
+
+ private static final String KEY_POWER_NOTIFICATIONS = "power_notifications";
+ private static final String KEY_POWER_NOTIFICATIONS_VIBRATE = "power_notifications_vibrate";
+ private static final String KEY_POWER_NOTIFICATIONS_RINGTONE = "power_notifications_ringtone";
+
+ private static final String RING_MODE_NORMAL = "normal";
+ private static final String RING_MODE_VIBRATE = "vibrate";
+ private static final String RING_MODE_MUTE = "mute";
private static final String[] NEED_VOICE_CAPABILITY = {
KEY_RINGTONE, KEY_DTMF_TONE, KEY_CATEGORY_CALLS,
- KEY_EMERGENCY_TONE, KEY_VIBRATE
+ KEY_EMERGENCY_TONE, KEY_INCREASING_RING, KEY_VIBRATE
};
private static final int MSG_UPDATE_RINGTONE_SUMMARY = 1;
private static final int MSG_UPDATE_NOTIFICATION_SUMMARY = 2;
- private static final int MSG_UPDATE_ALARM_SUMMARY = 3;
- private ListPreference mVolumePanelStyle;
- private CheckBoxPreference mVibrateWhenRinging;
- private CheckBoxPreference mDtmfTone;
+ // Request code for power notification ringtone picker
+ private static final int REQUEST_CODE_POWER_NOTIFICATIONS_RINGTONE = 1;
+
+ // Used for power notification uri string if set to silent
+ private static final String POWER_NOTIFICATIONS_SILENT_URI = "silent";
+
+ private ListPreference mVolumeOverlay;
+ private ListPreference mRingMode;
private CheckBoxPreference mSoundEffects;
- private CheckBoxPreference mHapticFeedback;
+ private ListPreference mCameraSounds;
private Preference mMusicFx;
- private CheckBoxPreference mLockSounds;
private Preference mRingtonePreference;
private Preference mNotificationPreference;
- private Preference mAlarmPreference;
+ private PreferenceScreen mQuietHours;
+ private SeekBarPreference mVibrationDuration;
+ private SeekBarPreferenceAmra mVolumePanelTimeout;
private Runnable mRingtoneLookupRunnable;
@@ -108,8 +142,13 @@ public class SoundSettings extends SettingsPreferenceFragment implements
private Intent mDockIntent;
private CheckBoxPreference mDockAudioMediaEnabled;
- private CheckBoxPreference mVolumeAdustSound;
-
+ private CheckBoxPreference mPowerSounds;
+ private CheckBoxPreference mPowerSoundsVibrate;
+ private Preference mPowerSoundsRingtone;
+
+ private Vibrator mVib;
+ private boolean mFirstVibration = false;
+
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -119,9 +158,6 @@ public void handleMessage(Message msg) {
case MSG_UPDATE_NOTIFICATION_SUMMARY:
mNotificationPreference.setSummary((CharSequence) msg.obj);
break;
- case MSG_UPDATE_ALARM_SUMMARY:
- mAlarmPreference.setSummary((CharSequence) msg.obj);
- break;
}
}
};
@@ -131,6 +167,8 @@ public void handleMessage(Message msg) {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_DOCK_EVENT)) {
handleDockChange(intent);
+ } else if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
+ updateState(false);
}
}
};
@@ -145,6 +183,8 @@ public void onCreate(Bundle savedInstanceState) {
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ mVib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
+
addPreferencesFromResource(R.xml.sound_settings);
if (TelephonyManager.PHONE_TYPE_CDMA != activePhoneType) {
@@ -152,54 +192,68 @@ public void onCreate(Bundle savedInstanceState) {
getPreferenceScreen().removePreference(findPreference(KEY_EMERGENCY_TONE));
}
+ mVolumeOverlay = (ListPreference) findPreference(KEY_VOLUME_OVERLAY);
+ mVolumeOverlay.setOnPreferenceChangeListener(this);
+ int volumeOverlay = Settings.System.getInt(getContentResolver(),
+ Settings.System.MODE_VOLUME_OVERLAY,
+ VolumePanel.VOLUME_OVERLAY_EXPANDABLE);
+ mVolumeOverlay.setValue(Integer.toString(volumeOverlay));
+ mVolumeOverlay.setSummary(mVolumeOverlay.getEntry());
+
+ mVolumePanelTimeout = (SeekBarPreferenceAmra) findPreference(KEY_VOLUME_PANEL_TIMEOUT);
+
+ int statusVolumePanelTimeout = Settings.System.getInt(resolver,
+ Settings.System.VOLUME_PANEL_TIMEOUT, 3000);
+ mVolumePanelTimeout.setValue(statusVolumePanelTimeout / 1000);
+ mVolumePanelTimeout.setOnPreferenceChangeListener(this);
+
+ mRingMode = (ListPreference) findPreference(KEY_RING_MODE);
if (!getResources().getBoolean(R.bool.has_silent_mode)) {
+ getPreferenceScreen().removePreference(mRingMode);
findPreference(KEY_RING_VOLUME).setDependency(null);
+ } else {
+ mRingMode.setOnPreferenceChangeListener(this);
}
- mVolumePanelStyle = (ListPreference) findPreference(KEY_VOLUME_PANEL_STYLE);
-
if (getResources().getBoolean(com.android.internal.R.bool.config_useFixedVolume)) {
// device with fixed volume policy, do not display volumes submenu
getPreferenceScreen().removePreference(findPreference(KEY_RING_VOLUME));
- getPreferenceScreen().removePreference(findPreference(KEY_VOLUME_PANEL_STYLE));
+ getPreferenceScreen().removePreference(findPreference(KEY_VOLUME_PANEL_TIMEOUT));
+ }
+
+ mQuietHours = (PreferenceScreen) findPreference(KEY_QUIET_HOURS);
+ if (Settings.System.getInt(resolver, Settings.System.QUIET_HOURS_ENABLED, 0) == 1) {
+ mQuietHours.setSummary(getString(R.string.quiet_hours_active_from) + " " +
+ returnTime(Settings.System.getString(resolver, Settings.System.QUIET_HOURS_START))
+ + " " + getString(R.string.quiet_hours_active_to) + " " +
+ returnTime(Settings.System.getString(resolver, Settings.System.QUIET_HOURS_END)));
} else {
- int statusVolumePanelStyle = Settings.System.getInt(resolver,
- Settings.System.MODE_VOLUME_OVERLAY, 1);
- mVolumePanelStyle.setValue(String.valueOf(statusVolumePanelStyle));
- mVolumePanelStyle.setOnPreferenceChangeListener(this);
+ mQuietHours.setSummary(getString(R.string.quiet_hours_summary));
}
- mVibrateWhenRinging = (CheckBoxPreference) findPreference(KEY_VIBRATE);
- mVibrateWhenRinging.setPersistent(false);
- mVibrateWhenRinging.setChecked(Settings.System.getInt(resolver,
- Settings.System.VIBRATE_WHEN_RINGING, 0) != 0);
-
- mDtmfTone = (CheckBoxPreference) findPreference(KEY_DTMF_TONE);
- mDtmfTone.setPersistent(false);
- mDtmfTone.setChecked(Settings.System.getInt(resolver,
- Settings.System.DTMF_TONE_WHEN_DIALING, 1) != 0);
mSoundEffects = (CheckBoxPreference) findPreference(KEY_SOUND_EFFECTS);
- mSoundEffects.setPersistent(false);
- mSoundEffects.setChecked(Settings.System.getInt(resolver,
- Settings.System.SOUND_EFFECTS_ENABLED, 1) != 0);
- mHapticFeedback = (CheckBoxPreference) findPreference(KEY_HAPTIC_FEEDBACK);
- mHapticFeedback.setPersistent(false);
- mHapticFeedback.setChecked(Settings.System.getInt(resolver,
- Settings.System.HAPTIC_FEEDBACK_ENABLED, 1) != 0);
- mLockSounds = (CheckBoxPreference) findPreference(KEY_LOCK_SOUNDS);
- mLockSounds.setPersistent(false);
- mLockSounds.setChecked(Settings.System.getInt(resolver,
- Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) != 0);
+ if (!Utils.hasVolumeRocker(getActivity())) {
+ getPreferenceScreen().removePreference(findPreference(KEY_VOLUME_ADJUST_SOUNDS));
+ }
+
+ mCameraSounds = (ListPreference) findPreference(KEY_CAMERA_SOUNDS);
+ mCameraSounds.setOnPreferenceChangeListener(this);
+ final int currentCamSound = SystemProperties.getInt(PROP_CAMERA_SOUND, 1);
+ mCameraSounds.setValue(Integer.toString(currentCamSound));
+ mCameraSounds.setSummary(mCameraSounds.getEntry());
+
+ int userMillis = Settings.System.getInt(resolver,
+ Settings.System.MINIMUM_VIBRATION_DURATION, 0);
+ mVibrationDuration = (SeekBarPreference) findPreference(KEY_VIBRATION_DURATION);
+ mVibrationDuration.setInterval(1);
+ mVibrationDuration.setDefault(0);
+ mVibrationDuration.isMilliseconds(true);
+ mVibrationDuration.setInitValue(userMillis);
+ mVibrationDuration.setOnPreferenceChangeListener(this);
+
mRingtonePreference = findPreference(KEY_RINGTONE);
mNotificationPreference = findPreference(KEY_NOTIFICATION_SOUND);
- mAlarmPreference = findPreference(KEY_ALARM_SOUND);
-
- Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
- if (vibrator == null || !vibrator.hasVibrator()) {
- removePreference(KEY_VIBRATE);
- removePreference(KEY_HAPTIC_FEEDBACK);
- }
if (TelephonyManager.PHONE_TYPE_CDMA == activePhoneType) {
ListPreference emergencyTonePreference =
@@ -213,15 +267,13 @@ public void onCreate(Bundle savedInstanceState) {
mMusicFx = mSoundSettings.findPreference(KEY_MUSICFX);
Intent i = new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL);
+ mMusicFx.setIntent(i);
PackageManager p = getPackageManager();
- List ris = p.queryIntentActivities(i, PackageManager.GET_DISABLED_COMPONENTS);
- if (ris.size() <= 2) {
- // no need to show the item if there is no choice for the user to make
- // note: the built in musicfx panel has two activities (one being a
- // compatibility shim that launches either the other activity, or a
- // third party one), hence the check for <=2. If the implementation
- // of the compatbility layer changes, this check may need to be updated.
+ List ris = p.queryIntentActivities(i, 0);
+ if (ris.size() == 0) {
mSoundSettings.removePreference(mMusicFx);
+ } else if (ris.size() == 1) {
+ mMusicFx.setSummary(ris.get(0).loadLabel(p));
}
if (!Utils.isVoiceCapable(getActivity())) {
@@ -231,6 +283,7 @@ public void onCreate(Bundle savedInstanceState) {
getPreferenceScreen().removePreference(pref);
}
}
+ mRingtonePreference = null;
}
mRingtoneLookupRunnable = new Runnable() {
@@ -243,29 +296,64 @@ public void run() {
updateRingtoneName(RingtoneManager.TYPE_NOTIFICATION, mNotificationPreference,
MSG_UPDATE_NOTIFICATION_SUMMARY);
}
- if (mAlarmPreference != null) {
- updateRingtoneName(RingtoneManager.TYPE_ALARM, mAlarmPreference,
- MSG_UPDATE_ALARM_SUMMARY);
- }
}
};
+ // power state change notification sounds
+ mPowerSounds = (CheckBoxPreference) findPreference(KEY_POWER_NOTIFICATIONS);
+ mPowerSounds.setChecked(Settings.Global.getInt(resolver,
+ Settings.Global.POWER_NOTIFICATIONS_ENABLED, 0) != 0);
+ mPowerSoundsVibrate = (CheckBoxPreference) findPreference(KEY_POWER_NOTIFICATIONS_VIBRATE);
+ mPowerSoundsVibrate.setChecked(Settings.Global.getInt(resolver,
+ Settings.Global.POWER_NOTIFICATIONS_VIBRATE, 0) != 0);
+
+ mPowerSoundsRingtone = findPreference(KEY_POWER_NOTIFICATIONS_RINGTONE);
+ String currentPowerRingtonePath =
+ Settings.Global.getString(resolver, Settings.Global.POWER_NOTIFICATIONS_RINGTONE);
+
+ // set to default notification if we don't yet have one
+ if (currentPowerRingtonePath == null) {
+ currentPowerRingtonePath = Settings.System.DEFAULT_NOTIFICATION_URI.toString();
+ Settings.Global.putString(getContentResolver(),
+ Settings.Global.POWER_NOTIFICATIONS_RINGTONE, currentPowerRingtonePath);
+ }
+ // is it silent ?
+ if (currentPowerRingtonePath.equals(POWER_NOTIFICATIONS_SILENT_URI)) {
+ mPowerSoundsRingtone.setSummary(
+ getString(R.string.power_notifications_ringtone_silent));
+ } else {
+ final Ringtone ringtone =
+ RingtoneManager.getRingtone(getActivity(), Uri.parse(currentPowerRingtonePath));
+ if (ringtone != null) {
+ mPowerSoundsRingtone.setSummary(ringtone.getTitle(getActivity()));
+ }
+ }
+
+ if (mVib == null || !mVib.hasVibrator()) {
+ removePreference(KEY_VIBRATE);
+ removePreference(KEY_HAPTIC_FEEDBACK);
+ removePreference(KEY_CONVERT_SOUND_TO_VIBRATE);
+ removePreference(KEY_VIBRATE_DURING_CALLS);
+ removePreference(KEY_VIBRATION_DURATION);
+ removePreference(KEY_POWER_NOTIFICATIONS_VIBRATE);
+ }
+
initDockSettings();
-
- mVolumeAdustSound = (CheckBoxPreference) findPreference(KEY_VOLUME_ADJUST_SOUNDS);
- mVolumeAdustSound.setPersistent(false);
- mVolumeAdustSound.setChecked(Settings.System.getInt(resolver,
- Settings.System.VOLUME_ADJUST_SOUNDS_ENABLED, 1) == 1);
}
@Override
public void onResume() {
super.onResume();
+ updateState(true);
lookupRingtoneNames();
IntentFilter filter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
getActivity().registerReceiver(mReceiver, filter);
+
+ filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+ getActivity().registerReceiver(mReceiver, filter);
+
}
@Override
@@ -275,6 +363,48 @@ public void onPause() {
getActivity().unregisterReceiver(mReceiver);
}
+ private void setPhoneRingModeValue(String value) {
+ int ringerMode = AudioManager.RINGER_MODE_NORMAL;
+ if (value.equals(RING_MODE_MUTE)) {
+ ringerMode = AudioManager.RINGER_MODE_SILENT;
+ } else if (value.equals(RING_MODE_VIBRATE)) {
+ ringerMode = AudioManager.RINGER_MODE_VIBRATE;
+ }
+ mAudioManager.setRingerMode(ringerMode);
+ }
+
+ private String getPhoneRingModeSettingValue() {
+ switch (mAudioManager.getRingerMode()) {
+ case AudioManager.RINGER_MODE_NORMAL:
+ return RING_MODE_NORMAL;
+ case AudioManager.RINGER_MODE_VIBRATE:
+ return RING_MODE_VIBRATE;
+ case AudioManager.RINGER_MODE_SILENT:
+ return RING_MODE_MUTE;
+ }
+ // Shouldn't happen
+ return RING_MODE_NORMAL;
+ }
+
+ // updateState in fact updates the UI to reflect the system state
+ private void updateState(boolean force) {
+ if (getActivity() == null) return;
+ ContentResolver resolver = getContentResolver();
+
+ mRingMode.setValue(getPhoneRingModeSettingValue());
+
+ if (Settings.System.getInt(resolver, Settings.System.QUIET_HOURS_ENABLED, 0) == 1) {
+ mQuietHours.setSummary(getString(R.string.quiet_hours_active_from) + " " +
+ returnTime(Settings.System.getString(resolver, Settings.System.QUIET_HOURS_START))
+ + " " + getString(R.string.quiet_hours_active_to) + " " +
+ returnTime(Settings.System.getString(resolver, Settings.System.QUIET_HOURS_END)));
+ } else {
+ mQuietHours.setSummary(getString(R.string.quiet_hours_summary));
+ }
+
+ mRingMode.setSummary(mRingMode.getEntry());
+ }
+
private void updateRingtoneName(int type, Preference preference, int msg) {
if (preference == null) return;
Context context = getActivity();
@@ -308,30 +438,12 @@ private void lookupRingtoneNames() {
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
- if (preference == mVibrateWhenRinging) {
- Settings.System.putInt(getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING,
- mVibrateWhenRinging.isChecked() ? 1 : 0);
- } else if (preference == mDtmfTone) {
- Settings.System.putInt(getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING,
- mDtmfTone.isChecked() ? 1 : 0);
-
- } else if (preference == mSoundEffects) {
+ if (preference == mSoundEffects) {
if (mSoundEffects.isChecked()) {
mAudioManager.loadSoundEffects();
} else {
mAudioManager.unloadSoundEffects();
}
- Settings.System.putInt(getContentResolver(), Settings.System.SOUND_EFFECTS_ENABLED,
- mSoundEffects.isChecked() ? 1 : 0);
-
- } else if (preference == mHapticFeedback) {
- Settings.System.putInt(getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED,
- mHapticFeedback.isChecked() ? 1 : 0);
-
- } else if (preference == mLockSounds) {
- Settings.System.putInt(getContentResolver(), Settings.System.LOCKSCREEN_SOUNDS_ENABLED,
- mLockSounds.isChecked() ? 1 : 0);
-
} else if (preference == mMusicFx) {
// let the framework fire off the intent
return false;
@@ -365,13 +477,25 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
} else if (preference == mDockAudioMediaEnabled) {
Settings.Global.putInt(getContentResolver(), Settings.Global.DOCK_AUDIO_MEDIA_ENABLED,
mDockAudioMediaEnabled.isChecked() ? 1 : 0);
- } else if (preference == mVolumeAdustSound) {
- Settings.System.putInt(getContentResolver(), Settings.System.VOLUME_ADJUST_SOUNDS_ENABLED,
- mVolumeAdustSound.isChecked() ? 1 : 0);
+ } else if (preference == mPowerSounds) {
+ Settings.Global.putInt(getContentResolver(),
+ Settings.Global.POWER_NOTIFICATIONS_ENABLED,
+ mPowerSounds.isChecked() ? 1 : 0);
+
+ } else if (preference == mPowerSoundsVibrate) {
+ Settings.Global.putInt(getContentResolver(),
+ Settings.Global.POWER_NOTIFICATIONS_VIBRATE,
+ mPowerSoundsVibrate.isChecked() ? 1 : 0);
+
+ } else if (preference == mPowerSoundsRingtone) {
+ launchNotificationSoundPicker(REQUEST_CODE_POWER_NOTIFICATIONS_RINGTONE,
+ Settings.Global.getString(getContentResolver(),
+ Settings.Global.POWER_NOTIFICATIONS_RINGTONE));
} else {
// If we didn't handle it, let preferences handle it.
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
+
return true;
}
@@ -385,15 +509,52 @@ public boolean onPreferenceChange(Preference preference, Object objValue) {
} catch (NumberFormatException e) {
Log.e(TAG, "could not persist emergency tone setting", e);
}
- } else if (preference == mVolumePanelStyle) {
- int volumePanelStyle = Integer.valueOf((String) objValue);
+ } else if (preference == mRingMode) {
+ setPhoneRingModeValue(objValue.toString());
+ } else if (preference == mVolumeOverlay) {
+ final int value = Integer.valueOf((String) objValue);
+ final int index = mVolumeOverlay.findIndexOfValue((String) objValue);
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.MODE_VOLUME_OVERLAY, value);
+ mVolumeOverlay.setSummary(mVolumeOverlay.getEntries()[index]);
+ } else if (preference == mVolumePanelTimeout) {
+ int volumePanelTimeout = (Integer) objValue;
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.VOLUME_PANEL_TIMEOUT, volumePanelTimeout * 1000);
+ } else if (preference == mVibrationDuration) {
+ int value = Integer.parseInt((String) objValue);
Settings.System.putInt(getContentResolver(),
- Settings.System.MODE_VOLUME_OVERLAY, volumePanelStyle);
+ Settings.System.MINIMUM_VIBRATION_DURATION, value);
+ if (mFirstVibration && (value % 5 == 0) && mVib != null) {
+ mVib.vibrate(1);
+ }
+ mFirstVibration = true;
+ } else if (preference == mCameraSounds) {
+ final int value = Integer.valueOf((String)objValue);
+ final int index = mCameraSounds.findIndexOfValue((String) objValue);
+ SystemProperties.set(PROP_CAMERA_SOUND, (String)objValue);
+ mCameraSounds.setSummary(mCameraSounds.getEntries()[index]);
}
return true;
}
+ private String returnTime(String t) {
+ if (t == null || t.equals("")) {
+ return "";
+ }
+ int hr = Integer.parseInt(t.trim());
+ int mn = hr;
+
+ hr = hr / 60;
+ mn = mn % 60;
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.HOUR_OF_DAY, hr);
+ cal.set(Calendar.MINUTE, mn);
+ Date date = cal.getTime();
+ return DateFormat.getTimeFormat(getActivity()).format(date);
+ }
+
@Override
protected int getHelpResource() {
return R.string.help_url_sound;
@@ -465,6 +626,60 @@ private void handleDockChange(Intent intent) {
}
}
+ private void launchNotificationSoundPicker(int code, String currentPowerRingtonePath) {
+ final Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
+
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE,
+ getString(R.string.power_notifications_ringtone_title));
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE,
+ RingtoneManager.TYPE_NOTIFICATION);
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI,
+ Settings.System.DEFAULT_NOTIFICATION_URI);
+ if (currentPowerRingtonePath != null &&
+ !currentPowerRingtonePath.equals(POWER_NOTIFICATIONS_SILENT_URI)) {
+ Uri uri = Uri.parse(currentPowerRingtonePath);
+ if (uri != null) {
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, uri);
+ }
+ }
+ startActivityForResult(intent, code);
+ }
+
+ private void setPowerNotificationRingtone(Intent intent) {
+ final Uri uri = intent.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
+
+ final String toneName;
+ final String toneUriPath;
+
+ if ( uri != null ) {
+ final Ringtone ringtone = RingtoneManager.getRingtone(getActivity(), uri);
+ toneName = ringtone.getTitle(getActivity());
+ toneUriPath = uri.toString();
+ } else {
+ // silent
+ toneName = getString(R.string.power_notifications_ringtone_silent);
+ toneUriPath = POWER_NOTIFICATIONS_SILENT_URI;
+ }
+
+ mPowerSoundsRingtone.setSummary(toneName);
+ Settings.Global.putString(getContentResolver(),
+ Settings.Global.POWER_NOTIFICATIONS_RINGTONE, toneUriPath);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case REQUEST_CODE_POWER_NOTIFICATIONS_RINGTONE:
+ if (resultCode == Activity.RESULT_OK) {
+ setPowerNotificationRingtone(data);
+ }
+ break;
+ default:
+ super.onActivityResult(requestCode, resultCode, data);
+ break;
+ }
+ }
+
@Override
public Dialog onCreateDialog(int id) {
if (id == DIALOG_NOT_DOCKED) {
diff --git a/src/com/android/settings/SubSettings.java b/src/com/android/settings/SubSettings.java
index 34e9ba3a707..1e02c624a84 100644
--- a/src/com/android/settings/SubSettings.java
+++ b/src/com/android/settings/SubSettings.java
@@ -17,7 +17,9 @@
package com.android.settings;
import android.app.Fragment;
+import android.app.FragmentManager;
import android.util.Log;
+import android.view.MenuItem;
import com.android.settings.ChooseLockGeneric.ChooseLockGenericFragment;
@@ -26,10 +28,11 @@
* since for our app it is a special singleTask class.
*/
public class SubSettings extends Settings {
-
@Override
public boolean onNavigateUp() {
- finish();
+ if (!popFragment()) {
+ finish();
+ }
return true;
}
@@ -38,4 +41,13 @@ protected boolean isValidFragment(String fragmentName) {
Log.d("SubSettings", "Launching fragment " + fragmentName);
return true;
}
+
+ private boolean popFragment() {
+ FragmentManager fm = getFragmentManager();
+ if (fm.getBackStackEntryCount() > 0) {
+ fm.popBackStack();
+ return true;
+ }
+ return false;
+ }
}
diff --git a/src/com/android/settings/TetherSettings.java b/src/com/android/settings/TetherSettings.java
index f0b6b44e035..4e0933d534a 100644
--- a/src/com/android/settings/TetherSettings.java
+++ b/src/com/android/settings/TetherSettings.java
@@ -387,6 +387,8 @@ private void updateBluetoothState(String[] available, String[] tethered,
}
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter == null)
+ return;
int btState = adapter.getState();
if (btState == BluetoothAdapter.STATE_TURNING_OFF) {
mBluetoothTether.setEnabled(false);
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 71299dcd3ac..d4c99188c04 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -24,13 +24,12 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
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.content.pm.UserInfo;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.database.Cursor;
@@ -58,10 +57,9 @@
import android.provider.ContactsContract.RawContacts;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
-import android.util.Log;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.view.DisplayInfo;
-import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -70,6 +68,10 @@
import com.android.settings.users.ProfileUpdateReceiver;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -80,6 +82,8 @@
public class Utils {
+ private static final String TAG = "Utils";
+
/**
* Set the preference's title to the matching activity's label.
*/
@@ -195,8 +199,7 @@ public static boolean updatePreferenceToSpecificActivityOrRemove(Context context
public static boolean updatePreferenceToSpecificActivityFromMetaDataOrRemove(Context context,
PreferenceGroup parentPreferenceGroup, String preferenceKey) {
- IconPreferenceScreen preference = (IconPreferenceScreen)parentPreferenceGroup
- .findPreference(preferenceKey);
+ Preference preference = parentPreferenceGroup.findPreference(preferenceKey);
if (preference == null) {
return false;
}
@@ -222,7 +225,9 @@ public static boolean updatePreferenceToSpecificActivityFromMetaDataOrRemove(Con
Bundle metaData = resolveInfo.activityInfo.metaData;
if (res != null && metaData != null) {
- icon = res.getDrawable(metaData.getInt(META_DATA_PREFERENCE_ICON));
+ if (preference instanceof IconPreferenceScreen) {
+ icon = res.getDrawable(metaData.getInt(META_DATA_PREFERENCE_ICON));
+ }
title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE));
summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY));
}
@@ -239,9 +244,12 @@ public static boolean updatePreferenceToSpecificActivityFromMetaDataOrRemove(Con
}
// Set icon, title and summary for the preference
- preference.setIcon(icon);
preference.setTitle(title);
preference.setSummary(summary);
+ if (preference instanceof IconPreferenceScreen) {
+ IconPreferenceScreen iconPreference = (IconPreferenceScreen) preference;
+ iconPreference.setIcon(icon);
+ }
// Replace the intent with this specific activity
preference.setIntent(new Intent().setClassName(
@@ -501,6 +509,43 @@ public static int getTetheringLabel(ConnectivityManager cm) {
}
}
+ public static boolean fileExists(String filename) {
+ return new File(filename).exists();
+ }
+
+ public static String fileReadOneLine(String fname) {
+ BufferedReader br;
+ String line = null;
+
+ try {
+ br = new BufferedReader(new FileReader(fname), 512);
+ try {
+ line = br.readLine();
+ } finally {
+ br.close();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "IO Exception when reading /sys/ file", e);
+ }
+ return line;
+ }
+
+ public static boolean fileWriteOneLine(String fname, String value) {
+ try {
+ FileWriter fw = new FileWriter(fname);
+ try {
+ fw.write(value);
+ } finally {
+ fw.close();
+ }
+ } catch (IOException e) {
+ String Error = "Error writing to " + fname + ". Exception: ";
+ Log.e(TAG, Error, e);
+ return false;
+ }
+ return true;
+ }
+
/* Used by UserSettings as well. Call this on a non-ui thread. */
public static boolean copyMeProfilePhoto(Context context, UserInfo user) {
Uri contactUri = Profile.CONTENT_URI;
@@ -652,36 +697,24 @@ public static boolean isTablet(Context context) {
return getScreenType(context) == DEVICE_TABLET;
}
- /**
- * Locks the activity orientation to the current device orientation
- * @param activity
- */
- public static void lockCurrentOrientation(Activity activity) {
- int currentRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
- int orientation = activity.getResources().getConfiguration().orientation;
- int frozenRotation = 0;
- switch (currentRotation) {
- case Surface.ROTATION_0:
- frozenRotation = orientation == Configuration.ORIENTATION_LANDSCAPE
- ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
- : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
- break;
- case Surface.ROTATION_90:
- frozenRotation = orientation == Configuration.ORIENTATION_PORTRAIT
- ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
- : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
- break;
- case Surface.ROTATION_180:
- frozenRotation = orientation == Configuration.ORIENTATION_LANDSCAPE
- ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
- : ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
- break;
- case Surface.ROTATION_270:
- frozenRotation = orientation == Configuration.ORIENTATION_PORTRAIT
- ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
- : ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
- break;
+ /* returns whether the device has volume rocker or not. */
+ public static boolean hasVolumeRocker(Context context) {
+ return context.getResources().getBoolean(R.bool.has_volume_rocker);
+ }
+
+ public static boolean isPackageInstalled(Context context, String pkg) {
+ if (pkg == null) {
+ return false;
+ }
+ try {
+ PackageInfo pi = context.getPackageManager().getPackageInfo(pkg, 0);
+ if (!pi.applicationInfo.enabled) {
+ return false;
+ } else {
+ return true;
+ }
+ } catch (NameNotFoundException e) {
+ return false;
}
- activity.setRequestedOrientation(frozenRotation);
}
}
diff --git a/src/com/android/settings/WirelessSettings.java b/src/com/android/settings/WirelessSettings.java
index 65127b5773f..9d3a8586284 100644
--- a/src/com/android/settings/WirelessSettings.java
+++ b/src/com/android/settings/WirelessSettings.java
@@ -22,6 +22,7 @@
import android.app.Dialog;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -46,10 +47,13 @@
import com.android.internal.telephony.SmsApplication;
import com.android.internal.telephony.SmsApplication.SmsApplicationData;
+import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
import com.android.settings.nfc.NfcEnabler;
+import com.android.internal.telephony.PhoneConstants;
+
import java.util.Collection;
public class WirelessSettings extends RestrictedSettingsFragment
@@ -66,14 +70,22 @@ public class WirelessSettings extends RestrictedSettingsFragment
private static final String KEY_MOBILE_NETWORK_SETTINGS = "mobile_network_settings";
private static final String KEY_MANAGE_MOBILE_PLAN = "manage_mobile_plan";
private static final String KEY_SMS_APPLICATION = "sms_application";
+ private static final String KEY_VOICE_PLUS_ACCOUNT = "voice_plus";
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_SHOW_LTE_OR_FOURGEE = "show_lte_or_fourgee";
+ private static final String KEY_CONNECTION_MANAGER = "connection_manager";
+
+ private static final String GOOGLE_VOICE_PACKAGE = "com.google.android.apps.googlevoice";
+ private static final ComponentName VOICE_PLUS_SETUP =
+ new ComponentName("org.cyanogenmod.voiceplus", "org.cyanogenmod.voiceplus.VoicePlusSetup");
public static final String EXIT_ECM_RESULT = "exit_ecm_result";
public static final int REQUEST_CODE_EXIT_ECM = 1;
private AirplaneModeEnabler mAirplaneModeEnabler;
private CheckBoxPreference mAirplaneModePreference;
+ private CheckBoxPreference mShowLTEorFourGee;
private NfcEnabler mNfcEnabler;
private NfcAdapter mNfcAdapter;
private NsdEnabler mNsdEnabler;
@@ -109,6 +121,16 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
return true;
} else if (preference == findPreference(KEY_MANAGE_MOBILE_PLAN)) {
onManageMobilePlanClick();
+ } else if (preference == mShowLTEorFourGee) {
+ Settings.System.putBoolean(getActivity().getApplicationContext().getContentResolver(),
+ Settings.System.SHOW_LTE_OR_FOURGEE,
+ ((CheckBoxPreference) preference).isChecked());
+ return true;
+ } else if (preference == findPreference(KEY_VOICE_PLUS_ACCOUNT)) {
+ Intent chooseVoicePlusAccount = new Intent();
+ chooseVoicePlusAccount.setComponent(VOICE_PLUS_SETUP);
+ chooseVoicePlusAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(chooseVoicePlusAccount);
}
// Let the intents be launched by the Preference manager
return super.onPreferenceTreeClick(preferenceScreen, preference);
@@ -247,7 +269,7 @@ public static boolean isRadioAllowed(Context context, String type) {
private boolean isSmsSupported() {
// Some tablet has sim card but could not do telephony operations. Skip those.
- return (mTm.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE);
+ return mTm.isSmsCapable();
}
@Override
@@ -328,10 +350,16 @@ public void onCreate(Bundle savedInstanceState) {
mNfcEnabler = null;
}
- // Remove Mobile Network Settings and Manage Mobile Plan if it's a wifi-only device.
+ // Remove Connection Manager on CDMA devices
+ if (mTm.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
+ removePreference(KEY_CONNECTION_MANAGER);
+ }
+
+ // Remove Mobile Network Settings, Manage Mobile Plan and Connection Manager if it's a wifi-only device.
if (isSecondaryUser || Utils.isWifiOnly(getActivity())) {
removePreference(KEY_MOBILE_NETWORK_SETTINGS);
removePreference(KEY_MANAGE_MOBILE_PLAN);
+ removePreference(KEY_CONNECTION_MANAGER);
}
// Remove Mobile Network Settings and Manage Mobile Plan
// if config_show_mobile_plan sets false.
@@ -351,6 +379,11 @@ public void onCreate(Bundle savedInstanceState) {
removePreference(KEY_SMS_APPLICATION);
}
+ // Remove Voice+ option if Google Voice is not installed
+ if (!isPackageInstalled(GOOGLE_VOICE_PACKAGE)) {
+ removePreference(KEY_VOICE_PLUS_ACCOUNT);
+ }
+
// Remove Airplane Mode settings if it's a stationary device such as a TV.
if (getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
removePreference(KEY_TOGGLE_AIRPLANE);
@@ -376,18 +409,22 @@ public void onCreate(Bundle savedInstanceState) {
protectByRestrictions(KEY_TETHER_SETTINGS);
// Enable link to CMAS app settings depending on the value in config.xml.
- boolean isCellBroadcastAppLinkEnabled = this.getResources().getBoolean(
- com.android.internal.R.bool.config_cellBroadcastAppLinks);
- try {
- if (isCellBroadcastAppLinkEnabled) {
- PackageManager pm = getPackageManager();
- if (pm.getApplicationEnabledSetting("com.android.cellbroadcastreceiver")
- == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
- isCellBroadcastAppLinkEnabled = false; // CMAS app disabled
+ PackageManager pm = getPackageManager();
+ // boolean hasPhoneFeatures = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+ boolean isCellBroadcastAppLinkEnabled = false;
+ if (isSmsSupported()) {
+ isCellBroadcastAppLinkEnabled = this.getResources().getBoolean(
+ com.android.internal.R.bool.config_cellBroadcastAppLinks);
+ try {
+ if (isCellBroadcastAppLinkEnabled) {
+ if (pm.getApplicationEnabledSetting("com.android.cellbroadcastreceiver")
+ == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
+ isCellBroadcastAppLinkEnabled = false; // CMAS app disabled
+ }
}
+ } catch (IllegalArgumentException ignored) {
+ isCellBroadcastAppLinkEnabled = false; // CMAS app not installed
}
- } catch (IllegalArgumentException ignored) {
- isCellBroadcastAppLinkEnabled = false; // CMAS app not installed
}
if (isSecondaryUser || !isCellBroadcastAppLinkEnabled) {
PreferenceScreen root = getPreferenceScreen();
@@ -395,6 +432,19 @@ public void onCreate(Bundle savedInstanceState) {
if (ps != null) root.removePreference(ps);
}
protectByRestrictions(KEY_CELL_BROADCAST_SETTINGS);
+
+ mShowLTEorFourGee = (CheckBoxPreference) findPreference(KEY_SHOW_LTE_OR_FOURGEE);
+ mShowLTEorFourGee.setChecked(Settings.System.getBoolean(getActivity().
+ getApplicationContext().getContentResolver(),
+ Settings.System.SHOW_LTE_OR_FOURGEE, false));
+ if (!deviceSupportsLTE()) {
+ getPreferenceScreen().removePreference(mShowLTEorFourGee);
+ }
+ }
+
+ private boolean deviceSupportsLTE() {
+ return (TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE
+ || TelephonyManager.getLteOnGsmModeStatic() != 0);
}
@Override
diff --git a/src/com/android/settings/WrappingCheckBoxPreference.java b/src/com/android/settings/WrappingCheckBoxPreference.java
new file mode 100644
index 00000000000..6c3b2e03a25
--- /dev/null
+++ b/src/com/android/settings/WrappingCheckBoxPreference.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 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.content.Context;
+import android.preference.CheckBoxPreference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+public class WrappingCheckBoxPreference extends CheckBoxPreference {
+
+ public WrappingCheckBoxPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public WrappingCheckBoxPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+
+ TextView title = (TextView) view.findViewById(android.R.id.title);
+ if (title != null) {
+ title.setSingleLine(false);
+ title.setMaxLines(3);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 4d24d096850..ed643864d98 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -43,6 +43,7 @@
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.Log;
+import android.view.Gravity;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
@@ -56,8 +57,8 @@
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
+import org.regulus.amrasettings.utils.SeekBarPreference;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -103,6 +104,12 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
"captioning_preference_screen";
private static final String DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN =
"screen_magnification_preference_screen";
+ private static final String RECENT_PANEL_LEFTY_MODE =
+ "recent_panel_lefty_mode";
+ private static final String RECENT_PANEL_SCALE =
+ "recent_panel_scale";
+ private static final String RECENT_PANEL_EXPANDED_MODE =
+ "recent_panel_expanded_mode";
// Extras passed to sub-fragments.
static final String EXTRA_PREFERENCE_KEY = "preference_key";
@@ -119,6 +126,9 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
// presentation.
private static final long DELAY_UPDATE_SERVICES_MILLIS = 1000;
+ // Default longpress duration
+ private static final int LONGPRESS_TIME_DEFAULT = 500;
+
// Dialog IDs.
private static final int DIALOG_ID_NO_ACCESSIBILITY_SERVICES = 1;
@@ -128,9 +138,6 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
static final Set sInstalledServices = new HashSet();
- private final Map mLongPressTimeoutValuetoTitleMap =
- new HashMap();
-
private final Configuration mCurConfig = new Configuration();
private final Handler mHandler = new Handler();
@@ -193,13 +200,14 @@ public void onChange() {
private CheckBoxPreference mTogglePowerButtonEndsCallPreference;
private CheckBoxPreference mToggleLockScreenRotationPreference;
private CheckBoxPreference mToggleSpeakPasswordPreference;
- private ListPreference mSelectLongPressTimeoutPreference;
+ private SeekBarPreference mSelectLongPressTimeoutPreference;
private Preference mNoServicesMessagePreference;
private PreferenceScreen mCaptioningPreferenceScreen;
private PreferenceScreen mDisplayMagnificationPreferenceScreen;
private PreferenceScreen mGlobalGesturePreferenceScreen;
-
- private int mLongPressTimeoutDefault;
+ private CheckBoxPreference mRecentPanelLeftyMode;
+ private ListPreference mRecentPanelScale;
+ private ListPreference mRecentPanelExpandedMode;
@Override
public void onCreate(Bundle icicle) {
@@ -241,8 +249,21 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
String stringValue = (String) newValue;
Settings.Secure.putInt(getContentResolver(),
Settings.Secure.LONG_PRESS_TIMEOUT, Integer.parseInt(stringValue));
- mSelectLongPressTimeoutPreference.setSummary(
- mLongPressTimeoutValuetoTitleMap.get(stringValue));
+ return true;
+ } else if (preference == mRecentPanelScale) {
+ int value = Integer.parseInt((String) newValue);
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.RECENT_PANEL_SCALE_FACTOR, value);
+ return true;
+ } else if (preference == mRecentPanelExpandedMode) {
+ int value = Integer.parseInt((String) newValue);
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.RECENT_PANEL_EXPANDED_MODE, value);
+ return true;
+ } else if (preference == mRecentPanelLeftyMode) {
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.RECENT_PANEL_GRAVITY,
+ ((Boolean) newValue) ? Gravity.LEFT : Gravity.RIGHT);
return true;
}
return false;
@@ -353,19 +374,13 @@ private void initializeAllPreferences() {
// Long press timeout.
mSelectLongPressTimeoutPreference =
- (ListPreference) findPreference(SELECT_LONG_PRESS_TIMEOUT_PREFERENCE);
+ (SeekBarPreference) findPreference(SELECT_LONG_PRESS_TIMEOUT_PREFERENCE);
+ mSelectLongPressTimeoutPreference.setDefault(LONGPRESS_TIME_DEFAULT);
+ mSelectLongPressTimeoutPreference.isMilliseconds(true);
+ mSelectLongPressTimeoutPreference.setInterval(1);
+ mSelectLongPressTimeoutPreference.minimumValue(80);
+ mSelectLongPressTimeoutPreference.multiplyValue(20);
mSelectLongPressTimeoutPreference.setOnPreferenceChangeListener(this);
- if (mLongPressTimeoutValuetoTitleMap.size() == 0) {
- String[] timeoutValues = getResources().getStringArray(
- R.array.long_press_timeout_selector_values);
- mLongPressTimeoutDefault = Integer.parseInt(timeoutValues[0]);
- String[] timeoutTitles = getResources().getStringArray(
- R.array.long_press_timeout_selector_titles);
- final int timeoutValueCount = timeoutValues.length;
- for (int i = 0; i < timeoutValueCount; i++) {
- mLongPressTimeoutValuetoTitleMap.put(timeoutValues[i], timeoutTitles[i]);
- }
- }
// Captioning.
mCaptioningPreferenceScreen = (PreferenceScreen) findPreference(
@@ -387,6 +402,19 @@ private void initializeAllPreferences() {
// nor long press power does not show global actions menu.
mSystemsCategory.removePreference(mGlobalGesturePreferenceScreen);
}
+
+ mRecentPanelLeftyMode =
+ (CheckBoxPreference) findPreference(RECENT_PANEL_LEFTY_MODE);
+ mRecentPanelLeftyMode.setOnPreferenceChangeListener(this);
+
+ mRecentPanelScale =
+ (ListPreference) findPreference(RECENT_PANEL_SCALE);
+ mRecentPanelScale.setOnPreferenceChangeListener(this);
+
+ mRecentPanelExpandedMode =
+ (ListPreference) findPreference(RECENT_PANEL_EXPANDED_MODE);
+ mRecentPanelExpandedMode.setOnPreferenceChangeListener(this);
+
}
private void updateAllPreferences() {
@@ -513,10 +541,9 @@ private void updateSystemPreferences() {
// Long press timeout.
final int longPressTimeout = Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.LONG_PRESS_TIMEOUT, mLongPressTimeoutDefault);
- String value = String.valueOf(longPressTimeout);
- mSelectLongPressTimeoutPreference.setValue(value);
- mSelectLongPressTimeoutPreference.setSummary(mLongPressTimeoutValuetoTitleMap.get(value));
+ Settings.Secure.LONG_PRESS_TIMEOUT, LONGPRESS_TIME_DEFAULT);
+ // Minimum 80 is 4 intervals of the 20 multiplier
+ mSelectLongPressTimeoutPreference.setInitValue((longPressTimeout / 20) - 4);
// Captioning.
final boolean captioningEnabled = Settings.Secure.getInt(getContentResolver(),
@@ -548,6 +575,19 @@ private void updateSystemPreferences() {
mGlobalGesturePreferenceScreen.setSummary(
R.string.accessibility_global_gesture_preference_summary_off);
}
+
+ final boolean recentLeftyMode = Settings.System.getInt(getContentResolver(),
+ Settings.System.RECENT_PANEL_GRAVITY, Gravity.RIGHT) == Gravity.LEFT;
+ mRecentPanelLeftyMode.setChecked(recentLeftyMode);
+
+ final int recentScale = Settings.System.getInt(getContentResolver(),
+ Settings.System.RECENT_PANEL_SCALE_FACTOR, 100);
+ mRecentPanelScale.setValue(recentScale + "");
+
+ final int recentExpandedMode = Settings.System.getInt(getContentResolver(),
+ Settings.System.RECENT_PANEL_EXPANDED_MODE, 0);
+ mRecentPanelExpandedMode.setValue(recentExpandedMode + "");
+
}
private void updateLockScreenRotationCheckbox() {
diff --git a/src/com/android/settings/accessibility/CaptionPropertiesFragment.java b/src/com/android/settings/accessibility/CaptionPropertiesFragment.java
index b010ca8c8c1..8a08d90edfe 100644
--- a/src/com/android/settings/accessibility/CaptionPropertiesFragment.java
+++ b/src/com/android/settings/accessibility/CaptionPropertiesFragment.java
@@ -16,6 +16,8 @@
package com.android.settings.accessibility;
+import android.app.ActionBar;
+import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
@@ -24,22 +26,46 @@
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceCategory;
+import android.preference.PreferenceFrameLayout;
import android.preference.Preference.OnPreferenceChangeListener;
import android.provider.Settings;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
import android.view.accessibility.CaptioningManager;
import android.view.accessibility.CaptioningManager.CaptionStyle;
+import com.android.internal.widget.SubtitleView;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.accessibility.ListDialogPreference.OnValueChangedListener;
+import com.android.settings.accessibility.ToggleSwitch.OnBeforeCheckedChangeListener;
+
+import java.util.Locale;
/**
* Settings fragment containing captioning properties.
*/
public class CaptionPropertiesFragment extends SettingsPreferenceFragment
implements OnPreferenceChangeListener, OnValueChangedListener {
- private ToggleCaptioningPreferenceFragment mParent;
+ private static final String PREF_BACKGROUND_COLOR = "captioning_background_color";
+ private static final String PREF_BACKGROUND_OPACITY = "captioning_background_opacity";
+ private static final String PREF_FOREGROUND_COLOR = "captioning_foreground_color";
+ private static final String PREF_FOREGROUND_OPACITY = "captioning_foreground_opacity";
+ private static final String PREF_EDGE_COLOR = "captioning_edge_color";
+ private static final String PREF_EDGE_TYPE = "captioning_edge_type";
+ private static final String PREF_FONT_SIZE = "captioning_font_size";
+ private static final String PREF_TYPEFACE = "captioning_typeface";
+ private static final String PREF_LOCALE = "captioning_locale";
+ private static final String PREF_PRESET = "captioning_preset";
+ private static final String PREF_CUSTOM = "custom";
+
+ private static final float DEFAULT_FONT_SIZE = 48f;
+
private CaptioningManager mCaptioningManager;
+ private SubtitleView mPreviewText;
// Standard options.
private LocalePreference mLocale;
@@ -49,6 +75,7 @@ public class CaptionPropertiesFragment extends SettingsPreferenceFragment
// Custom options.
private ListPreference mTypeface;
private ColorPreference mForegroundColor;
+ private ColorPreference mForegroundOpacity;
private EdgeTypePreference mEdgeType;
private ColorPreference mEdgeColor;
private ColorPreference mBackgroundColor;
@@ -70,35 +97,137 @@ public void onCreate(Bundle icicle) {
installUpdateListeners();
}
- /**
- * Sets the parent fragment, which is used to update the live preview.
- *
- * @param parent the parent fragment
- */
- public void setParent(ToggleCaptioningPreferenceFragment parent) {
- mParent = parent;
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ final View rootView = inflater.inflate(R.layout.captioning_preview, container, false);
+
+ // We have to do this now because PreferenceFrameLayout looks at it
+ // only when the view is added.
+ if (container instanceof PreferenceFrameLayout) {
+ ((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true;
+ }
+
+ final View content = super.onCreateView(inflater, container, savedInstanceState);
+ ((ViewGroup) rootView.findViewById(R.id.properties_fragment)).addView(
+ content, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+
+ return rootView;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ mPreviewText = (SubtitleView) view.findViewById(R.id.preview_text);
+
+ installActionBarToggleSwitch();
+ refreshPreviewText();
+ }
+
+ private void refreshPreviewText() {
+ final Context context = getActivity();
+ if (context == null) {
+ // We've been destroyed, abort!
+ return;
+ }
+
+ final SubtitleView preview = mPreviewText;
+ if (preview != null) {
+ final int styleId = mCaptioningManager.getRawUserStyle();
+ applyCaptionProperties(mCaptioningManager, preview, styleId);
+
+ final Locale locale = mCaptioningManager.getLocale();
+ if (locale != null) {
+ final CharSequence localizedText = AccessibilityUtils.getTextForLocale(
+ context, locale, R.string.captioning_preview_text);
+ preview.setText(localizedText);
+ } else {
+ preview.setText(R.string.captioning_preview_text);
+ }
+ }
+ }
+
+ public static void applyCaptionProperties(
+ CaptioningManager manager, SubtitleView previewText, int styleId) {
+ previewText.setStyle(styleId);
+
+ final Context context = previewText.getContext();
+ final ContentResolver cr = context.getContentResolver();
+ final float fontScale = manager.getFontScale();
+ previewText.setTextSize(fontScale * DEFAULT_FONT_SIZE);
+
+ final Locale locale = manager.getLocale();
+ if (locale != null) {
+ final CharSequence localizedText = AccessibilityUtils.getTextForLocale(
+ context, locale, R.string.captioning_preview_characters);
+ previewText.setText(localizedText);
+ } else {
+ previewText.setText(R.string.captioning_preview_characters);
+ }
+ }
+
+ private void installActionBarToggleSwitch() {
+ final Activity activity = getActivity();
+ final ToggleSwitch toggleSwitch = new ToggleSwitch(activity);
+
+ final int padding = getResources().getDimensionPixelSize(
+ R.dimen.action_bar_switch_padding);
+ toggleSwitch.setPaddingRelative(0, 0, padding, 0);
+
+ final ActionBar actionBar = activity.getActionBar();
+ actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM);
+
+ final ActionBar.LayoutParams params = new ActionBar.LayoutParams(
+ ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT,
+ Gravity.CENTER_VERTICAL | Gravity.END);
+ actionBar.setCustomView(toggleSwitch, params);
+
+ final boolean enabled = mCaptioningManager.isEnabled();
+ getPreferenceScreen().setEnabled(enabled);
+ mPreviewText.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
+ toggleSwitch.setCheckedInternal(enabled);
+ toggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
+ @Override
+ public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
+ toggleSwitch.setCheckedInternal(checked);
+ Settings.Secure.putInt(getActivity().getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, checked ? 1 : 0);
+ getPreferenceScreen().setEnabled(checked);
+ mPreviewText.setVisibility(checked ? View.VISIBLE : View.INVISIBLE);
+ return false;
+ }
+ });
}
private void initializeAllPreferences() {
- mLocale = (LocalePreference) findPreference("captioning_locale");
- mFontSize = (ListPreference) findPreference("captioning_font_size");
+ mLocale = (LocalePreference) findPreference(PREF_LOCALE);
+ mFontSize = (ListPreference) findPreference(PREF_FONT_SIZE);
final Resources res = getResources();
final int[] presetValues = res.getIntArray(R.array.captioning_preset_selector_values);
final String[] presetTitles = res.getStringArray(R.array.captioning_preset_selector_titles);
- mPreset = (PresetPreference) findPreference("captioning_preset");
+ mPreset = (PresetPreference) findPreference(PREF_PRESET);
mPreset.setValues(presetValues);
mPreset.setTitles(presetTitles);
- mCustom = (PreferenceCategory) findPreference("custom");
+ mCustom = (PreferenceCategory) findPreference(PREF_CUSTOM);
mShowingCustom = true;
final int[] colorValues = res.getIntArray(R.array.captioning_color_selector_values);
final String[] colorTitles = res.getStringArray(R.array.captioning_color_selector_titles);
- mForegroundColor = (ColorPreference) mCustom.findPreference("captioning_foreground_color");
+ mForegroundColor = (ColorPreference) mCustom.findPreference(PREF_FOREGROUND_COLOR);
mForegroundColor.setTitles(colorTitles);
mForegroundColor.setValues(colorValues);
- mEdgeColor = (ColorPreference) mCustom.findPreference("captioning_edge_color");
+
+ final int[] opacityValues = res.getIntArray(R.array.captioning_opacity_selector_values);
+ final String[] opacityTitles = res.getStringArray(
+ R.array.captioning_opacity_selector_titles);
+ mForegroundOpacity = (ColorPreference) mCustom.findPreference(PREF_FOREGROUND_OPACITY);
+ mForegroundOpacity.setTitles(opacityTitles);
+ mForegroundOpacity.setValues(opacityValues);
+
+ mEdgeColor = (ColorPreference) mCustom.findPreference(PREF_EDGE_COLOR);
mEdgeColor.setTitles(colorTitles);
mEdgeColor.setValues(colorValues);
@@ -109,25 +238,22 @@ private void initializeAllPreferences() {
System.arraycopy(colorTitles, 0, bgColorTitles, 1, colorTitles.length);
bgColorValues[0] = Color.TRANSPARENT;
bgColorTitles[0] = getString(R.string.color_none);
- mBackgroundColor = (ColorPreference) mCustom.findPreference("captioning_background_color");
+ mBackgroundColor = (ColorPreference) mCustom.findPreference(PREF_BACKGROUND_COLOR);
mBackgroundColor.setTitles(bgColorTitles);
mBackgroundColor.setValues(bgColorValues);
- final int[] opacityValues = res.getIntArray(R.array.captioning_opacity_selector_values);
- final String[] opacityTitles = res.getStringArray(
- R.array.captioning_opacity_selector_titles);
- mBackgroundOpacity = (ColorPreference) mCustom.findPreference(
- "captioning_background_opacity");
+ mBackgroundOpacity = (ColorPreference) mCustom.findPreference(PREF_BACKGROUND_OPACITY);
mBackgroundOpacity.setTitles(opacityTitles);
mBackgroundOpacity.setValues(opacityValues);
- mEdgeType = (EdgeTypePreference) mCustom.findPreference("captioning_edge_type");
- mTypeface = (ListPreference) mCustom.findPreference("captioning_typeface");
+ mEdgeType = (EdgeTypePreference) mCustom.findPreference(PREF_EDGE_TYPE);
+ mTypeface = (ListPreference) mCustom.findPreference(PREF_TYPEFACE);
}
private void installUpdateListeners() {
mPreset.setOnValueChangedListener(this);
mForegroundColor.setOnValueChangedListener(this);
+ mForegroundOpacity.setOnValueChangedListener(this);
mEdgeColor.setOnValueChangedListener(this);
mBackgroundColor.setOnValueChangedListener(this);
mBackgroundOpacity.setOnValueChangedListener(this);
@@ -147,22 +273,11 @@ private void updateAllPreferences() {
final ContentResolver cr = getContentResolver();
final CaptionStyle attrs = CaptionStyle.getCustomStyle(cr);
- mForegroundColor.setValue(attrs.foregroundColor);
mEdgeType.setValue(attrs.edgeType);
mEdgeColor.setValue(attrs.edgeColor);
- final int backgroundColor = attrs.backgroundColor;
- final int bgColor;
- final int bgAlpha;
- if (Color.alpha(backgroundColor) == 0) {
- bgColor = Color.TRANSPARENT;
- bgAlpha = (backgroundColor & 0xFF) << 24;
- } else {
- bgColor = backgroundColor | 0xFF000000;
- bgAlpha = backgroundColor & 0xFF000000;
- }
- mBackgroundColor.setValue(bgColor);
- mBackgroundOpacity.setValue(bgAlpha | 0xFFFFFF);
+ parseColorOpacity(mForegroundColor, mForegroundOpacity, attrs.foregroundColor);
+ parseColorOpacity(mBackgroundColor, mBackgroundOpacity, attrs.backgroundColor);
final String rawTypeface = attrs.mRawTypeface;
mTypeface.setValue(rawTypeface == null ? "" : rawTypeface);
@@ -171,10 +286,30 @@ private void updateAllPreferences() {
mLocale.setValue(rawLocale == null ? "" : rawLocale);
}
- private void refreshPreviewText() {
- if (mParent != null) {
- mParent.refreshPreviewText();
+ private void parseColorOpacity(ColorPreference color, ColorPreference opacity, int value) {
+ final int colorValue;
+ final int opacityValue;
+ if (Color.alpha(value) == 0) {
+ colorValue = Color.TRANSPARENT;
+ opacityValue = (value & 0xFF) << 24;
+ } else {
+ colorValue = value | 0xFF000000;
+ opacityValue = value & 0xFF000000;
}
+ color.setValue(colorValue);
+ opacity.setValue(opacityValue | 0xFFFFFF);
+ }
+
+ private int mergeColorOpacity(ColorPreference color, ColorPreference opacity) {
+ final int colorValue = color.getValue();
+ final int opacityValue = opacity.getValue();
+ final int value;
+ if (Color.alpha(colorValue) == 0) {
+ value = Color.alpha(opacityValue);
+ } else {
+ value = colorValue & 0x00FFFFFF | opacityValue & 0xFF000000;
+ }
+ return value;
}
private void refreshShowingCustom() {
@@ -191,20 +326,14 @@ private void refreshShowingCustom() {
@Override
public void onValueChanged(ListDialogPreference preference, int value) {
final ContentResolver cr = getActivity().getContentResolver();
- if (mForegroundColor == preference) {
+ if (mForegroundColor == preference || mForegroundOpacity == preference) {
+ final int merged = mergeColorOpacity(mForegroundColor, mForegroundOpacity);
Settings.Secure.putInt(
- cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR, value);
+ cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR, merged);
} else if (mBackgroundColor == preference || mBackgroundOpacity == preference) {
- final int bgColor = mBackgroundColor.getValue();
- final int bgAlpha = mBackgroundOpacity.getValue();
- final int argb;
- if (Color.alpha(bgColor) == 0) {
- argb = Color.alpha(bgAlpha);
- } else {
- argb = bgColor & 0x00FFFFFF | bgAlpha & 0xFF000000;
- }
+ final int merged = mergeColorOpacity(mBackgroundColor, mBackgroundOpacity);
Settings.Secure.putInt(
- cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR, argb);
+ cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR, merged);
} else if (mEdgeColor == preference) {
Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_EDGE_COLOR, value);
} else if (mPreset == preference) {
diff --git a/src/com/android/settings/accessibility/PresetPreference.java b/src/com/android/settings/accessibility/PresetPreference.java
index c091f712cad..84aba6c7e11 100644
--- a/src/com/android/settings/accessibility/PresetPreference.java
+++ b/src/com/android/settings/accessibility/PresetPreference.java
@@ -51,7 +51,7 @@ public boolean shouldDisableDependents() {
protected void onBindListItem(View view, int index) {
final SubtitleView previewText = (SubtitleView) view.findViewById(R.id.preview);
final int value = getValueAt(index);
- ToggleCaptioningPreferenceFragment.applyCaptionProperties(
+ CaptionPropertiesFragment.applyCaptionProperties(
mCaptioningManager, previewText, value);
previewText.setTextSize(DEFAULT_FONT_SIZE);
diff --git a/src/com/android/settings/accessibility/ToggleCaptioningPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleCaptioningPreferenceFragment.java
deleted file mode 100644
index f3c8b1ce93e..00000000000
--- a/src/com/android/settings/accessibility/ToggleCaptioningPreferenceFragment.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2013 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.accessibility;
-
-import android.app.ActionBar;
-import android.app.Activity;
-import android.app.Fragment;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.os.Bundle;
-import android.preference.PreferenceFrameLayout;
-import android.provider.Settings;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.CaptioningManager;
-
-import com.android.internal.widget.SubtitleView;
-import com.android.settings.R;
-import com.android.settings.accessibility.ToggleSwitch.OnBeforeCheckedChangeListener;
-
-import java.util.Locale;
-
-public class ToggleCaptioningPreferenceFragment extends Fragment {
- private static final float DEFAULT_FONT_SIZE = 48f;
-
- private CaptionPropertiesFragment mPropsFragment;
- private SubtitleView mPreviewText;
- private CaptioningManager mCaptioningManager;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- mCaptioningManager = (CaptioningManager) getActivity()
- .getSystemService(Context.CAPTIONING_SERVICE);
- }
-
- @Override
- public View onCreateView(
- LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- final View rootView = inflater.inflate(R.layout.captioning_preview, container, false);
-
- // We have to do this now because PreferenceFrameLayout looks at it
- // only when the view is added.
- if (container instanceof PreferenceFrameLayout) {
- ((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true;
- }
-
- return rootView;
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- mPropsFragment = ((CaptionPropertiesFragment) getFragmentManager()
- .findFragmentById(R.id.properties_fragment));
- mPropsFragment.setParent(this);
-
- mPreviewText = (SubtitleView) view.findViewById(R.id.preview_text);
-
- installActionBarToggleSwitch();
- refreshPreviewText();
- }
-
- public void refreshPreviewText() {
- final SubtitleView preview = mPreviewText;
- if (preview != null) {
- final Activity activity = getActivity();
- final ContentResolver cr = activity.getContentResolver();
- final int styleId = mCaptioningManager.getRawUserStyle();
- applyCaptionProperties(mCaptioningManager, preview, styleId);
-
- final Locale locale = mCaptioningManager.getLocale();
- if (locale != null) {
- final CharSequence localizedText = AccessibilityUtils.getTextForLocale(
- activity, locale, R.string.captioning_preview_text);
- preview.setText(localizedText);
- } else {
- preview.setText(R.string.captioning_preview_text);
- }
- }
- }
-
- public static void applyCaptionProperties(
- CaptioningManager manager, SubtitleView previewText, int styleId) {
- previewText.setStyle(styleId);
-
- final Context context = previewText.getContext();
- final ContentResolver cr = context.getContentResolver();
- final float fontScale = manager.getFontScale();
- previewText.setTextSize(fontScale * DEFAULT_FONT_SIZE);
-
- final Locale locale = manager.getLocale();
- if (locale != null) {
- final CharSequence localizedText = AccessibilityUtils.getTextForLocale(
- context, locale, R.string.captioning_preview_characters);
- previewText.setText(localizedText);
- } else {
- previewText.setText(R.string.captioning_preview_characters);
- }
- }
-
- private void installActionBarToggleSwitch() {
- final Activity activity = getActivity();
- final ToggleSwitch toggleSwitch = new ToggleSwitch(activity);
-
- final int padding = getResources().getDimensionPixelSize(
- R.dimen.action_bar_switch_padding);
- toggleSwitch.setPaddingRelative(0, 0, padding, 0);
-
- final ActionBar actionBar = activity.getActionBar();
- actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM);
-
- final ActionBar.LayoutParams params = new ActionBar.LayoutParams(
- ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT,
- Gravity.CENTER_VERTICAL | Gravity.END);
- actionBar.setCustomView(toggleSwitch, params);
-
- final boolean enabled = mCaptioningManager.isEnabled();
- mPropsFragment.getPreferenceScreen().setEnabled(enabled);
- mPreviewText.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
- toggleSwitch.setCheckedInternal(enabled);
- toggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
- @Override
- public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
- toggleSwitch.setCheckedInternal(checked);
- Settings.Secure.putInt(getActivity().getContentResolver(),
- Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, checked ? 1 : 0);
- mPropsFragment.getPreferenceScreen().setEnabled(checked);
- mPreviewText.setVisibility(checked ? View.VISIBLE : View.INVISIBLE);
- return false;
- }
- });
- }
-}
diff --git a/src/com/android/settings/applications/AppOpsDetails.java b/src/com/android/settings/applications/AppOpsDetails.java
index ee87290acb8..c9248c90eb2 100644
--- a/src/com/android/settings/applications/AppOpsDetails.java
+++ b/src/com/android/settings/applications/AppOpsDetails.java
@@ -20,26 +20,36 @@
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.AppOpsManager;
+import android.app.Dialog;
+import android.app.DialogFragment;
import android.app.Fragment;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+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.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.res.Resources;
+import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceActivity;
+import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.AdapterView;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.Switch;
+import android.widget.Spinner;
import android.widget.TextView;
import com.android.settings.R;
@@ -52,6 +62,14 @@ public class AppOpsDetails extends Fragment {
public static final String ARG_PACKAGE_NAME = "package";
+ private static final int MENU_RESET = Menu.FIRST;
+ private static final int MENU_ENABLE_PRIVACY_GUARD = Menu.FIRST + 1;
+
+ // Dialog identifiers used in showDialog
+ private static final int DLG_BASE = 0;
+ private static final int DLG_RESET = DLG_BASE + 1;
+ private static final int DLG_ENABLE_PRIVACY_GUARD = DLG_BASE + 2;
+
private AppOpsState mState;
private PackageManager mPm;
private AppOpsManager mAppOps;
@@ -61,9 +79,50 @@ public class AppOpsDetails extends Fragment {
private TextView mAppVersion;
private LinearLayout mOperationsSection;
+ private final int MODE_ALLOWED = 0;
+ private final int MODE_IGNORED = 1;
+ private final int MODE_ASK = 2;
+
+ private int modeToPosition(int mode) {
+ switch (mode) {
+ case AppOpsManager.MODE_ALLOWED:
+ return MODE_ALLOWED;
+ case AppOpsManager.MODE_IGNORED:
+ return MODE_IGNORED;
+ case AppOpsManager.MODE_ASK:
+ return MODE_ASK;
+ };
+
+ return MODE_IGNORED;
+ }
+
+ private int positionToMode(int position) {
+ switch (position) {
+ case MODE_ALLOWED:
+ return AppOpsManager.MODE_ALLOWED;
+ case MODE_IGNORED:
+ return AppOpsManager.MODE_IGNORED;
+ case MODE_ASK:
+ return AppOpsManager.MODE_ASK;
+ };
+
+ return AppOpsManager.MODE_IGNORED;
+ }
+
// Utility method to set application label and icon.
- private void setAppLabelAndIcon(PackageInfo pkgInfo) {
+ private void setAppLabelAndIcon(final PackageInfo pkgInfo) {
final View appSnippet = mRootView.findViewById(R.id.app_snippet);
+ appSnippet.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ try {
+ startActivity(new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+ Uri.fromParts("package", pkgInfo.packageName, null)));
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "Couldn't open app details activity", e);
+ }
+ }
+ });
appSnippet.setPaddingRelative(0, appSnippet.getPaddingTop(), 0, appSnippet.getPaddingBottom());
ImageView icon = (ImageView) appSnippet.findViewById(R.id.app_icon);
@@ -129,10 +188,12 @@ private boolean refreshUi() {
mOperationsSection.removeAllViews();
String lastPermGroup = "";
+ boolean hasEntries = false;
for (AppOpsState.OpsTemplate tpl : AppOpsState.ALL_TEMPLATES) {
List entries = mState.buildState(tpl,
mPackageInfo.applicationInfo.uid, mPackageInfo.packageName);
for (final AppOpsState.AppOpEntry entry : entries) {
+ hasEntries = true;
final AppOpsManager.OpEntry firstOp = entry.getOpEntry(0);
final View view = mInflater.inflate(R.layout.app_ops_details_item,
mOperationsSection, false);
@@ -154,23 +215,42 @@ private boolean refreshUi() {
}
((TextView)view.findViewById(R.id.op_name)).setText(
entry.getSwitchText(mState));
+ ((TextView)view.findViewById(R.id.op_counts)).setText(
+ entry.getCountsText(res));
((TextView)view.findViewById(R.id.op_time)).setText(
entry.getTimeText(res, true));
- Switch sw = (Switch)view.findViewById(R.id.switchWidget);
+ Spinner sw = (Spinner)view.findViewById(R.id.spinnerWidget);
final int switchOp = AppOpsManager.opToSwitch(firstOp.getOp());
- sw.setChecked(mAppOps.checkOp(switchOp, entry.getPackageOps().getUid(),
- entry.getPackageOps().getPackageName()) == AppOpsManager.MODE_ALLOWED);
- sw.setOnCheckedChangeListener(new Switch.OnCheckedChangeListener() {
+ int mode = mAppOps.checkOp(switchOp, entry.getPackageOps().getUid(),
+ entry.getPackageOps().getPackageName());
+ sw.setSelection(modeToPosition(mode));
+ sw.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
+ boolean firstMode = true;
+
@Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ public void onItemSelected(AdapterView> parentView, View selectedItemView, int position, long id) {
+ if(firstMode) {
+ firstMode = false;
+ return;
+ }
mAppOps.setMode(switchOp, entry.getPackageOps().getUid(),
- entry.getPackageOps().getPackageName(), isChecked
- ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
+ entry.getPackageOps().getPackageName(), positionToMode(position));
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parentView) {
+ // Do nothing
}
});
}
}
+ if (!hasEntries) {
+ final View view = mInflater.inflate(R.layout.app_ops_no_item,
+ mOperationsSection, false);
+ mOperationsSection.addView(view);
+ }
+
return true;
}
@@ -200,7 +280,7 @@ public void onCreate(Bundle icicle) {
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.app_ops_details, container, false);
- Utils.prepareCustomPreferencesList(container, view, view, false);
+ Utils.prepareCustomPreferencesList(container, view, view, true);
mRootView = view;
mOperationsSection = (LinearLayout)view.findViewById(R.id.operations_section);
@@ -214,4 +294,121 @@ public void onResume() {
setIntentAndFinish(true, true);
}
}
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ menu.add(0, MENU_RESET, 0, R.string.reset)
+ .setIcon(R.drawable.ic_settings_backup)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ if (mAppOps.getPrivacyGuardOpsForPackage(mPackageInfo.packageName).size() > 0) {
+ menu.add(0, MENU_ENABLE_PRIVACY_GUARD, 0, R.string.privacy_guard_manager_title)
+ .setIcon(R.drawable.ic_privacy_guard)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_RESET:
+ showDialogInner(DLG_RESET);
+ return true;
+ case MENU_ENABLE_PRIVACY_GUARD:
+ if (isPrivacyGuardActive()) {
+ setPrivacyGuard(false, false);
+ } else {
+ showDialogInner(DLG_ENABLE_PRIVACY_GUARD);
+ }
+ return true;
+ default:
+ return super.onContextItemSelected(item);
+ }
+ }
+
+ private void showDialogInner(int id) {
+ DialogFragment newFragment = MyAlertDialogFragment.newInstance(id);
+ newFragment.setTargetFragment(this, 0);
+ newFragment.show(getFragmentManager(), "dialog " + id);
+ }
+
+ public static class MyAlertDialogFragment extends DialogFragment {
+
+ public static MyAlertDialogFragment newInstance(int id) {
+ MyAlertDialogFragment frag = new MyAlertDialogFragment();
+ Bundle args = new Bundle();
+ args.putInt("id", id);
+ frag.setArguments(args);
+ return frag;
+ }
+
+ AppOpsDetails getOwner() {
+ return (AppOpsDetails) getTargetFragment();
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ int id = getArguments().getInt("id");
+ switch (id) {
+ case DLG_RESET:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.reset)
+ .setMessage(R.string.privacy_guard_app_ops_detail_reset_dialog_text)
+ .setPositiveButton(R.string.dlg_ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ getOwner().setPrivacyGuard(false, true);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ })
+ .create();
+ case DLG_ENABLE_PRIVACY_GUARD:
+ final int messageResId;
+ if ((getOwner().mPackageInfo.applicationInfo.flags
+ & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ messageResId = R.string.privacy_guard_dlg_system_app_text;
+ } else {
+ messageResId = R.string.privacy_guard_dlg_text;
+ }
+
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.privacy_guard_dlg_title)
+ .setMessage(messageResId)
+ .setPositiveButton(R.string.dlg_ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ getOwner().setPrivacyGuard(true, false);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ })
+ .create();
+ }
+ throw new IllegalArgumentException("unknown id " + id);
+ }
+ }
+
+ private boolean isPrivacyGuardActive() {
+ int state = mAppOps.getPrivacyGuardSettingForPackage(
+ mPackageInfo.applicationInfo.uid, mPackageInfo.packageName);
+ if (state > AppOpsManager.PRIVACY_GUARD_DISABLED_PLUS) {
+ return true;
+ }
+ return false;
+ }
+
+ private void setPrivacyGuard(boolean enabled, boolean forceAll) {
+ mAppOps.setPrivacyGuardSettingForPackage(
+ mPackageInfo.applicationInfo.uid,
+ mPackageInfo.packageName, enabled, forceAll);
+ refreshUi();
+ }
+
}
diff --git a/src/com/android/settings/applications/AppOpsState.java b/src/com/android/settings/applications/AppOpsState.java
index c3964793f2a..c98410e3bef 100644
--- a/src/com/android/settings/applications/AppOpsState.java
+++ b/src/com/android/settings/applications/AppOpsState.java
@@ -16,6 +16,7 @@
package com.android.settings.applications;
+import android.app.Activity;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -23,6 +24,7 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
+import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -52,12 +54,15 @@ public class AppOpsState {
List mApps;
+ private SharedPreferences mPreferences;
+
public AppOpsState(Context context) {
mContext = context;
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
mPm = context.getPackageManager();
- mOpSummaries = context.getResources().getTextArray(R.array.app_ops_summaries);
- mOpLabels = context.getResources().getTextArray(R.array.app_ops_labels);
+ mOpSummaries = context.getResources().getTextArray(R.array.app_ops_summaries_cm);
+ mOpLabels = context.getResources().getTextArray(R.array.app_ops_labels_cm);
+ mPreferences = context.getSharedPreferences("appops_manager", Activity.MODE_PRIVATE);
}
public static class OpsTemplate implements Parcelable {
@@ -134,12 +139,15 @@ public void writeToParcel(Parcel dest, int flags) {
public static final OpsTemplate MESSAGING_TEMPLATE = new OpsTemplate(
new int[] { AppOpsManager.OP_READ_SMS,
+ AppOpsManager.OP_READ_MMS,
AppOpsManager.OP_RECEIVE_SMS,
AppOpsManager.OP_RECEIVE_EMERGECY_SMS,
AppOpsManager.OP_RECEIVE_MMS,
AppOpsManager.OP_RECEIVE_WAP_PUSH,
AppOpsManager.OP_WRITE_SMS,
+ AppOpsManager.OP_WRITE_MMS,
AppOpsManager.OP_SEND_SMS,
+ AppOpsManager.OP_SEND_MMS,
AppOpsManager.OP_READ_ICC_SMS,
AppOpsManager.OP_WRITE_ICC_SMS },
new boolean[] { true,
@@ -150,6 +158,9 @@ public void writeToParcel(Parcel dest, int flags) {
true,
true,
true,
+ true,
+ true,
+ true,
true }
);
@@ -166,7 +177,10 @@ public void writeToParcel(Parcel dest, int flags) {
AppOpsManager.OP_AUDIO_MEDIA_VOLUME,
AppOpsManager.OP_AUDIO_ALARM_VOLUME,
AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,
- AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, },
+ AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,
+ AppOpsManager.OP_WIFI_CHANGE,
+ AppOpsManager.OP_BLUETOOTH_CHANGE,
+ AppOpsManager.OP_DATA_CONNECT_CHANGE },
new boolean[] { false,
true,
true,
@@ -179,7 +193,10 @@ public void writeToParcel(Parcel dest, int flags) {
false,
false,
false,
- false }
+ false,
+ true,
+ true,
+ true }
);
public static final OpsTemplate DEVICE_TEMPLATE = new OpsTemplate(
@@ -188,18 +205,31 @@ public void writeToParcel(Parcel dest, int flags) {
AppOpsManager.OP_CALL_PHONE,
AppOpsManager.OP_WRITE_SETTINGS,
AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
- AppOpsManager.OP_WAKE_LOCK },
+ AppOpsManager.OP_WAKE_LOCK,
+ AppOpsManager.OP_WIFI_CHANGE,
+ AppOpsManager.OP_BLUETOOTH_CHANGE,
+ AppOpsManager.OP_DATA_CONNECT_CHANGE,
+ AppOpsManager.OP_ALARM_WAKEUP, },
new boolean[] { false,
true,
true,
true,
true,
- true, }
+ true,
+ true,
+ true,
+ true,
+ true }
+ );
+
+ public static final OpsTemplate BOOTUP_TEMPLATE = new OpsTemplate(
+ new int[] { AppOpsManager.OP_BOOT_COMPLETED },
+ new boolean[] { true, }
);
public static final OpsTemplate[] ALL_TEMPLATES = new OpsTemplate[] {
LOCATION_TEMPLATE, PERSONAL_TEMPLATE, MESSAGING_TEMPLATE,
- MEDIA_TEMPLATE, DEVICE_TEMPLATE
+ MEDIA_TEMPLATE, DEVICE_TEMPLATE, BOOTUP_TEMPLATE
};
/**
@@ -355,30 +385,59 @@ public AppOpsManager.OpEntry getOpEntry(int pos) {
}
private CharSequence getCombinedText(ArrayList ops,
- CharSequence[] items) {
- if (ops.size() == 1) {
- return items[ops.get(0).getOp()];
- } else {
- StringBuilder builder = new StringBuilder();
- for (int i=0; i 0) {
- builder.append(", ");
- }
- builder.append(items[ops.get(i).getOp()]);
+ CharSequence[] items, Resources res, boolean withTerseCounts) {
+ StringBuilder builder = new StringBuilder();
+ for (int i=0; i 0) {
+ builder.append(", ");
+ }
+ AppOpsManager.OpEntry op = ops.get(i);
+ int count = op.getAllowedCount() + op.getIgnoredCount();
+
+ if (withTerseCounts && count > 0) {
+ String quantity = res.getQuantityString(R.plurals.app_ops_count,
+ count, count);
+ builder.append(res.getString(R.string.app_ops_entry_summary,
+ items[op.getOp()], quantity));
+ } else {
+ builder.append(items[op.getOp()]);
}
- return builder.toString();
}
+ return builder.toString();
+ }
+
+ public CharSequence getCountsText(Resources res) {
+ AppOpsManager.OpEntry op = mOps.get(0);
+ int allowed = op.getAllowedCount();
+ int denied = op.getIgnoredCount();
+
+ if (allowed == 0 && denied == 0) {
+ return null;
+ }
+
+ CharSequence allowedQuantity = res.getQuantityString(R.plurals.app_ops_count,
+ allowed, allowed);
+ CharSequence deniedQuantity = res.getQuantityString(R.plurals.app_ops_count,
+ denied, denied);
+
+ if (denied == 0) {
+ return res.getString(R.string.app_ops_allowed_count, allowedQuantity);
+ } else if (allowed == 0) {
+ return res.getString(R.string.app_ops_ignored_count, deniedQuantity);
+ }
+ return res.getString(R.string.app_ops_both_count, allowedQuantity, deniedQuantity);
}
public CharSequence getSummaryText(AppOpsState state) {
- return getCombinedText(mOps, state.mOpSummaries);
+ return getCombinedText(mOps, state.mOpSummaries, state.mContext.getResources(), true);
}
public CharSequence getSwitchText(AppOpsState state) {
+ Resources res = state.mContext.getResources();
if (mSwitchOps.size() > 0) {
- return getCombinedText(mSwitchOps, state.mOpLabels);
+ return getCombinedText(mSwitchOps, state.mOpLabels, res, false);
} else {
- return getCombinedText(mOps, state.mOpLabels);
+ return getCombinedText(mOps, state.mOpLabels, res, false);
}
}
@@ -462,19 +521,34 @@ public List buildState(OpsTemplate tpl) {
}
private AppEntry getAppEntry(final Context context, final HashMap appEntries,
- final String packageName, ApplicationInfo appInfo) {
+ final String packageName, ApplicationInfo appInfo, boolean applyFilters) {
+
+ if (appInfo == null) {
+ try {
+ appInfo = mPm.getApplicationInfo(packageName,
+ PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.GET_UNINSTALLED_PACKAGES);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Unable to find info for package " + packageName);
+ return null;
+ }
+ }
+
+ if (applyFilters) {
+ // Hide user apps if needed
+ if (!shouldShowUserApps() &&
+ (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ return null;
+ }
+ // Hide system apps if needed
+ if (!shouldShowSystemApps() &&
+ (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ return null;
+ }
+ }
+
AppEntry appEntry = appEntries.get(packageName);
if (appEntry == null) {
- if (appInfo == null) {
- try {
- appInfo = mPm.getApplicationInfo(packageName,
- PackageManager.GET_DISABLED_COMPONENTS
- | PackageManager.GET_UNINSTALLED_PACKAGES);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Unable to find info for package " + packageName);
- return null;
- }
- }
appEntry = new AppEntry(this, appInfo);
appEntry.loadLabel(context);
appEntries.put(packageName, appEntry);
@@ -482,6 +556,14 @@ private AppEntry getAppEntry(final Context context, final HashMap buildState(OpsTemplate tpl, int uid, String packageName) {
final Context context = mContext;
@@ -502,6 +584,9 @@ public List buildState(OpsTemplate tpl, int uid, String packageName)
}
}
+ // Whether to apply hide user / system app filters
+ final boolean applyFilters = (packageName == null);
+
List pkgs;
if (packageName != null) {
pkgs = mAppOps.getOpsForPackage(uid, packageName, tpl.ops);
@@ -512,7 +597,8 @@ public List buildState(OpsTemplate tpl, int uid, String packageName)
if (pkgs != null) {
for (int i=0; i buildState(OpsTemplate tpl, int uid, String packageName)
for (int i=0; i buildState(OpsTemplate tpl, int uid, String packageName)
}
AppOpsManager.OpEntry opEntry = new AppOpsManager.OpEntry(
- permOps.get(k), AppOpsManager.MODE_ALLOWED, 0, 0, 0);
+ permOps.get(k), AppOpsManager.MODE_ALLOWED, 0, 0, 0, 0, 0);
dummyOps.add(opEntry);
addOp(entries, pkgOps, appEntry, opEntry, packageName == null,
packageName == null ? 0 : opToOrder[opEntry.getOp()]);
diff --git a/src/com/android/settings/applications/AppOpsSummary.java b/src/com/android/settings/applications/AppOpsSummary.java
index 4cee8e583a8..6c06998d94a 100644
--- a/src/com/android/settings/applications/AppOpsSummary.java
+++ b/src/com/android/settings/applications/AppOpsSummary.java
@@ -16,15 +16,23 @@
package com.android.settings.applications;
+import android.app.Activity;
+import android.app.AlertDialog;
import android.app.AppOpsManager;
import android.app.Fragment;
import android.app.FragmentManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceFrameLayout;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.PagerTabStrip;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -38,13 +46,19 @@ public class AppOpsSummary extends Fragment {
private View mRootView;
private ViewPager mViewPager;
+ private MyPagerAdapter mAdapter;
+
+ private Activity mActivity;
+ private SharedPreferences mPreferences;
+
CharSequence[] mPageNames;
static AppOpsState.OpsTemplate[] sPageTemplates = new AppOpsState.OpsTemplate[] {
AppOpsState.LOCATION_TEMPLATE,
AppOpsState.PERSONAL_TEMPLATE,
AppOpsState.MESSAGING_TEMPLATE,
AppOpsState.MEDIA_TEMPLATE,
- AppOpsState.DEVICE_TEMPLATE
+ AppOpsState.DEVICE_TEMPLATE,
+ AppOpsState.BOOTUP_TEMPLATE
};
int mCurPos;
@@ -79,6 +93,10 @@ public void onPageSelected(int position) {
mCurPos = position;
}
+ public int getCurrentPage() {
+ return mCurPos;
+ }
+
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
@@ -87,6 +105,14 @@ public void onPageScrollStateChanged(int state) {
}
}
+ private void resetAdapter() {
+ // trigger adapter load, preserving the selected page
+ int curPos = mAdapter.getCurrentPage();
+ mViewPager.setAdapter(mAdapter);
+ mViewPager.setOnPageChangeListener(mAdapter);
+ mViewPager.setCurrentItem(curPos);
+ }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// initialize the inflater
@@ -97,14 +123,14 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
mContentContainer = container;
mRootView = rootView;
- mPageNames = getResources().getTextArray(R.array.app_ops_categories);
+ mPageNames = getResources().getTextArray(R.array.app_ops_categories_cm);
mViewPager = (ViewPager) rootView.findViewById(R.id.pager);
- MyPagerAdapter adapter = new MyPagerAdapter(getChildFragmentManager());
- mViewPager.setAdapter(adapter);
- mViewPager.setOnPageChangeListener(adapter);
+ mAdapter = new MyPagerAdapter(getChildFragmentManager());
+ mViewPager.setAdapter(mAdapter);
+ mViewPager.setOnPageChangeListener(mAdapter);
PagerTabStrip tabs = (PagerTabStrip) rootView.findViewById(R.id.tabs);
- tabs.setTabIndicatorColorResource(android.R.color.holo_blue_light);
+ tabs.setTabIndicatorColorResource(R.color.tab_selector);
// We have to do this now because PreferenceFrameLayout looks at it
// only when the view is added.
@@ -112,6 +138,88 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true;
}
+ mActivity = getActivity();
+
return rootView;
}
+
+ private boolean shouldShowUserApps() {
+ return mPreferences.getBoolean("show_user_apps", true);
+ }
+
+ private boolean shouldShowSystemApps() {
+ return mPreferences.getBoolean("show_system_apps", true);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ // get shared preferences
+ mPreferences = mActivity.getSharedPreferences("appops_manager", Activity.MODE_PRIVATE);
+
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.appops_manager, menu);
+ menu.findItem(R.id.show_user_apps).setChecked(shouldShowUserApps());
+ menu.findItem(R.id.show_system_apps).setChecked(shouldShowSystemApps());
+ }
+
+ private void resetCounters() {
+ final AppOpsManager appOps =
+ (AppOpsManager) mActivity.getSystemService(Context.APP_OPS_SERVICE);
+ if (appOps == null) {
+ return;
+ }
+ appOps.resetCounters();
+ // reload content
+ resetAdapter();
+ }
+
+ private void resetCountersConfirm() {
+ new AlertDialog.Builder(getActivity())
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(R.string.app_ops_reset_confirm_title)
+ .setMessage(R.string.app_ops_reset_confirm_mesg)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
+ {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ resetCounters();
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.show_user_apps:
+ final String prefNameUserApps = "show_user_apps";
+ // set the menu checkbox and save it in shared preference
+ item.setChecked(!item.isChecked());
+ mPreferences.edit().putBoolean(prefNameUserApps, item.isChecked()).commit();
+ // reload content
+ resetAdapter();
+ return true;
+ case R.id.show_system_apps:
+ final String prefNameSysApps = "show_system_apps";
+ // set the menu checkbox and save it in shared preference
+ item.setChecked(!item.isChecked());
+ mPreferences.edit().putBoolean(prefNameSysApps, item.isChecked()).commit();
+ // reload view content
+ resetAdapter();
+ return true;
+ case R.id.reset_counters:
+ resetCountersConfirm();
+ return true;
+ default:
+ return super.onContextItemSelected(item);
+ }
+ }
}
diff --git a/src/com/android/settings/applications/ApplicationsState.java b/src/com/android/settings/applications/ApplicationsState.java
index 1c2eb2c7020..68fb595f2b8 100644
--- a/src/com/android/settings/applications/ApplicationsState.java
+++ b/src/com/android/settings/applications/ApplicationsState.java
@@ -572,6 +572,10 @@ void handleRebuildList() {
if (DEBUG) Log.i(TAG, "Rebuilding...");
for (int i=0; i mHomePackages = new HashSet();
@@ -182,13 +226,17 @@ public class InstalledAppDetails extends Fragment
private static final int DLG_DISABLE = DLG_BASE + 7;
private static final int DLG_DISABLE_NOTIFICATIONS = DLG_BASE + 8;
private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 9;
+ private static final int DLG_PRIVACY_GUARD = DLG_BASE + 10;
+ private static final int DLG_BLACKLIST = DLG_BASE + 11;
// Menu identifiers
public static final int UNINSTALL_ALL_USERS_MENU = 1;
+ public static final int OPEN_PROTECTED_APPS = 2;
// Result code identifiers
public static final int REQUEST_UNINSTALL = 1;
public static final int REQUEST_MANAGE_SPACE = 2;
+ public static final int REQUEST_TOGGLE_PROTECTION = 3;
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
@@ -237,6 +285,56 @@ public void packageMoved(String packageName, int returnCode) throws RemoteExcept
}
}
+ private ServiceConnection mBackupServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className,
+ IBinder service) {
+ mBackupService = ((BackupService.BackupServiceBinder) service).getService();
+ mBackupService.listBackups(Arrays.asList(mPackageInfo.packageName),
+ mListBackupsObserver);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mBackupService = null;
+ }
+ };
+
+ class ListBackupsObserver implements BackupService.ListBackupsObserver {
+ @Override
+ public void onListBackupsCompleted(Map> backups) {
+ mBackupsList.removeAllViews();
+ for (Backup b : backups.get(mPackageInfo.packageName)) {
+ BackupView bv = (BackupView) View.inflate(getActivity(), R.layout.backup_item, null);
+ bv.setBackup(b, getSizeStr(b.size), InstalledAppDetails.this);
+ mBackupsList.addView(bv);
+ }
+ }
+ }
+
+ class CreateBackupObserver implements BackupService.CreateBackupObserver {
+ @Override
+ public void onCreateBackupCompleted() {
+ mBackupService.listBackups(
+ Arrays.asList(mPackageInfo.packageName), mListBackupsObserver);
+ }
+ }
+
+ class DeleteBackupObserver implements BackupService.DeleteBackupObserver {
+ @Override
+ public void onDeleteBackupCompleted() {
+ mBackupService.listBackups(
+ Arrays.asList(mPackageInfo.packageName), mListBackupsObserver);
+ }
+ }
+
+ class RestoreBackupObserver implements BackupService.RestoreBackupObserver {
+ @Override
+ public void onRestoreBackupCompleted() {
+ refreshUi();
+ }
+ }
+
private String getSizeStr(long size) {
if (size == SIZE_INVALID) {
return mInvalidSizeStr.toString();
@@ -245,6 +343,7 @@ private String getSizeStr(long size) {
}
private void initDataButtons() {
+ boolean enabled = false;
// If the app doesn't have its own space management UI
// And it's a system app that doesn't allow clearing user data or is an active admin
// Then disable the Clear Data button.
@@ -254,7 +353,7 @@ private void initDataButtons() {
== ApplicationInfo.FLAG_SYSTEM
|| mDpm.packageHasActiveAdmins(mPackageInfo.packageName))) {
mClearDataButton.setText(R.string.clear_user_data_text);
- mClearDataButton.setEnabled(false);
+ enabled = false;
mCanClearData = false;
} else {
if (mAppEntry.info.manageSpaceActivityName != null) {
@@ -262,6 +361,18 @@ private void initDataButtons() {
} else {
mClearDataButton.setText(R.string.clear_user_data_text);
}
+ enabled = true;
+ }
+
+ // This is a protected app component.
+ // You cannot clear data for a protected component
+ if (mPackageInfo.applicationInfo.protect) {
+ enabled = false;
+ }
+
+ mClearDataButton.setEnabled(enabled);
+ mCanClearData = enabled;
+ if (enabled) {
mClearDataButton.setOnClickListener(this);
}
}
@@ -285,7 +396,7 @@ private CharSequence getMoveErrMsg(int errCode) {
}
private void initMoveButton() {
- if (Environment.isExternalStorageEmulated()) {
+ if (!Environment.isExternalAppsAvailableAndMounted()) {
mMoveAppButton.setVisibility(View.INVISIBLE);
return;
}
@@ -350,9 +461,9 @@ private void initUninstallButtons() {
specialDisable = handleDisableable(mSpecialDisableButton);
mSpecialDisableButton.setOnClickListener(this);
}
- mMoreControlButtons.setVisibility(specialDisable ? View.VISIBLE : View.GONE);
+ mSpecialDisableButton.setVisibility(specialDisable ? View.VISIBLE : View.INVISIBLE);
} else {
- mMoreControlButtons.setVisibility(View.GONE);
+ mSpecialDisableButton.setVisibility(View.INVISIBLE);
if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
enabled = handleDisableable(mUninstallButton);
} else if ((mPackageInfo.applicationInfo.flags
@@ -366,11 +477,34 @@ private void initUninstallButtons() {
mUninstallButton.setText(R.string.uninstall_text);
}
}
- // If this is a device admin, it can't be uninstall or disabled.
+ // If this is a device admin, it can't be uninstalled or disabled.
// We do this here so the text of the button is still set correctly.
if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
enabled = false;
}
+
+ // This is a protected app component.
+ // You cannot a uninstall a protected component
+ if (mPackageInfo.applicationInfo.protect) {
+ enabled = false;
+ }
+
+ // If this is the default (or only) home app, suppress uninstall (even if
+ // we still think it should be allowed for other reasons)
+ if (enabled && mHomePackages.contains(mPackageInfo.packageName)) {
+ ArrayList homeActivities = new ArrayList();
+ ComponentName currentDefaultHome = mPm.getHomeActivities(homeActivities);
+ if (currentDefaultHome == null) {
+ // No preferred default, so permit uninstall only when
+ // there is more than one candidate
+ enabled = (mHomePackages.size() > 1);
+ } else {
+ // There is an explicit default home app -- forbid uninstall of
+ // that one, but permit it for installed-but-inactive ones.
+ enabled = !mPackageInfo.packageName.equals(currentDefaultHome.getPackageName());
+ }
+ }
+
mUninstallButton.setEnabled(enabled);
if (enabled) {
// Register listener
@@ -378,17 +512,47 @@ private void initUninstallButtons() {
}
}
+ private void initBlacklistButton() {
+ mBlacklistButton.setText(R.string.blacklist_button_title);
+
+ boolean allowedForPeek = true, allowedForFloating = true, allowedForHalo = true, allowedForHover = true;
+ try {
+ allowedForHalo = mNotificationManager
+ .isPackageAllowedForHalo(mAppEntry.info.packageName);
+ allowedForPeek = mNotificationManager
+ .isPackageAllowedForPeek(mAppEntry.info.packageName);
+ allowedForFloating = mNotificationManager
+ .isPackageAllowedForFloatingMode(mAppEntry.info.packageName);
+ allowedForHover = mNotificationManager
+ .isPackageAllowedForHover(mAppEntry.info.packageName);
+ } catch (android.os.RemoteException ex) {
+ // uh oh
+ }
+ mHaloState.setChecked((!allowedForHalo));
+ mHaloState.setOnCheckedChangeListener(this);
+ mPeekBlacklist.setChecked(!allowedForPeek);
+ mPeekBlacklist.setOnCheckedChangeListener(this);
+ mFloatingBlacklist.setChecked(!allowedForFloating);
+ mFloatingBlacklist.setOnCheckedChangeListener(this);
+ mHoverBlacklist.setChecked(!allowedForHover);
+ mHoverBlacklist.setOnCheckedChangeListener(this);
+
+ mBlacklistButton.setOnClickListener(this);
+ }
+
private void initNotificationButton() {
- INotificationManager nm = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
boolean enabled = true; // default on
+ boolean allowedForHalo = true; // default on
try {
- enabled = nm.areNotificationsEnabledForPackage(mAppEntry.info.packageName,
+ enabled = mNotificationManager.areNotificationsEnabledForPackage(mAppEntry.info.packageName,
mAppEntry.info.uid);
+ allowedForHalo = mNotificationManager.isPackageAllowedForHalo(mAppEntry.info.packageName);
} catch (android.os.RemoteException ex) {
// this does not bode well
}
mNotificationSwitch.setChecked(enabled);
+ mHaloState.setChecked((mHaloPolicyIsBlack ? !allowedForHalo : allowedForHalo));
+ mHaloState.setOnCheckedChangeListener(this);
if (isThisASystemPackage()) {
mNotificationSwitch.setEnabled(false);
} else {
@@ -397,6 +561,41 @@ private void initNotificationButton() {
}
}
+ private void initHeadsUpButton() {
+ boolean enabled = mPm.getHeadsUpSetting(mAppEntry.info.packageName);
+ mHeadsUpSwitch.setChecked(enabled);
+ if (isThisASystemPackage() || !mNotificationSwitch.isChecked()) {
+ mHeadsUpSwitch.setEnabled(false);
+ } else {
+ mHeadsUpSwitch.setEnabled(true);
+ mHeadsUpSwitch.setOnCheckedChangeListener(this);
+ }
+ }
+
+ private void initAppOpsButton() {
+ boolean enabled = true;
+ if (isThisASystemPackage()) {
+ enabled = false;
+ }
+
+ mAppOpsButton.setEnabled(enabled);
+ if (enabled) {
+ // Register listener
+ mAppOpsButton.setOnClickListener(this);
+ }
+ }
+
+ private void initPrivacyGuardButton() {
+ if (mPrivacyGuardSwitch == null) {
+ return;
+ }
+ mAppOps = (AppOpsManager) getActivity().getSystemService(Context.APP_OPS_SERVICE);
+ int state = mAppOps.getPrivacyGuardSettingForPackage(
+ mAppEntry.info.uid, mAppEntry.info.packageName);
+ mPrivacyGuardSwitch.setChecked(state > AppOpsManager.PRIVACY_GUARD_DISABLED_PLUS);
+ mPrivacyGuardSwitch.setOnCheckedChangeListener(this);
+ }
+
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
@@ -411,9 +610,22 @@ public void onCreate(Bundle icicle) {
mAppWidgetManager = AppWidgetManager.getInstance(getActivity());
mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
mSmsManager = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+ mNotificationManager = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+
+ if (UserHandle.myUserId() == UserHandle.USER_OWNER) {
+ getActivity().bindService(new Intent(getActivity(), BackupService.class),
+ mBackupServiceConnection, Context.BIND_AUTO_CREATE);
+ }
mCanBeOnSdCardChecker = new CanBeOnSdCardChecker();
+ try {
+ mHaloPolicyIsBlack = mNotificationManager.isHaloPolicyBlack();
+ } catch (android.os.RemoteException ex) {
+ // System dead
+ }
+
// Need to make sure we have loaded applications at this point.
mSession.resume();
@@ -438,7 +650,7 @@ public View onCreateView(
mExternalCodeSize = (TextView)view.findViewById(R.id.external_code_size_text);
mExternalDataSize = (TextView)view.findViewById(R.id.external_data_size_text);
- if (Environment.isExternalStorageEmulated()) {
+ if (!Environment.isExternalAppsAvailableAndMounted()) {
((View)mExternalCodeSize.getParent()).setVisibility(View.GONE);
((View)mExternalDataSize.getParent()).setVisibility(View.GONE);
}
@@ -451,10 +663,10 @@ public View onCreateView(
mForceStopButton.setEnabled(false);
// Get More Control button panel
- mMoreControlButtons = view.findViewById(R.id.more_control_buttons_panel);
- mMoreControlButtons.findViewById(R.id.left_button).setVisibility(View.INVISIBLE);
- mSpecialDisableButton = (Button)mMoreControlButtons.findViewById(R.id.right_button);
- mMoreControlButtons.setVisibility(View.GONE);
+ View moreCtrlBtns = view.findViewById(R.id.more_control_buttons_panel);
+ mBlacklistButton = (Button)moreCtrlBtns.findViewById(R.id.left_button);
+ mSpecialDisableButton = (Button)moreCtrlBtns.findViewById(R.id.right_button);
+ mSpecialDisableButton.setVisibility(View.INVISIBLE);
// Initialize clear data and move install location buttons
View data_buttons_panel = view.findViewById(R.id.data_buttons_panel);
@@ -465,6 +677,14 @@ public View onCreateView(
mCacheSize = (TextView) view.findViewById(R.id.cache_size_text);
mClearCacheButton = (Button) view.findViewById(R.id.clear_cache_button);
+ // Backup section (show only to device admin)
+ if (UserHandle.myUserId() == UserHandle.USER_OWNER) {
+ mBackupsList = (LinearLayout) view.findViewById(R.id.backups_list);
+ mListBackupsObserver = new ListBackupsObserver();
+ mCreateBackup = (Button) view.findViewById(R.id.create_backup);
+ mCreateBackup.setOnClickListener(this);
+ }
+
mActivitiesButton = (Button)view.findViewById(R.id.clear_activities_button);
// Screen compatibility control
@@ -473,6 +693,18 @@ public View onCreateView(
mEnableCompatibilityCB = (CheckBox)view.findViewById(R.id.enable_compatibility_cb);
mNotificationSwitch = (CompoundButton) view.findViewById(R.id.notification_switch);
+ mPrivacyGuardSwitch = (CompoundButton) view.findViewById(R.id.privacy_guard_switch);
+
+ mAppOps = (AppOpsManager) getActivity().getSystemService(Context.APP_OPS_SERVICE);
+ mAppOpsButton = (Button) view.findViewById(R.id.app_ops_button);
+
+ mBlacklistDialogView = inflater.inflate(R.layout.blacklist_dialog, null);
+ mHaloState = (CheckBox) mBlacklistDialogView.findViewById(R.id.halo_state);
+ mHaloState.setText((mHaloPolicyIsBlack ? R.string.app_halo_label_black : R.string.app_halo_label_white));
+ mPeekBlacklist = (CheckBox) mBlacklistDialogView.findViewById(R.id.peek_blacklist);
+ mFloatingBlacklist = (CheckBox) mBlacklistDialogView.findViewById(R.id.floating_blacklist);
+ mHoverBlacklist = (CheckBox) mBlacklistDialogView.findViewById(R.id.hover_blacklist);
+ mHeadsUpSwitch = (CompoundButton) view.findViewById(R.id.heads_up_switch);
return view;
}
@@ -481,6 +713,9 @@ public View onCreateView(
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.add(0, UNINSTALL_ALL_USERS_MENU, 1, R.string.uninstall_all_users_text)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ menu.add(0, OPEN_PROTECTED_APPS, Menu.NONE, R.string.protected_apps)
+ .setIcon(getResources().getDrawable(R.drawable.folder_lock))
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
@Override
@@ -500,6 +735,8 @@ public void onPrepareOptionsMenu(Menu menu) {
showIt = false;
}
menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(showIt);
+
+ menu.findItem(OPEN_PROTECTED_APPS).setVisible(mPackageInfo.applicationInfo.protect);
}
@Override
@@ -508,6 +745,10 @@ public boolean onOptionsItemSelected(MenuItem item) {
if (menuId == UNINSTALL_ALL_USERS_MENU) {
uninstallPkg(mAppEntry.info.packageName, true, false);
return true;
+ } else if (menuId == OPEN_PROTECTED_APPS) {
+ // Verify protection for toggling protected component status
+ Intent protectedApps = new Intent(getActivity(), org.regulus.amrasettings.protectedapps.LockPatternActivity.class);
+ startActivityForResult(protectedApps, REQUEST_TOGGLE_PROTECTION);
}
return false;
}
@@ -533,6 +774,36 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (!refreshUi()) {
setIntentAndFinish(true, true);
}
+ } else if (requestCode == REQUEST_TOGGLE_PROTECTION) {
+ switch (resultCode) {
+ case Activity.RESULT_OK:
+ new ToggleProtectedAppComponents().execute();
+ break;
+ case Activity.RESULT_CANCELED:
+ // User failed to enter/confirm a lock pattern, do nothing
+ break;
+ }
+ }
+ }
+ private class ToggleProtectedAppComponents extends AsyncTask {
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ getActivity().invalidateOptionsMenu();
+ if (!refreshUi()) {
+ setIntentAndFinish(true, true);
+ }
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ ArrayList components = new ArrayList();
+ for (ActivityInfo aInfo : mPackageInfo.activities) {
+ components.add(new ComponentName(aInfo.packageName, aInfo.name));
+ }
+
+ ProtectedAppsReceiver.updateProtectedAppComponentsAndNotify(getActivity(),
+ components, PackageManager.COMPONENT_VISIBLE_STATUS);
+ return null;
}
}
@@ -579,6 +850,13 @@ public void onPause() {
mSession.pause();
}
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ mSession.release();
+ getActivity().unbindService(mBackupServiceConnection);
+ }
+
@Override
public void onAllSizesComputed() {
}
@@ -624,7 +902,8 @@ private String retrieveAppEntry() {
mPackageInfo = mPm.getPackageInfo(mAppEntry.info.packageName,
PackageManager.GET_DISABLED_COMPONENTS |
PackageManager.GET_UNINSTALLED_PACKAGES |
- PackageManager.GET_SIGNATURES);
+ PackageManager.GET_SIGNATURES |
+ PackageManager.GET_ACTIVITIES);
} catch (NameNotFoundException e) {
Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e);
}
@@ -761,7 +1040,8 @@ private boolean refreshUi() {
}
// Security permissions section
- LinearLayout permsView = (LinearLayout) mRootView.findViewById(R.id.permissions_section);
+ RelativeLayout permsView =
+ (RelativeLayout) mRootView.findViewById(R.id.permissions_section);
AppSecurityPermissions asp = new AppSecurityPermissions(getActivity(), packageName);
int premiumSmsPermission = getPremiumSmsPermission(packageName);
// Premium SMS permission implies the app also has SEND_SMS permission, so the original
@@ -874,6 +1154,12 @@ private boolean refreshUi() {
}
}
+ // only setup the privacy guard setting if we didn't get uninstalled
+ if (!mMoveInProgress) {
+ initPrivacyGuardButton();
+ initHeadsUpButton();
+ }
+
return true;
}
@@ -945,7 +1231,7 @@ private void refreshSizeInfo() {
mHaveSizes = true;
long codeSize = mAppEntry.codeSize;
long dataSize = mAppEntry.dataSize;
- if (Environment.isExternalStorageEmulated()) {
+ if (!Environment.isExternalAppsAvailableAndMounted()) {
codeSize += mAppEntry.externalCodeSize;
dataSize += mAppEntry.externalDataSize;
} else {
@@ -1014,11 +1300,15 @@ private void refreshButtons() {
initDataButtons();
initMoveButton();
initNotificationButton();
+ initAppOpsButton();
+ initBlacklistButton();
} else {
mMoveAppButton.setText(R.string.moving);
mMoveAppButton.setEnabled(false);
mUninstallButton.setEnabled(false);
mSpecialDisableButton.setEnabled(false);
+ mAppOpsButton.setEnabled(false);
+ mBlacklistButton.setEnabled(false);
}
}
@@ -1197,8 +1487,11 @@ public void onClick(DialogInterface dialog, int which) {
.setNegativeButton(R.string.dlg_cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
- // Re-enable the checkbox
- getOwner().mNotificationSwitch.setChecked(true);
+ dialog.cancel();
+ // Give access to heads up check box.
+ if (getOwner().mHeadsUpSwitch != null) {
+ getOwner().mHeadsUpSwitch.setEnabled(true);
+ }
}
})
.create();
@@ -1217,9 +1510,64 @@ public void onClick(DialogInterface dialog, int which) {
})
.setNegativeButton(R.string.dlg_cancel, null)
.create();
+ case DLG_BLACKLIST:
+ AlertDialog dialog = new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.blacklist_button_title))
+ .setView(mBlacklistDialogView)
+ .setNeutralButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ((ViewGroup)mBlacklistDialogView.getParent())
+ .removeView(mBlacklistDialogView);
+ }
+ })
+ .create();
+ dialog.setCanceledOnTouchOutside(false);
+ dialog.setCancelable(false);
+ return dialog;
+ case DLG_PRIVACY_GUARD:
+ final int messageResId;
+ if ((getOwner().mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ messageResId = R.string.privacy_guard_dlg_system_app_text;
+ } else {
+ messageResId = R.string.privacy_guard_dlg_text;
+ }
+
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.privacy_guard_dlg_title)
+ .setIconAttribute(android.R.attr.alertDialogIcon)
+ .setMessage(messageResId)
+ .setPositiveButton(R.string.dlg_ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ getOwner().setPrivacyGuard(true, false);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ })
+ .create();
}
throw new IllegalArgumentException("unknown id " + id);
}
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ int id = getArguments().getInt("id");
+ switch (id) {
+ case DLG_DISABLE_NOTIFICATIONS:
+ // Re-enable the checkbox
+ getOwner().mNotificationSwitch.setChecked(true);
+ break;
+ case DLG_PRIVACY_GUARD:
+ // Re-enable the checkbox
+ getOwner().mPrivacyGuardSwitch.setChecked(false);
+ break;
+ }
+ }
}
private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) {
@@ -1295,14 +1643,59 @@ protected Object doInBackground(Object... params) {
}
private void setNotificationsEnabled(boolean enabled) {
- String packageName = mAppEntry.info.packageName;
- INotificationManager nm = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ //String packageName = mAppEntry.info.packageName;
+ //INotificationManager nm = INotificationManager.Stub.asInterface(
+ // ServiceManager.getService(Context.NOTIFICATION_SERVICE));
try {
final boolean enable = mNotificationSwitch.isChecked();
- nm.setNotificationsEnabledForPackage(packageName, mAppEntry.info.uid, enabled);
+ mNotificationManager.setNotificationsEnabledForPackage(mAppEntry.info.packageName, mAppEntry.info.uid, enabled);
+ if (mHeadsUpSwitch != null) {
+ mHeadsUpSwitch.setEnabled(enable);
+ }
} catch (android.os.RemoteException ex) {
mNotificationSwitch.setChecked(!enabled); // revert
+ if (mHeadsUpSwitch != null) {
+ mHeadsUpSwitch.setEnabled(!enabled);
+ }
+ }
+ }
+
+ private void setPrivacyGuard(boolean enabled, boolean forceAll) {
+ mAppOps.setPrivacyGuardSettingForPackage(
+ mPackageInfo.applicationInfo.uid,
+ mPackageInfo.packageName, enabled, forceAll);
+ refreshUi();
+ }
+
+ private void setHaloState(boolean state) {
+ try {
+ mNotificationManager.setHaloStatus(mAppEntry.info.packageName, state);
+ } catch (android.os.RemoteException ex) {
+ mHaloState.setChecked(!state); // revert
+ }
+ }
+
+ private void setPeekState(boolean state) {
+ try {
+ mNotificationManager.setPeekBlacklistStatus(mAppEntry.info.packageName, state);
+ } catch (android.os.RemoteException ex) {
+ mPeekBlacklist.setChecked(!state); // revert
+ }
+ }
+
+ private void setFloatingModeState(boolean state) {
+ try {
+ mNotificationManager.setFloatingModeBlacklistStatus(mAppEntry.info.packageName, state);
+ } catch (android.os.RemoteException ex) {
+ mFloatingBlacklist.setChecked(!state); // revert
+ }
+ }
+
+ private void setHoverState(boolean state) {
+ try {
+ mNotificationManager.setHoverBlacklistStatus(mAppEntry.info.packageName, state);
+ } catch (android.os.RemoteException ex) {
+ mHoverBlacklist.setChecked(!state); // revert
}
}
@@ -1384,6 +1777,33 @@ public void onClick(View v) {
mMoveInProgress = true;
refreshButtons();
mPm.movePackage(mAppEntry.info.packageName, mPackageMoveObserver, moveFlags);
+ } else if (v == mAppOpsButton) {
+ Bundle args = new Bundle();
+ args.putString(AppOpsDetails.ARG_PACKAGE_NAME, mAppEntry.info.packageName);
+ PreferenceActivity pa = (PreferenceActivity) getActivity();
+ pa.startPreferencePanel(AppOpsDetails.class.getName(), args,
+ R.string.app_ops_settings, null, this, 2);
+ } else if (v == mCreateBackup) {
+ if (mCreateBackupObserver == null) {
+ mCreateBackupObserver = new CreateBackupObserver();
+ }
+ mBackupService.createBackup(packageName, mCreateBackupObserver);
+ } else if (v.getId() == R.id.restore) {
+ if (mRestoreBackupObserver == null) {
+ mRestoreBackupObserver = new RestoreBackupObserver();
+ }
+ View parent = (View) v.getParent();
+ BackupView bv = (BackupView) parent;
+ mBackupService.restoreBackup(bv.getBackup(), mRestoreBackupObserver);
+ } else if (v.getId() == R.id.delete) {
+ if (mDeleteBackupObserver == null) {
+ mDeleteBackupObserver = new DeleteBackupObserver();
+ }
+ View parent = (View) v.getParent();
+ BackupView bv = (BackupView) parent;
+ mBackupService.deleteBackup(bv.getBackup(), mDeleteBackupObserver);
+ } else if (v == mBlacklistButton) {
+ showDialogInner(DLG_BLACKLIST, 0);
}
}
@@ -1403,6 +1823,22 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
} else {
setNotificationsEnabled(true);
}
+ } else if (buttonView == mPrivacyGuardSwitch) {
+ if (isChecked) {
+ showDialogInner(DLG_PRIVACY_GUARD, 0);
+ } else {
+ setPrivacyGuard(false, false);
+ }
+ } else if (buttonView == mHaloState) {
+ setHaloState(isChecked);
+ } else if (buttonView == mPeekBlacklist) {
+ setPeekState(isChecked);
+ } else if (buttonView == mFloatingBlacklist) {
+ setFloatingModeState(isChecked);
+ } else if (buttonView == mHoverBlacklist) {
+ setHoverState(isChecked);
+ } else if (buttonView == mHeadsUpSwitch) {
+ mPm.setHeadsUpSetting(packageName, isChecked);
}
}
}
diff --git a/src/com/android/settings/applications/LinearColorBar.java b/src/com/android/settings/applications/LinearColorBar.java
index f374c293b32..79c8b886d1d 100644
--- a/src/com/android/settings/applications/LinearColorBar.java
+++ b/src/com/android/settings/applications/LinearColorBar.java
@@ -16,8 +16,8 @@
import android.widget.LinearLayout;
public class LinearColorBar extends LinearLayout {
- static final int LEFT_COLOR = 0xff0099cc;
- static final int MIDDLE_COLOR = 0xff0099cc;
+ static final int LEFT_COLOR = 0xffcccccc;
+ static final int MIDDLE_COLOR = 0xffcccccc;
static final int RIGHT_COLOR = 0xff888888;
static final int GRAY_COLOR = 0xff555555;
static final int WHITE_COLOR = 0xffffffff;
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index aa10c9e9d91..0506c83af1d 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -170,6 +170,8 @@ public class ManageApplications extends Fragment implements
public static final int SHOW_RUNNING_SERVICES = MENU_OPTIONS_BASE + 6;
public static final int SHOW_BACKGROUND_PROCESSES = MENU_OPTIONS_BASE + 7;
public static final int RESET_APP_PREFERENCES = MENU_OPTIONS_BASE + 8;
+ public static final int SHOW_PROTECTED_APPS = MENU_OPTIONS_BASE + 9;
+
// sort order
private int mSortOrder = SORT_ORDER_ALPHA;
@@ -261,6 +263,7 @@ public View build(LayoutInflater inflater, ViewGroup contentParent, View content
lv.setSaveEnabled(true);
lv.setItemsCanFocus(true);
lv.setTextFilterEnabled(true);
+ lv.setFastScrollEnabled(true);
mListView = lv;
mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter);
mListView.setAdapter(mApplications);
@@ -321,6 +324,12 @@ public void pause() {
}
}
+ public void release() {
+ if (mApplications != null) {
+ mApplications.release();
+ }
+ }
+
void updateStorageUsage() {
// Make sure a callback didn't come at an inopportune time.
if (mOwner.getActivity() == null) return;
@@ -593,6 +602,10 @@ public void pause() {
}
}
+ public void release() {
+ mSession.release();
+ }
+
public void rebuild(int sort) {
if (sort == mLastSortMode) {
return;
@@ -911,7 +924,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
mViewPager.setAdapter(adapter);
mViewPager.setOnPageChangeListener(adapter);
PagerTabStrip tabs = (PagerTabStrip) rootView.findViewById(R.id.tabs);
- tabs.setTabIndicatorColorResource(android.R.color.holo_blue_light);
+ tabs.setTabIndicatorColorResource(R.color.tab_selector);
// We have to do this now because PreferenceFrameLayout looks at it
// only when the view is added.
@@ -990,6 +1003,7 @@ public void onDestroyView() {
// are no longer attached to their view hierarchy.
for (int i=0; i getConnectedDevices() {
public boolean connect(BluetoothDevice device) {
if (mService == null) return false;
+ //Check if remote device supports AudioSink
+ if (!BluetoothUuid.isUuidPresent(device.getUuids(), BluetoothUuid.AudioSink)) {
+ Log.d(TAG,"Remote device doesn't support A2dpSink, Ignoring");
+ return false;
+ }
List sinks = getConnectedDevices();
if (sinks != null) {
for (BluetoothDevice sink : sinks) {
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
index 80a3d1f01c7..6343e2730c9 100644
--- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
@@ -19,11 +19,15 @@
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
import android.app.AlertDialog;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.os.UserManager;
import android.preference.Preference;
import android.text.Html;
@@ -54,6 +58,10 @@ public final class BluetoothDevicePreference extends Preference implements
private AlertDialog mDisconnectDialog;
+ private Context mContext;
+
+ private static final int OK_BUTTON = -1;
+
public BluetoothDevicePreference(Context context, CachedBluetoothDevice cachedDevice) {
super(context);
@@ -187,21 +195,32 @@ void onClicked() {
// Show disconnect confirmation dialog for a device.
private void askDisconnect() {
- Context context = getContext();
+ mContext = getContext();
String name = mCachedDevice.getName();
if (TextUtils.isEmpty(name)) {
- name = context.getString(R.string.bluetooth_device);
+ name = mContext.getString(R.string.bluetooth_device);
}
- String message = context.getString(R.string.bluetooth_disconnect_all_profiles, name);
- String title = context.getString(R.string.bluetooth_disconnect_title);
+ String message = mContext.getString(R.string.bluetooth_disconnect_all_profiles, name);
+ String title = mContext.getString(R.string.bluetooth_disconnect_title);
+
+ IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+ mContext.registerReceiver(mBluetoothReceiver, filter);
DialogInterface.OnClickListener disconnectListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
- mCachedDevice.disconnect();
+ // Disconnect only when user has selected OK
+ if (which == OK_BUTTON) {
+ mCachedDevice.disconnect();
+ }
+ try {
+ mContext.unregisterReceiver(mBluetoothReceiver);
+ } catch(IllegalArgumentException e) {
+ Log.e(TAG, "mBluetoothReceiver already unregistered");
+ }
}
};
- mDisconnectDialog = Utils.showDisconnectDialog(context,
+ mDisconnectDialog = Utils.showDisconnectDialog(mContext,
mDisconnectDialog, disconnectListener, title, Html.fromHtml(message));
}
@@ -232,7 +251,7 @@ private int getConnectionSummary() {
break;
case BluetoothProfile.STATE_DISCONNECTED:
- if (profile.isProfileReady() && profile.isPreferred(cachedDevice.getDevice())) {
+ if (profile.isProfileReady()) {
if (profile instanceof A2dpProfile) {
a2dpNotConnected = true;
} else if (profile instanceof HeadsetProfile) {
@@ -307,4 +326,22 @@ private int getBtClassDrawable() {
}
return 0;
}
+
+ private final BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+ switch (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) {
+ case BluetoothAdapter.STATE_TURNING_OFF:
+ Log.v(TAG, "Receiver DISABLED_ACTION ");
+ if (mDisconnectDialog != null && mDisconnectDialog.isShowing()) {
+ mDisconnectDialog.dismiss();
+ }
+ mContext.unregisterReceiver(mBluetoothReceiver);
+ break;
+ }
+ }
+ }
+ };
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java
index d687136e15d..1a4f32962ce 100755
--- a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java
+++ b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java
@@ -144,6 +144,10 @@ private void setEnabled(boolean enable) {
if (timeout > 0) {
BluetoothDiscoverableTimeoutReceiver.setDiscoverableAlarm(mContext, endTimestamp);
}
+ else if(timeout == 0) {
+ // cancel the previous alarms set for 2 mims/5 mins/ 1 hour
+ BluetoothDiscoverableTimeoutReceiver.cancelDiscoverableAlarm(mContext);
+ }
} else {
mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
BluetoothDiscoverableTimeoutReceiver.cancelDiscoverableAlarm(mContext);
diff --git a/src/com/android/settings/bluetooth/BluetoothEventManager.java b/src/com/android/settings/bluetooth/BluetoothEventManager.java
old mode 100755
new mode 100644
index 0eead8567b5..af7d9947748
--- a/src/com/android/settings/bluetooth/BluetoothEventManager.java
+++ b/src/com/android/settings/bluetooth/BluetoothEventManager.java
@@ -288,6 +288,14 @@ public void onReceive(Context context, Intent intent,
cachedDevice.setVisible(false);
}
}
+ if (cachedDevice.isRemovable()) {
+ synchronized (mCallbacks) {
+ for (BluetoothCallback callback : mCallbacks) {
+ callback.onDeviceDeleted(cachedDevice);
+ }
+ }
+ mDeviceManager.onDeviceDeleted(cachedDevice);
+ }
int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
BluetoothDevice.ERROR);
@@ -306,6 +314,7 @@ private void showUnbondMessage(Context context, String name, int reason) {
switch(reason) {
case BluetoothDevice.UNBOND_REASON_AUTH_FAILED:
+ case BluetoothDevice.UNBOND_REASON_REMOVED:
errorMsg = R.string.bluetooth_pairing_pin_error_message;
break;
case BluetoothDevice.UNBOND_REASON_AUTH_REJECTED:
@@ -350,7 +359,9 @@ public void onReceive(Context context, Intent intent, BluetoothDevice device) {
}
int errorMsg = R.string.bluetooth_pairing_error_message;
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
- Utils.showError(context, cachedDevice.getName(), errorMsg);
+ if (context != null && cachedDevice != null) {
+ Utils.showError(context, cachedDevice.getName(), errorMsg);
+ }
}
}
diff --git a/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java
index b80e42ac03a..d7ad4086107 100644
--- a/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java
@@ -189,7 +189,7 @@ public void afterTextChanged(Editable s) {
} else {
mDeviceNameEdited = true;
if (mOkButton != null) {
- mOkButton.setEnabled(s.length() != 0);
+ mOkButton.setEnabled(s.length() != 0 && !(s.toString().trim().isEmpty()));
}
}
}
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
index 9b2a3e89810..fa931171f78 100755
--- a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
@@ -60,6 +60,8 @@ public final class BluetoothPairingDialog extends AlertActivity implements
private String mPairingKey;
private EditText mPairingView;
private Button mOkButton;
+ private boolean mIsSecurityHigh;
+ private boolean mIsButtonPressed;
/**
* Dismiss the dialog if the bond state changes to bonded or none,
@@ -72,8 +74,8 @@ public void onReceive(Context context, Intent intent) {
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
BluetoothDevice.ERROR);
- if (bondState == BluetoothDevice.BOND_BONDED ||
- bondState == BluetoothDevice.BOND_NONE) {
+ if (((bondState == BluetoothDevice.BOND_BONDED) && (!mIsSecurityHigh) ) ||
+ (bondState == BluetoothDevice.BOND_NONE)) {
dismiss();
}
} else if (BluetoothDevice.ACTION_PAIRING_CANCEL.equals(action)) {
@@ -89,6 +91,8 @@ public void onReceive(Context context, Intent intent) {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mIsButtonPressed = false;
+
Intent intent = getIntent();
if (!intent.getAction().equals(BluetoothDevice.ACTION_PAIRING_REQUEST))
{
@@ -108,6 +112,8 @@ protected void onCreate(Bundle savedInstanceState) {
mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
mType = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
+ mIsSecurityHigh = intent.getBooleanExtra(BluetoothDevice.EXTRA_SECURE_PAIRING, false);
+ Log.i(TAG, "Secure is " + mIsSecurityHigh);
switch (mType) {
case BluetoothDevice.PAIRING_VARIANT_PIN:
@@ -188,7 +194,11 @@ private View createPinEntryView(String deviceName) {
int maxLength;
switch (mType) {
case BluetoothDevice.PAIRING_VARIANT_PIN:
- messageId1 = R.string.bluetooth_enter_pin_msg;
+ if (mIsSecurityHigh)
+ messageId1 = R.string.bluetooth_enter_pin_msg_hs;
+ else
+ messageId1 = R.string.bluetooth_enter_pin_msg;
+
messageId2 = R.string.bluetooth_enter_pin_other_device;
// Maximum of 16 characters in a PIN
maxLength = BLUETOOTH_PIN_MAX_LENGTH;
@@ -301,7 +311,13 @@ protected void onDestroy() {
public void afterTextChanged(Editable s) {
if (mOkButton != null) {
- mOkButton.setEnabled(s.length() > 0);
+ if (s.length() > 0 && !mIsSecurityHigh) {
+ mOkButton.setEnabled(true);
+ } else if (mIsSecurityHigh && s.length() == BLUETOOTH_PIN_MAX_LENGTH) {
+ mOkButton.setEnabled(true);
+ } else {
+ mOkButton.setEnabled(false);
+ }
}
}
@@ -351,6 +367,11 @@ public boolean onKeyDown(int keyCode, KeyEvent event) {
}
public void onClick(DialogInterface dialog, int which) {
+ if(mIsButtonPressed)
+ {
+ Log.e(TAG, "button already pressed");
+ return;
+ }
switch (which) {
case BUTTON_POSITIVE:
if (mPairingView != null) {
@@ -358,9 +379,11 @@ public void onClick(DialogInterface dialog, int which) {
} else {
onPair(null);
}
+ mIsButtonPressed = true;
break;
case BUTTON_NEGATIVE:
+ mIsButtonPressed = true;
default:
onCancel();
break;
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingRequest.java b/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
index 838e7b1b00e..090c6cc5eb1 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
@@ -48,10 +48,12 @@ public void onReceive(Context context, Intent intent) {
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
BluetoothDevice.ERROR);
+ boolean secure = intent.getBooleanExtra(BluetoothDevice.EXTRA_SECURE_PAIRING, false);
Intent pairingIntent = new Intent();
pairingIntent.setClass(context, BluetoothPairingDialog.class);
pairingIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
pairingIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, type);
+ pairingIntent.putExtra(BluetoothDevice.EXTRA_SECURE_PAIRING, secure);
if (type == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION ||
type == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY ||
type == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN) {
@@ -78,7 +80,7 @@ public void onReceive(Context context, Intent intent) {
.setTicker(res.getString(R.string.bluetooth_notif_ticker));
PendingIntent pending = PendingIntent.getActivity(context, 0,
- pairingIntent, PendingIntent.FLAG_ONE_SHOT);
+ pairingIntent, PendingIntent.FLAG_UPDATE_CURRENT);
String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
if (TextUtils.isEmpty(name)) {
@@ -98,11 +100,34 @@ public void onReceive(Context context, Intent intent) {
}
} else if (action.equals(BluetoothDevice.ACTION_PAIRING_CANCEL)) {
+ Intent pairingIntent = new Intent();
+
+ pairingIntent.setClass(context, BluetoothPairingDialog.class);
+ pairingIntent.setAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
+ pairingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ PendingIntent pending = PendingIntent.getActivity(context, 0,
+ pairingIntent, PendingIntent.FLAG_NO_CREATE);
+ if (pending != null) {
+ pending.cancel();
+ }
// Remove the notification
NotificationManager manager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(NOTIFICATION_ID);
+
+ } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
+ int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+ BluetoothDevice.ERROR);
+ int oldState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE,
+ BluetoothDevice.ERROR);
+ if((oldState == BluetoothDevice.BOND_BONDING) &&
+ (bondState == BluetoothDevice.BOND_NONE)) {
+ // Remove the notification
+ NotificationManager manager = (NotificationManager) context
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+ manager.cancel(NOTIFICATION_ID);
+ }
}
}
}
diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
index c3b93be9511..19041727921 100644
--- a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
+++ b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
@@ -96,6 +96,13 @@ public void onReceive(Context context, Intent intent) {
LocalBluetoothPreferences.shouldShowDialogInForeground(context, deviceAddress) ) {
context.startActivity(connectionAccessIntent);
} else {
+ // Acquire wakelock so that LCD comes up since screen is off
+ PowerManager.WakeLock wakeLock = null;
+ wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK |
+ PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE,
+ "ConnectionAccessActivity");
+ wakeLock.setReferenceCounted(false);
+ wakeLock.acquire();
// Put up a notification that leads to the dialog
// Create an intent triggered by clicking on the
@@ -140,6 +147,7 @@ public void onReceive(Context context, Intent intent) {
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(getNotificationTag(mRequestType),NOTIFICATION_ID, notification);
+ wakeLock.release();
}
} else if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL)) {
// Remove the notification
diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java
index 529ee79714f..1826fe8b795 100755
--- a/src/com/android/settings/bluetooth/BluetoothSettings.java
+++ b/src/com/android/settings/bluetooth/BluetoothSettings.java
@@ -32,6 +32,7 @@
import android.preference.PreferenceCategory;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
+import android.provider.Settings;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
@@ -54,6 +55,7 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment {
private static final int MENU_ID_RENAME_DEVICE = Menu.FIRST + 1;
private static final int MENU_ID_VISIBILITY_TIMEOUT = Menu.FIRST + 2;
private static final int MENU_ID_SHOW_RECEIVED = Menu.FIRST + 3;
+ private static final int MENU_ID_ACCEPT_ALL_FILES = Menu.FIRST + 4;
/* Private intent to show the list of received files */
private static final String BTOPP_ACTION_OPEN_RECEIVED_FILES =
@@ -175,6 +177,10 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
boolean isDiscovering = mLocalAdapter.isDiscovering();
int textId = isDiscovering ? R.string.bluetooth_searching_for_devices :
R.string.bluetooth_search_for_devices;
+
+ boolean acceptAllFilesIsEnabled = Settings.System.getInt(getContentResolver(),
+ Settings.System.BLUETOOTH_ACCEPT_ALL_FILES, 0) == 1;
+
menu.add(Menu.NONE, MENU_ID_SCAN, 0, textId)
.setEnabled(bluetoothIsEnabled && !isDiscovering)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
@@ -186,6 +192,10 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
menu.add(Menu.NONE, MENU_ID_SHOW_RECEIVED, 0, R.string.bluetooth_show_received_files)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ menu.add(Menu.NONE, MENU_ID_ACCEPT_ALL_FILES, 0, R.string.bluetooth_accept_all_files)
+ .setCheckable(true)
+ .setChecked(acceptAllFilesIsEnabled)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
super.onCreateOptionsMenu(menu, inflater);
}
@@ -212,6 +222,13 @@ public boolean onOptionsItemSelected(MenuItem item) {
Intent intent = new Intent(BTOPP_ACTION_OPEN_RECEIVED_FILES);
getActivity().sendBroadcast(intent);
return true;
+
+ case MENU_ID_ACCEPT_ALL_FILES:
+ item.setChecked(!item.isChecked());
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.BLUETOOTH_ACCEPT_ALL_FILES,
+ item.isChecked() ? 1 : 0);
+ return true;
}
return super.onOptionsItemSelected(item);
}
@@ -327,6 +344,10 @@ private void updateContent(int bluetoothState, boolean scanState) {
break;
case BluetoothAdapter.STATE_OFF:
+ /* reset the progress icon only when available device category present */
+ if(mAvailableDevicesCategoryIsPresent) {
+ ((BluetoothProgressCategory)mAvailableDevicesCategory).setProgress(false);
+ }
messageId = R.string.bluetooth_empty_list_bluetooth_off;
break;
diff --git a/src/com/android/settings/bluetooth/CachedBluetoothDevice.java b/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
old mode 100755
new mode 100644
index 12637974bfc..8983a5ea238
--- a/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
+++ b/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
@@ -16,6 +16,7 @@
package com.android.settings.bluetooth;
+import android.bluetooth.BluetoothUuid;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
@@ -64,6 +65,8 @@ final class CachedBluetoothDevice implements Comparable {
private boolean mVisible;
+ private boolean mDeviceRemove;
+
private int mPhonebookPermissionChoice;
private int mMessagePermissionChoice;
@@ -107,6 +110,8 @@ final class CachedBluetoothDevice implements Comparable {
// See mConnectAttempted
private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
+ private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
+
/** Auto-connect after pairing only if locally initiated. */
private boolean mConnectAfterPairing;
@@ -301,15 +306,26 @@ private boolean ensurePaired() {
}
boolean startPairing() {
+ if(mLocalAdapter.checkPairingState() == true)
+ {
+ Log.v(TAG, "Pairing is onging");
+ return true;
+ }
+
+ mLocalAdapter.setPairingState(true);
+ Log.v(TAG, "startPairing : isPairing : " + mLocalAdapter.checkPairingState());
+
// Pairing is unreliable while scanning, so cancel discovery
if (mLocalAdapter.isDiscovering()) {
mLocalAdapter.cancelDiscovery();
}
if (!mDevice.createBond()) {
+ mLocalAdapter.setPairingState(false);
return false;
}
+ Log.v(TAG, "startPairing CreateBond : isPairing : " + mLocalAdapter.checkPairingState());
mConnectAfterPairing = true; // auto-connect after pairing
return true;
}
@@ -335,8 +351,10 @@ void unpair() {
final boolean successful = dev.removeBond();
if (successful) {
if (Utils.D) {
+ mDevice.setAlias(null);
Log.d(TAG, "Command sent successfully:REMOVE_BOND " + describe(null));
}
+ setRemovable(true);
} else if (Utils.V) {
Log.v(TAG, "Framework rejected command immediately:REMOVE_BOND " +
describe(null));
@@ -394,6 +412,14 @@ void setName(String name) {
mName = mDevice.getAddress();
} else {
mName = name;
+ }
+ dispatchAttributesChanged();
+ }
+ }
+ void setAliasName(String name) {
+ if (!mName.equals(name)) {
+ if (!TextUtils.isEmpty(name)) {
+ mName = name;
mDevice.setAlias(name);
}
dispatchAttributesChanged();
@@ -422,6 +448,11 @@ boolean isVisible() {
return mVisible;
}
+ boolean isRemovable () {
+ return mDeviceRemove;
+ }
+
+
void setVisible(boolean visible) {
if (mVisible != visible) {
mVisible = visible;
@@ -429,6 +460,11 @@ void setVisible(boolean visible) {
}
}
+ void setRemovable(boolean removable) {
+ mDeviceRemove = removable;
+ }
+
+
int getBondState() {
return mDevice.getBondState();
}
@@ -517,18 +553,22 @@ void refreshBtClass() {
*/
void onUuidChanged() {
updateProfiles();
-
- if (DEBUG) {
- Log.e(TAG, "onUuidChanged: Time since last connect"
+ ParcelUuid[] uuids = mDevice.getUuids();
+ long timeout = MAX_UUID_DELAY_FOR_AUTO_CONNECT;
+ Log.d(TAG, "onUuidChanged: Time since last connect"
+ (SystemClock.elapsedRealtime() - mConnectAttempted));
- }
/*
* If a connect was attempted earlier without any UUID, we will do the
* connect now.
*/
+ if(BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp))
+ {
+ timeout = MAX_HOGP_DELAY_FOR_AUTO_CONNECT;
+ }
+ Log.d(TAG, "onUuidChanged timeout value="+timeout);
if (!mProfiles.isEmpty()
- && (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock
+ && (mConnectAttempted + timeout) > SystemClock
.elapsedRealtime()) {
connectWithoutResettingTimer(false);
}
@@ -537,6 +577,7 @@ void onUuidChanged() {
void onBondingStateChanged(int bondState) {
if (bondState == BluetoothDevice.BOND_NONE) {
+ mLocalAdapter.setPairingState(false);
mProfiles.clear();
mConnectAfterPairing = false; // cancel auto-connect
setPhonebookPermissionChoice(ACCESS_UNKNOWN);
@@ -545,17 +586,44 @@ void onBondingStateChanged(int bondState) {
savePhonebookRejectTimes();
mMessageRejectedTimes = 0;
saveMessageRejectTimes();
- }
-
- refresh();
+ Log.v(TAG,"onBondingstate none: isPairing : " + mLocalAdapter.checkPairingState());
+ }
+
+ if(DEBUG) Log.d(TAG, "onBondingStateChanged" + bondState);
+
+ switch (bondState) {
+ case BluetoothDevice.BOND_NONE:
+ mLocalAdapter.setPairingState(false);
+ mProfiles.clear();
+ mConnectAfterPairing = false; // cancel auto-connect
+ // fall through
+
+ case BluetoothDevice.BOND_BONDING:
+ //Sometimes Remote device is unpaired by itself & try to connect again.
+ //so permission should be reset for that particular device.
+ setPhonebookPermissionChoice(ACCESS_UNKNOWN);
+ setMessagePermissionChoice(ACCESS_UNKNOWN);
+ mPhonebookRejectedTimes = 0;
+ savePhonebookRejectTimes();
+ mMessageRejectedTimes = 0;
+ saveMessageRejectTimes();
+
+ refresh();
+ break;
+
+ case BluetoothDevice.BOND_BONDED:
+ mLocalAdapter.setPairingState(false);
+ if (mDevice.isBluetoothDock()) {
+ onBondingDockConnect();
+ } else if (mConnectAfterPairing) {
+ connect(false);
+ }
+ mConnectAfterPairing = false;
+ Log.v(TAG,"BondState bonded: isPairing : " + mLocalAdapter.checkPairingState());
+ break;
- if (bondState == BluetoothDevice.BOND_BONDED) {
- if (mDevice.isBluetoothDock()) {
- onBondingDockConnect();
- } else if (mConnectAfterPairing) {
- connect(false);
- }
- mConnectAfterPairing = false;
+ default:
+ Log.e(TAG, "Incorrect Bond State received");
}
}
diff --git a/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java b/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java
index ff282cc67c9..004caceb8c7 100755
--- a/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java
+++ b/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java
@@ -111,13 +111,17 @@ public String getName(BluetoothDevice device) {
}
public synchronized void onScanningStateChanged(boolean started) {
- if (!started) return;
-
// If starting a new scan, clear old visibility
// Iterate in reverse order since devices may be removed.
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
- cachedDevice.setVisible(false);
+ if (started) {
+ cachedDevice.setVisible(false);
+ } else if (!started &&
+ cachedDevice.getBondState() == BluetoothDevice.BOND_NONE &&
+ cachedDevice.isRemovable()) {
+ mCachedDevices.remove(cachedDevice);
+ }
}
}
@@ -135,6 +139,15 @@ public synchronized void onUuidChanged(BluetoothDevice device) {
}
}
+ public synchronized void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
+ Log.d(TAG,"onDeviceDeleted");
+ if (cachedDevice != null &&
+ cachedDevice.getBondState() == BluetoothDevice.BOND_NONE &&
+ cachedDevice.isRemovable()) {
+ mCachedDevices.remove(cachedDevice);
+ }
+ }
+
public synchronized void onBluetoothStateChanged(int bluetoothState) {
// When Bluetooth is turning off, we need to clear the non-bonded devices
// Otherwise, they end up showing up on the next BT enable
diff --git a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
index e2faf7fd546..c61b2a2ea69 100644
--- a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
+++ b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
@@ -130,6 +130,23 @@ void addCachedDevices() {
}
}
+ void removeOorDevices() {
+ Collection cachedDevices =
+ mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
+ for (CachedBluetoothDevice cachedDevice : cachedDevices) {
+ if (cachedDevice.getBondState() == BluetoothDevice.BOND_NONE &&
+ !cachedDevice.isVisible()) {
+ Log.d(TAG, "Device Removed " + cachedDevice);
+ BluetoothDevicePreference preference = mDevicePreferenceMap.get(cachedDevice);
+ if (preference != null) {
+ mDeviceListGroup.removePreference(preference);
+ }
+ mDevicePreferenceMap.remove(cachedDevice);
+ cachedDevice.setRemovable(true);
+ }
+ }
+ }
+
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
@@ -191,6 +208,9 @@ public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
}
public void onScanningStateChanged(boolean started) {
+ if (started == false) {
+ removeOorDevices();
+ }
updateProgressUi(started);
}
diff --git a/src/com/android/settings/bluetooth/DeviceProfilesSettings.java b/src/com/android/settings/bluetooth/DeviceProfilesSettings.java
old mode 100755
new mode 100644
index 335d88835d4..c4765affd00
--- a/src/com/android/settings/bluetooth/DeviceProfilesSettings.java
+++ b/src/com/android/settings/bluetooth/DeviceProfilesSettings.java
@@ -60,6 +60,8 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
private CachedBluetoothDevice mCachedDevice;
private LocalBluetoothProfileManager mProfileManager;
+ private static final int OK_BUTTON = -1;
+
private PreferenceGroup mProfileContainer;
private EditTextPreference mDeviceNamePref;
@@ -238,7 +240,7 @@ public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference prefere
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == mDeviceNamePref) {
- mCachedDevice.setName((String) newValue);
+ mCachedDevice.setAliasName((String) newValue);
} else if (preference instanceof CheckBoxPreference) {
LocalBluetoothProfile prof = getProfileOf(preference);
onProfileClicked(prof, (CheckBoxPreference) preference);
@@ -256,14 +258,17 @@ private void onProfileClicked(LocalBluetoothProfile profile, CheckBoxPreference
int status = profile.getConnectionStatus(device);
boolean isConnected =
status == BluetoothProfile.STATE_CONNECTED;
-
if (isConnected) {
askDisconnect(getActivity(), profile);
} else {
if (profile.isPreferred(device)) {
// profile is preferred but not connected: disable auto-connect
- profile.setPreferred(device, false);
- refreshProfilePreference(profilePref, profile);
+ if (profile instanceof PanProfile) {
+ mCachedDevice.connectProfile(profile);
+ } else {
+ profile.setPreferred(device, false);
+ refreshProfilePreference(profilePref, profile);
+ }
} else {
profile.setPreferred(device, true);
mCachedDevice.connectProfile(profile);
@@ -289,8 +294,11 @@ private void askDisconnect(Context context,
DialogInterface.OnClickListener disconnectListener =
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
- device.disconnect(profile);
- profile.setPreferred(device.getDevice(), false);
+ // Disconnect only when user has selected OK
+ if (which == OK_BUTTON) {
+ device.disconnect(profile);
+ profile.setPreferred(device.getDevice(), false);
+ }
}
};
@@ -338,7 +346,13 @@ private void refreshProfilePreference(CheckBoxPreference profilePref,
* Gray out checkbox while connecting and disconnecting
*/
profilePref.setEnabled(!mCachedDevice.isBusy());
- profilePref.setChecked(profile.isPreferred(device));
+ if (profile instanceof PanProfile) {
+ profilePref.setChecked(profile.getConnectionStatus(device) ==
+ BluetoothProfile.STATE_CONNECTED);
+ }
+ else {
+ profilePref.setChecked(profile.isPreferred(device));
+ }
profilePref.setSummary(profile.getSummaryResourceForDevice(device));
}
diff --git a/src/com/android/settings/bluetooth/DunServerProfile.java b/src/com/android/settings/bluetooth/DunServerProfile.java
new file mode 100644
index 00000000000..b7556c95489
--- /dev/null
+++ b/src/com/android/settings/bluetooth/DunServerProfile.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothDun;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.util.Log;
+
+import com.android.settings.R;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * DunServerProfile handles Bluetooth DUN server profile.
+ */
+final class DunServerProfile implements LocalBluetoothProfile {
+ private static final String TAG = "DunServerProfile";
+ private static boolean V = true;
+
+ private BluetoothDun mService;
+ private boolean mIsProfileReady;
+
+ static final String NAME = "DUN Server";
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 11;
+
+ // These callbacks run on the main thread.
+ private final class DunServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (V) Log.d(TAG,"Bluetooth service connected");
+ mService = (BluetoothDun) proxy;
+ mIsProfileReady = true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (V) Log.d(TAG,"Bluetooth service disconnected");
+ mIsProfileReady = false;
+ }
+ }
+
+ public boolean isProfileReady() {
+ return mIsProfileReady;
+ }
+
+ DunServerProfile(Context context) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ adapter.getProfileProxy(context, new DunServiceListener(),
+ BluetoothProfile.DUN);
+ }
+
+ public boolean isConnectable() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return false;
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ return false;
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ if (mService == null) return false;
+ return mService.disconnect(device);
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ return true;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ return -1;
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ // ignore: isPreferred is always true for DUN
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource(BluetoothDevice device) {
+ return R.string.bluetooth_profile_dun;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = getConnectionStatus(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_dun_profile_summary_use_for;
+
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_dun_profile_summary_connected;
+ default:
+ return Utils.getConnectionStateSummary(state);
+ }
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return R.drawable.ic_bt_network_pan;
+ }
+
+ protected void finalize() {
+ if (V) Log.d(TAG, "finalize()");
+ if (mService != null) {
+ try {
+ BluetoothAdapter.getDefaultAdapter().closeProfileProxy
+ (BluetoothProfile.DUN, mService);
+ mService = null;
+ } catch (Throwable t) {
+ Log.w(TAG, "Error cleaning up DUN proxy", t);
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/HidProfile.java b/src/com/android/settings/bluetooth/HidProfile.java
old mode 100755
new mode 100644
index 8df2845cb3a..d1977927678
--- a/src/com/android/settings/bluetooth/HidProfile.java
+++ b/src/com/android/settings/bluetooth/HidProfile.java
@@ -112,11 +112,8 @@ public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
}
- List deviceList = mService.getConnectedDevices();
- return !deviceList.isEmpty() && deviceList.get(0).equals(device)
- ? mService.getConnectionState(device)
- : BluetoothProfile.STATE_DISCONNECTED;
+ return mService.getConnectionState(device);
}
public boolean isPreferred(BluetoothDevice device) {
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java b/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java
index 013171c14e6..12ee9b9009f 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java
@@ -49,7 +49,7 @@ public final class LocalBluetoothAdapter {
private static final int SCAN_EXPIRATION_MS = 5 * 60 * 1000; // 5 mins
private long mLastScan;
-
+ public static boolean isPairing = false;
private LocalBluetoothAdapter(BluetoothAdapter adapter) {
mAdapter = adapter;
}
@@ -82,10 +82,12 @@ void cancelDiscovery() {
}
boolean enable() {
+ isPairing = false;
return mAdapter.enable();
}
boolean disable() {
+ isPairing = false;
return mAdapter.disable();
}
@@ -199,7 +201,7 @@ public void setBluetoothEnabled(boolean enabled) {
boolean success = enabled
? mAdapter.enable()
: mAdapter.disable();
-
+ isPairing = false;
if (success) {
setBluetoothStateInt(enabled
? BluetoothAdapter.STATE_TURNING_ON
@@ -213,4 +215,12 @@ public void setBluetoothEnabled(boolean enabled) {
syncBluetoothState();
}
}
+
+ public boolean checkPairingState(){
+ return isPairing;
+ }
+
+ public void setPairingState(boolean state){
+ isPairing = state;
+ }
}
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
index 8fff964878d..947e0f4cc4b 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
@@ -22,6 +22,8 @@
import android.bluetooth.BluetoothMap;
import android.bluetooth.BluetoothInputDevice;
import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothSap;
+import android.bluetooth.BluetoothDun;
import android.bluetooth.BluetoothPbap;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
@@ -38,6 +40,7 @@
import java.util.Map;
import java.util.Set;
import java.util.List;
+import android.os.SystemProperties;
/**
* LocalBluetoothProfileManager provides access to the LocalBluetoothProfile
@@ -84,6 +87,8 @@ public interface ServiceListener {
private final HidProfile mHidProfile;
private OppProfile mOppProfile;
private final PanProfile mPanProfile;
+ private SapServerProfile mSapProfile;
+ private DunServerProfile mDunProfile;
private final PbapServerProfile mPbapProfile;
/**
@@ -126,6 +131,19 @@ public interface ServiceListener {
mDeviceManager, this);
addProfile(mMapProfile, MapProfile.NAME,
BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
+ // enable SAP only if the property is set
+ if (SystemProperties.getBoolean("ro.bluetooth.sap", false) == true) {
+ mSapProfile = new SapServerProfile(context);
+ addProfile(mSapProfile, SapServerProfile.NAME,
+ BluetoothSap.ACTION_CONNECTION_STATE_CHANGED);
+ }
+ // enable DUN only if the property is set
+ if (SystemProperties.getBoolean("ro.bluetooth.dun", false) == true) {
+ mDunProfile = new DunServerProfile(context);
+ addProfile(mDunProfile, DunServerProfile.NAME,
+ BluetoothDun.ACTION_CONNECTION_STATE_CHANGED);
+ }
+
//Create PBAP server profile, but do not add it to list of profiles
// as we do not need to monitor the profile as part of profile list
@@ -224,21 +242,29 @@ private class StateChangedHandler implements BluetoothEventManager.Handler {
}
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+ int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
+ int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
+ if (DEBUG) {
+ Log.d(TAG, mProfile + " state change " + oldState + " -> " + newState);
+ }
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
- if (cachedDevice == null) {
+
+ if ((cachedDevice == null) && ((newState != BluetoothProfile.STATE_DISCONNECTED)
+ && (newState != BluetoothProfile.STATE_DISCONNECTING))) {
Log.w(TAG, "StateChangedHandler found new device: " + device);
cachedDevice = mDeviceManager.addDevice(mLocalAdapter,
LocalBluetoothProfileManager.this, device);
}
- int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
- int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
+
if (newState == BluetoothProfile.STATE_DISCONNECTED &&
oldState == BluetoothProfile.STATE_CONNECTING) {
Log.i(TAG, "Failed to connect " + mProfile + " device");
}
- cachedDevice.onProfileStateChanged(mProfile, newState);
- cachedDevice.refresh();
+ if (cachedDevice != null) {
+ cachedDevice.onProfileStateChanged(mProfile, newState);
+ cachedDevice.refresh();
+ }
}
}
@@ -341,10 +367,21 @@ synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids,
}
}
- if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
- mA2dpProfile != null) {
- profiles.add(mA2dpProfile);
- removedProfiles.remove(mA2dpProfile);
+ if (SystemProperties.getBoolean("bluetooth.a2dp.sink.enabled", true)) {
+ Log.d(TAG, "a2dpSinkSupported, check for both sink and source UUIDs");
+ if ((BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SOURCE_UUIDS) ||
+ BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS))&&
+ mA2dpProfile != null) {
+ profiles.add(mA2dpProfile);
+ removedProfiles.remove(mA2dpProfile);
+ }
+ } else {
+ Log.d(TAG, "a2dpSinkNotSupported, check for only sink UUIDs");
+ if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
+ mA2dpProfile != null) {
+ profiles.add(mA2dpProfile);
+ removedProfiles.remove(mA2dpProfile);
+ }
}
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
diff --git a/src/com/android/settings/bluetooth/PanProfile.java b/src/com/android/settings/bluetooth/PanProfile.java
index f6e06915544..b9db77b2b24 100755
--- a/src/com/android/settings/bluetooth/PanProfile.java
+++ b/src/com/android/settings/bluetooth/PanProfile.java
@@ -106,8 +106,7 @@ public int getConnectionStatus(BluetoothDevice device) {
}
public boolean isPreferred(BluetoothDevice device) {
- // return current connection status so profile checkbox is set correctly
- return getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED;
+ return true;
}
public int getPreferred(BluetoothDevice device) {
diff --git a/src/com/android/settings/bluetooth/SapServerProfile.java b/src/com/android/settings/bluetooth/SapServerProfile.java
new file mode 100644
index 00000000000..e728db32ae9
--- /dev/null
+++ b/src/com/android/settings/bluetooth/SapServerProfile.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothSap;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.util.Log;
+
+import com.android.settings.R;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * SapServerProfile handles Bluetooth SAP server profile.
+ */
+final class SapServerProfile implements LocalBluetoothProfile {
+ private static final String TAG = "SapServerProfile";
+ private static boolean V = true;
+
+ private BluetoothSap mService;
+ private boolean mIsProfileReady;
+
+ static final String NAME = "SAP Server";
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 10;
+
+ // These callbacks run on the main thread.
+ private final class SapServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (V) Log.d(TAG,"Bluetooth service connected");
+ mService = (BluetoothSap) proxy;
+ mIsProfileReady=true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (V) Log.d(TAG,"Bluetooth service disconnected");
+ mIsProfileReady=false;
+ }
+ }
+
+ public boolean isProfileReady() {
+ return mIsProfileReady;
+ }
+
+ SapServerProfile(Context context) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ adapter.getProfileProxy(context, new SapServiceListener(),
+ BluetoothProfile.SAP);
+ }
+
+ public boolean isConnectable() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return false;
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ return false;
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ if (mService == null) return false;
+ return mService.disconnect(device);
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ return true;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ return -1;
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ // ignore: isPreferred is always true for SAP
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource(BluetoothDevice device) {
+ return R.string.bluetooth_profile_sap;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = getConnectionStatus(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_sap_profile_summary_use_for;
+
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_sap_profile_summary_connected;
+ default:
+ return Utils.getConnectionStateSummary(state);
+ }
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return R.drawable.ic_bt_network_pan;
+ }
+
+ protected void finalize() {
+ if (V) Log.d(TAG, "finalize()");
+ if (mService != null) {
+ try {
+ BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.SAP, mService);
+ mService = null;
+ }catch (Throwable t) {
+ Log.w(TAG, "Error cleaning up SAP proxy", t);
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/Utils.java b/src/com/android/settings/bluetooth/Utils.java
old mode 100755
new mode 100644
index fb44d5a38b0..2a871739510
--- a/src/com/android/settings/bluetooth/Utils.java
+++ b/src/com/android/settings/bluetooth/Utils.java
@@ -60,7 +60,7 @@ static AlertDialog showDisconnectDialog(Context context,
if (dialog == null) {
dialog = new AlertDialog.Builder(context)
.setPositiveButton(android.R.string.ok, disconnectListener)
- .setNegativeButton(android.R.string.cancel, null)
+ .setNegativeButton(android.R.string.cancel, disconnectListener)
.create();
} else {
if (dialog.isShowing()) {
diff --git a/src/com/android/settings/deviceinfo/Memory.java b/src/com/android/settings/deviceinfo/Memory.java
index 999611d12d2..52fef32b618 100644
--- a/src/com/android/settings/deviceinfo/Memory.java
+++ b/src/com/android/settings/deviceinfo/Memory.java
@@ -177,8 +177,7 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
public void onPrepareOptionsMenu(Menu menu) {
final MenuItem usb = menu.findItem(R.id.storage_usb);
UserManager um = (UserManager)getActivity().getSystemService(Context.USER_SERVICE);
- boolean usbItemVisible = !isMassStorageEnabled()
- && !um.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
+ boolean usbItemVisible = !um.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
usb.setVisible(usbItemVisible);
}
diff --git a/src/com/android/settings/deviceinfo/Status.java b/src/com/android/settings/deviceinfo/Status.java
index 6a15027e117..1b6730375df 100644
--- a/src/com/android/settings/deviceinfo/Status.java
+++ b/src/com/android/settings/deviceinfo/Status.java
@@ -50,6 +50,8 @@
import com.android.settings.R;
import com.android.settings.Utils;
+import org.cyanogenmod.hardware.SerialNumber;
+
import java.lang.ref.WeakReference;
/**
@@ -296,7 +298,7 @@ protected void onCreate(Bundle icicle) {
setBtStatus();
setIpAddressStatus();
- String serial = Build.SERIAL;
+ String serial = getSerialNumber();
if (serial != null && !serial.equals("")) {
setSummaryText(KEY_SERIAL_NUMBER, serial);
} else {
@@ -549,4 +551,16 @@ private String convert(long t) {
return h + ":" + pad(m) + ":" + pad(s);
}
+
+ private String getSerialNumber() {
+ try {
+ if (SerialNumber.isSupported()) {
+ return SerialNumber.getSerialNumber();
+ }
+ } catch (NoClassDefFoundError e) {
+ // Hardware abstraction framework not installed; fall through
+ }
+
+ return Build.SERIAL;
+ }
}
diff --git a/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java b/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
index ed5085a2a50..1719875d747 100644
--- a/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
+++ b/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
@@ -16,6 +16,8 @@
package com.android.settings.deviceinfo;
+import android.app.Activity;
+import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.DownloadManager;
@@ -25,28 +27,40 @@
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
+import android.media.MediaScannerConnection;
+import android.media.MediaScannerConnection.OnScanCompletedListener;
+import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.os.UserManager;
+import android.os.Environment.UserEnvironment;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.provider.MediaStore;
import android.text.format.Formatter;
+import android.util.Log;
+import android.widget.Toast;
import com.android.settings.R;
import com.android.settings.deviceinfo.StorageMeasurement.MeasurementDetails;
import com.android.settings.deviceinfo.StorageMeasurement.MeasurementReceiver;
+import com.android.settings.deviceinfo.UsageBarPreference.OnRequestMediaRescanListener;
import com.google.android.collect.Lists;
+import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
-public class StorageVolumePreferenceCategory extends PreferenceCategory {
+public class StorageVolumePreferenceCategory extends PreferenceCategory
+ implements OnRequestMediaRescanListener, OnScanCompletedListener {
+
+ public static final String TAG = "StorageVolumePreferenceCategory";
+
public static final String KEY_CACHE = "cache";
private static final int ORDER_USAGE_BAR = -2;
@@ -55,6 +69,8 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory {
/** Physical volume being measured, or {@code null} for internal. */
private final StorageVolume mVolume;
private final StorageMeasurement mMeasure;
+ private final boolean mIsInternal;
+ private final boolean mIsPrimary;
private final Resources mResources;
private final StorageManager mStorageManager;
@@ -121,6 +137,8 @@ private StorageVolumePreferenceCategory(Context context, StorageVolume volume) {
super(context);
mVolume = volume;
+ mIsInternal = mVolume == null;
+ mIsPrimary = mVolume != null ? mVolume.isPrimary() : false;
mMeasure = StorageMeasurement.getInstance(context, volume);
mResources = context.getResources();
@@ -150,8 +168,17 @@ public void init() {
final List otherUsers = getUsersExcluding(currentUser);
final boolean showUsers = mVolume == null && otherUsers.size() > 0;
+ boolean allowMediaScan = false;
+ if ((mIsInternal && Environment.isExternalStorageEmulated()) || mIsPrimary) {
+ allowMediaScan = true;
+ } else if (mVolume != null && !mVolume.isRemovable()) {
+ allowMediaScan = true;
+ }
+
mUsageBarPreference = new UsageBarPreference(context);
mUsageBarPreference.setOrder(ORDER_USAGE_BAR);
+ mUsageBarPreference.setOnRequestMediaRescanListener(this);
+ mUsageBarPreference.setAllowMediaScan(allowMediaScan);
addPreference(mUsageBarPreference);
mItemTotal = buildItem(R.string.memory_size, 0);
@@ -213,19 +240,24 @@ public void init() {
addPreference(mFormatPreference);
}
- final IPackageManager pm = ActivityThread.getPackageManager();
- try {
- if (pm.isStorageLow()) {
- mStorageLow = new Preference(context);
- mStorageLow.setOrder(ORDER_STORAGE_LOW);
- mStorageLow.setTitle(R.string.storage_low_title);
- mStorageLow.setSummary(R.string.storage_low_summary);
- addPreference(mStorageLow);
- } else if (mStorageLow != null) {
- removePreference(mStorageLow);
- mStorageLow = null;
+ // The low storage warning is only valid for the internal memory.
+ // Same condition as for (showDetails) above.
+ final boolean showLowStorage = mVolume == null || mVolume.isPrimary();
+ if (showLowStorage) {
+ final IPackageManager pm = ActivityThread.getPackageManager();
+ try {
+ if (pm.isStorageLow()) {
+ mStorageLow = new Preference(context);
+ mStorageLow.setOrder(ORDER_STORAGE_LOW);
+ mStorageLow.setTitle(R.string.storage_low_title);
+ mStorageLow.setSummary(R.string.storage_low_summary);
+ addPreference(mStorageLow);
+ } else if (mStorageLow != null) {
+ removePreference(mStorageLow);
+ mStorageLow = null;
+ }
+ } catch (RemoteException e) {
}
- } catch (RemoteException e) {
}
}
@@ -283,7 +315,7 @@ private void updatePreferencesFromState() {
mFormatPreference.setSummary(mResources.getString(R.string.mtp_ptp_mode_summary));
}
} else if (mFormatPreference != null) {
- mFormatPreference.setEnabled(true);
+ mFormatPreference.setEnabled(mMountTogglePreference.isEnabled());
mFormatPreference.setSummary(mResources.getString(R.string.sd_format_summary));
}
}
@@ -477,4 +509,37 @@ private List getUsersExcluding(UserInfo excluding) {
}
return users;
}
+
+ @Override
+ public void onRequestMediaRescan() {
+ final int currentUser = ActivityManager.getCurrentUser();
+ final UserEnvironment currentEnv = new UserEnvironment(currentUser);
+
+ File path = null;
+ if ((mIsInternal && Environment.isExternalStorageEmulated()) || mIsPrimary) {
+ path = currentEnv.getExternalStorageDirectory();
+ } else {
+ path = mVolume.getPathFile();
+ }
+
+ Log.d(TAG, "Request scan of " + path.getAbsolutePath());
+ MediaScannerConnection.scanFile(
+ getContext(), new String[]{path.getAbsolutePath()}, null, this);
+ }
+
+ @Override
+ public void onScanCompleted(String path, final Uri uri) {
+ if (uri != null) {
+ measure();
+ }
+ ((Activity)getContext()).runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mUsageBarPreference.notifyScanCompleted();
+ if (uri != null) {
+ Toast.makeText(getContext(), R.string.storage_rescan_media_complete, Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+ }
}
diff --git a/src/com/android/settings/deviceinfo/UsageBarPreference.java b/src/com/android/settings/deviceinfo/UsageBarPreference.java
index 371c7728837..63620fbeba3 100644
--- a/src/com/android/settings/deviceinfo/UsageBarPreference.java
+++ b/src/com/android/settings/deviceinfo/UsageBarPreference.java
@@ -17,9 +17,13 @@
package com.android.settings.deviceinfo;
import android.content.Context;
+import android.os.Handler;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
import com.android.settings.R;
import com.google.android.collect.Lists;
@@ -31,23 +35,42 @@
* Creates a percentage bar chart inside a preference.
*/
public class UsageBarPreference extends Preference {
+
+ public interface OnRequestMediaRescanListener {
+ void onRequestMediaRescan();
+ }
+
+ private ImageView mRescanMedia = null;
+ private ProgressBar mRescanMediaWaiting = null;
private PercentageBarChart mChart = null;
+ private boolean mAllowMediaScan;
+
+ private OnRequestMediaRescanListener mOnRequestMediaRescanListener;
+
private final List mEntries = Lists.newArrayList();
+ private Handler mHandler;
+
public UsageBarPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- setLayoutResource(R.layout.preference_memoryusage);
+ init();
}
public UsageBarPreference(Context context) {
super(context);
- setLayoutResource(R.layout.preference_memoryusage);
+ init();
}
public UsageBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
+ init();
+ }
+
+ private void init() {
setLayoutResource(R.layout.preference_memoryusage);
+ mHandler = new Handler();
+ mAllowMediaScan = false;
}
public void addEntry(int order, float percentage, int color) {
@@ -55,12 +78,49 @@ public void addEntry(int order, float percentage, int color) {
Collections.sort(mEntries);
}
+ protected void setOnRequestMediaRescanListener(OnRequestMediaRescanListener listener) {
+ mOnRequestMediaRescanListener = listener;
+ }
+
+ protected void setAllowMediaScan(boolean allow) {
+ mAllowMediaScan = allow;
+ notifyScanCompleted();
+ }
+
+ protected void notifyScanCompleted() {
+ if (mRescanMedia != null) {
+ mRescanMedia.setVisibility(mAllowMediaScan ? View.VISIBLE : View.INVISIBLE);
+ mRescanMediaWaiting.setVisibility(View.GONE);
+ }
+ }
+
@Override
protected void onBindView(View view) {
super.onBindView(view);
mChart = (PercentageBarChart) view.findViewById(R.id.percentage_bar_chart);
mChart.setEntries(mEntries);
+
+ mRescanMediaWaiting = (ProgressBar) view.findViewById(R.id.memory_usage_rescan_media_waiting);
+
+ mRescanMedia = (ImageView) view.findViewById(R.id.memory_usage_rescan_media);
+ mRescanMedia.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mOnRequestMediaRescanListener != null) {
+ mRescanMedia.setVisibility(View.GONE);
+ mRescanMediaWaiting.setVisibility(View.VISIBLE);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mOnRequestMediaRescanListener.onRequestMediaRescan();
+ }
+ });
+ }
+ }
+ });
+
+ notifyScanCompleted();
}
public void commit() {
diff --git a/src/com/android/settings/deviceinfo/UsbSettings.java b/src/com/android/settings/deviceinfo/UsbSettings.java
index 42de2fd5d69..e6cfd4c8934 100644
--- a/src/com/android/settings/deviceinfo/UsbSettings.java
+++ b/src/com/android/settings/deviceinfo/UsbSettings.java
@@ -23,6 +23,8 @@
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceScreen;
@@ -41,10 +43,14 @@ public class UsbSettings extends SettingsPreferenceFragment {
private static final String KEY_MTP = "usb_mtp";
private static final String KEY_PTP = "usb_ptp";
+ private static final String KEY_MASS_STORAGE = "usb_mass_storage";
private UsbManager mUsbManager;
+ private StorageManager storageManager;
+ private StorageVolume[] storageVolumes;
private CheckBoxPreference mMtp;
private CheckBoxPreference mPtp;
+ private CheckBoxPreference mUms;
private boolean mUsbAccessoryMode;
private final BroadcastReceiver mStateReceiver = new BroadcastReceiver() {
@@ -68,11 +74,16 @@ private PreferenceScreen createPreferenceHierarchy() {
mMtp = (CheckBoxPreference)root.findPreference(KEY_MTP);
mPtp = (CheckBoxPreference)root.findPreference(KEY_PTP);
+ mUms = (CheckBoxPreference)root.findPreference(KEY_MASS_STORAGE);
+ if (!storageVolumes[0].allowMassStorage()) {
+ root.removePreference(mUms);
+ }
UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
if (um.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
mMtp.setEnabled(false);
mPtp.setEnabled(false);
+ mUms.setEnabled(false);
}
return root;
@@ -82,6 +93,8 @@ private PreferenceScreen createPreferenceHierarchy() {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+ storageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
+ storageVolumes = storageManager.getVolumeList();
}
@Override
@@ -104,30 +117,27 @@ public void onResume() {
}
private void updateToggles(String function) {
- if (UsbManager.USB_FUNCTION_MTP.equals(function)) {
- mMtp.setChecked(true);
- mPtp.setChecked(false);
- } else if (UsbManager.USB_FUNCTION_PTP.equals(function)) {
- mMtp.setChecked(false);
- mPtp.setChecked(true);
- } else {
- mMtp.setChecked(false);
- mPtp.setChecked(false);
- }
+ mMtp.setChecked(UsbManager.USB_FUNCTION_MTP.equals(function));
+ mPtp.setChecked(UsbManager.USB_FUNCTION_PTP.equals(function));
+ mUms.setChecked(UsbManager.USB_FUNCTION_MASS_STORAGE.equals(function));
+
UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
if (um.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
Log.e(TAG, "USB is locked down");
mMtp.setEnabled(false);
mPtp.setEnabled(false);
+ mUms.setEnabled(false);
} else if (!mUsbAccessoryMode) {
//Enable MTP and PTP switch while USB is not in Accessory Mode, otherwise disable it
Log.e(TAG, "USB Normal Mode");
mMtp.setEnabled(true);
mPtp.setEnabled(true);
+ mUms.setEnabled(true);
} else {
Log.e(TAG, "USB Accessory Mode");
mMtp.setEnabled(false);
mPtp.setEnabled(false);
+ mUms.setEnabled(false);
}
}
@@ -151,6 +161,8 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
function = UsbManager.USB_FUNCTION_MTP;
} else if (preference == mPtp && mPtp.isChecked()) {
function = UsbManager.USB_FUNCTION_PTP;
+ } else if (preference == mUms && mUms.isChecked()) {
+ function = UsbManager.USB_FUNCTION_MASS_STORAGE;
}
mUsbManager.setCurrentFunction(function, true);
diff --git a/src/com/android/settings/fuelgauge/BatterySipper.java b/src/com/android/settings/fuelgauge/BatterySipper.java
index fcc8f697044..43ae437ec96 100644
--- a/src/com/android/settings/fuelgauge/BatterySipper.java
+++ b/src/com/android/settings/fuelgauge/BatterySipper.java
@@ -132,10 +132,12 @@ void getQuickNameIconForUid(Uid uidObj) {
final String uidString = Integer.toString(uid);
if (sUidCache.containsKey(uidString)) {
UidToDetail utd = sUidCache.get(uidString);
- defaultPackageName = utd.packageName;
- name = utd.name;
- icon = utd.icon;
- return;
+ if (utd != null) {
+ defaultPackageName = utd.packageName;
+ name = utd.name;
+ icon = utd.icon;
+ return;
+ }
}
PackageManager pm = mContext.getPackageManager();
String[] packages = pm.getPackagesForUid(uid);
diff --git a/src/com/android/settings/fuelgauge/BatteryStatsHelper.java b/src/com/android/settings/fuelgauge/BatteryStatsHelper.java
index 0191692a17e..a557522143e 100644
--- a/src/com/android/settings/fuelgauge/BatteryStatsHelper.java
+++ b/src/com/android/settings/fuelgauge/BatteryStatsHelper.java
@@ -29,6 +29,7 @@
import android.hardware.SensorManager;
import android.os.BatteryStats;
import android.os.BatteryStats.Uid;
+import android.os.BatteryManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcel;
@@ -142,7 +143,7 @@ public void clearStats() {
public BatteryStatsImpl getStats() {
if (mStats == null) {
- load();
+ loadStats();
}
return mStats;
}
@@ -322,6 +323,7 @@ public void startBatteryDetailPage(
/**
* Refreshes the power usage list.
+ * @parma context The current context
* @param includeZeroConsumption whether includes those applications which have consumed very
* little power up till now.
*/
@@ -820,7 +822,7 @@ public double getTotalPower() {
return mTotalPower;
}
- private void load() {
+ private void loadStats() {
try {
byte[] data = mBatteryInfo.getStatistics();
Parcel parcel = Parcel.obtain();
@@ -833,4 +835,12 @@ private void load() {
Log.e(TAG, "RemoteException:", e);
}
}
+
+ public void resetStatistics() {
+ try {
+ mBatteryInfo.resetStatistics();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException:", e);
+ }
+ }
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 0ce72b882f9..d7a07c7cb14 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -21,25 +21,21 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Parcel;
-import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
-import android.preference.PreferenceCategory;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
-import android.preference.Preference.OnPreferenceChangeListener;
-import android.provider.Settings;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-import android.view.SubMenu;
import com.android.internal.os.PowerProfile;
import com.android.settings.HelpUtils;
@@ -51,8 +47,7 @@
* Displays a list of apps and subsystems that consume power, ordered by how much power was
* consumed since the last time it was unplugged.
*/
-public class PowerUsageSummary extends PreferenceFragment implements
- Preference.OnPreferenceChangeListener {
+public class PowerUsageSummary extends PreferenceFragment {
private static final boolean DEBUG = false;
@@ -60,32 +55,23 @@ public class PowerUsageSummary extends PreferenceFragment implements
private static final String KEY_APP_LIST = "app_list";
private static final String KEY_BATTERY_STATUS = "battery_status";
- private static final String KEY_LOW_BATTERY_WARNING_POLICY = "pref_low_battery_warning_policy";
- private static final String KEY_BATTERY_INDICATOR = "pref_battery_indicator";
- private static final String KEY_BATTERY_PREFS_CATEGORY = "battery_prefs";
- private static final String KEY_BATTERY_STATS_CATEGORY = "battery_stats";
-
- private static final int MENU_STATS_TYPE = Menu.FIRST;
- private static final int MENU_STATS_REFRESH = Menu.FIRST + 1;
- private static final int MENU_BATTERY_STYLE = Menu.FIRST + 2;
- private static final int SUBMENU_BATTERY_BAR = Menu.FIRST + 3;
- private static final int SUBMENU_BATTERY_BAR_PERCENT = Menu.FIRST + 4;
- private static final int SUBMENU_BATTERY_CIRCLE = Menu.FIRST + 5;
- private static final int SUBMENU_BATTERY_CIRCLE_PERCENT = Menu.FIRST + 6;
- private static final int MENU_HELP = Menu.FIRST + 7;
+ private static final String KEY_BATTERY_SAVER = "pref_battery_saver";
+
+ private static final int MENU_STATS_TYPE = Menu.FIRST;
+ private static final int MENU_STATS_REFRESH = Menu.FIRST + 1;
+ private static final int MENU_STATS_RESET = Menu.FIRST + 2;
+ private static final int MENU_HELP = Menu.FIRST + 3;
private PreferenceGroup mAppListGroup;
private Preference mBatteryStatusPref;
- private ListPreference mLowBatteryWarning;
- private ListPreference mBatteryIndicator;
- private PreferenceCategory mBatteryPrefsCat;
- private PreferenceCategory mBatteryStatsCat;
+ private PreferenceScreen mBatterySaverPrefs;
private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
private static final int MIN_POWER_THRESHOLD = 5;
- private static final int MAX_ITEMS_TO_LIST = 10;
+ private static final int MAX_ITEMS_TO_LIST = 10;
+ private BatteryManager mBatteryService;
private BatteryStatsHelper mStatsHelper;
private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
@@ -116,31 +102,14 @@ public void onAttach(Activity activity) {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mStatsHelper.create(icicle);
+ mBatteryService = (BatteryManager) getActivity().getSystemService(Context.BATTERY_SERVICE);
addPreferencesFromResource(R.xml.power_usage_summary);
mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST);
mBatteryStatusPref = mAppListGroup.findPreference(KEY_BATTERY_STATUS);
- mBatteryPrefsCat =
- (PreferenceCategory) mAppListGroup.findPreference(KEY_BATTERY_PREFS_CATEGORY);
- mBatteryStatsCat =
- (PreferenceCategory) mAppListGroup.findPreference(KEY_BATTERY_STATS_CATEGORY);
-
- mLowBatteryWarning =
- (ListPreference) mAppListGroup.findPreference(KEY_LOW_BATTERY_WARNING_POLICY);
- int lowBatteryWarning = Settings.System.getInt(getActivity().getContentResolver(),
- Settings.System.POWER_UI_LOW_BATTERY_WARNING_POLICY, 0);
- mLowBatteryWarning.setValue(String.valueOf(lowBatteryWarning));
- mLowBatteryWarning.setSummary(mLowBatteryWarning.getEntry());
- mLowBatteryWarning.setOnPreferenceChangeListener(this);
-
- mBatteryIndicator =
- (ListPreference) mAppListGroup.findPreference(KEY_BATTERY_INDICATOR);
- int batteryIndicator = Settings.System.getInt(getActivity().getContentResolver(),
- Settings.System.STATUS_BAR_BATTERY_STYLE, 0);
- mBatteryIndicator.setValue(String.valueOf(batteryIndicator));
- mBatteryIndicator.setSummary(mBatteryIndicator.getEntry());
- mBatteryIndicator.setOnPreferenceChangeListener(this);
+ mBatterySaverPrefs =
+ (PreferenceScreen) mAppListGroup.findPreference(KEY_BATTERY_SAVER);
setHasOptionsMenu(true);
}
@@ -180,6 +149,9 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
R.string.history_details_title, null, null, 0);
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
+ if (preference == mBatterySaverPrefs) {
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
+ }
if (!(preference instanceof PowerGaugePreference)) {
return false;
}
@@ -189,27 +161,6 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- if (preference == mLowBatteryWarning) {
- int lowBatteryWarning = Integer.valueOf((String) newValue);
- int index = mLowBatteryWarning.findIndexOfValue((String) newValue);
- Settings.System.putInt(getActivity().getContentResolver(),
- Settings.System.POWER_UI_LOW_BATTERY_WARNING_POLICY,
- lowBatteryWarning);
- mLowBatteryWarning.setSummary(mLowBatteryWarning.getEntries()[index]);
- return true;
- } else if (preference == mBatteryIndicator) {
- int batteryIndicator = Integer.valueOf((String) newValue);
- int index = mBatteryIndicator.findIndexOfValue((String) newValue);
- Settings.System.putInt(getActivity().getContentResolver(),
- Settings.System.STATUS_BAR_BATTERY_STYLE,
- batteryIndicator);
- mBatteryIndicator.setSummary(mBatteryIndicator.getEntries()[index]);
- return true;
- }
- return false;
- }
-
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (DEBUG) {
@@ -220,7 +171,13 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
MenuItem refresh = menu.add(0, MENU_STATS_REFRESH, 0, R.string.menu_stats_refresh)
.setIcon(R.drawable.ic_menu_refresh_holo_dark)
.setAlphabeticShortcut('r');
- refresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ refresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
+ MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ MenuItem reset = menu.add(0, MENU_STATS_RESET, 0, R.string.reset)
+ .setIcon(R.drawable.ic_menu_delete_holo_dark)
+ .setAlphabeticShortcut('d');
+ reset.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
+ MenuItem.SHOW_AS_ACTION_WITH_TEXT);
String helpUrl;
if (!TextUtils.isEmpty(helpUrl = getResources().getString(R.string.help_url_battery))) {
@@ -244,6 +201,11 @@ public boolean onOptionsItemSelected(MenuItem item) {
mStatsHelper.clearStats();
refreshStats();
return true;
+ case MENU_STATS_RESET:
+ mStatsHelper.resetStatistics();
+ mStatsHelper.clearStats();
+ refreshStats();
+ return true;
default:
return false;
}
@@ -259,15 +221,8 @@ private void refreshStats() {
mAppListGroup.removeAll();
mAppListGroup.setOrderingAsAdded(false);
- mBatteryPrefsCat.setOrder(-6);
- mAppListGroup.addPreference(mBatteryPrefsCat);
- mLowBatteryWarning.setOrder(-5);
- mAppListGroup.addPreference(mLowBatteryWarning);
- mBatteryIndicator.setOrder(-4);
- mAppListGroup.addPreference(mBatteryIndicator);
- mBatteryStatsCat.setOrder(-3);
- mAppListGroup.addPreference(mBatteryStatsCat);
-
+ mBatterySaverPrefs.setOrder(-6);
+ mAppListGroup.addPreference(mBatterySaverPrefs);
mBatteryStatusPref.setOrder(-2);
mAppListGroup.addPreference(mBatteryStatusPref);
BatteryHistoryPreference hist = new BatteryHistoryPreference(
@@ -281,6 +236,7 @@ private void refreshStats() {
return;
}
mStatsHelper.refreshStats(false);
+ int sipperCount = 0;
List usageList = mStatsHelper.getUsageList();
for (BatterySipper sipper : usageList) {
if (sipper.getSortValue() < MIN_POWER_THRESHOLD) continue;
@@ -299,7 +255,8 @@ private void refreshStats() {
pref.setKey(Integer.toString(sipper.uidObj.getUid()));
}
mAppListGroup.addPreference(pref);
- if (mAppListGroup.getPreferenceCount() > (MAX_ITEMS_TO_LIST+1)) break;
+ sipperCount++;
+ if (sipperCount >= MAX_ITEMS_TO_LIST) break;
}
}
diff --git a/src/com/android/settings/fuelgauge/Utils.java b/src/com/android/settings/fuelgauge/Utils.java
index 1ff358ea1b2..9a06c9f2fcb 100644
--- a/src/com/android/settings/fuelgauge/Utils.java
+++ b/src/com/android/settings/fuelgauge/Utils.java
@@ -44,15 +44,15 @@ public static String formatElapsedTime(Context context, double millis, boolean i
}
int days = 0, hours = 0, minutes = 0;
- if (seconds > SECONDS_PER_DAY) {
+ if (seconds >= SECONDS_PER_DAY) {
days = seconds / SECONDS_PER_DAY;
seconds -= days * SECONDS_PER_DAY;
}
- if (seconds > SECONDS_PER_HOUR) {
+ if (seconds >= SECONDS_PER_HOUR) {
hours = seconds / SECONDS_PER_HOUR;
seconds -= hours * SECONDS_PER_HOUR;
}
- if (seconds > SECONDS_PER_MINUTE) {
+ if (seconds >= SECONDS_PER_MINUTE) {
minutes = seconds / SECONDS_PER_MINUTE;
seconds -= minutes * SECONDS_PER_MINUTE;
}
diff --git a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
index 34c806d3157..e2dea1c5649 100644
--- a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
+++ b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
@@ -65,9 +65,11 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
private static final String KEY_CURRENT_INPUT_METHOD = "current_input_method";
private static final String KEY_INPUT_METHOD_SELECTOR = "input_method_selector";
private static final String KEY_USER_DICTIONARY_SETTINGS = "key_user_dictionary_settings";
+ private static final String KEY_POINTER_SETTINGS_CATEGORY = "pointer_settings_category";
+ private static final String KEY_TRACKPAD_SETTINGS = "gesture_pad_settings";
private static final String KEY_STYLUS_ICON_ENABLED = "stylus_icon_enabled";
private static final String KEY_STYLUS_GESTURES = "stylus_gestures";
- private static final String KEY_POINTER_SETTINGS_CATEGORY = "pointer_settings_category";
+
// false: on ICS or later
private static final boolean SHOW_INPUT_METHOD_SWITCHER_SETTINGS = false;
@@ -79,9 +81,9 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
"auto_replace", "auto_caps", "auto_punctuate",
};
+ private CheckBoxPreference mStylusIconEnabled;
private int mDefaultInputMethodSelectorVisibility = 0;
private ListPreference mShowInputMethodSelectorPref;
- private CheckBoxPreference mStylusIconEnabled;
private PreferenceCategory mKeyboardSettingsCategory;
private PreferenceCategory mHardKeyboardCategory;
private PreferenceCategory mGameControllerCategory;
@@ -175,16 +177,22 @@ public void onCreate(Bundle icicle) {
mIm = (InputManager)getActivity().getSystemService(Context.INPUT_SERVICE);
updateInputDevices();
- mStylusIconEnabled = (CheckBoxPreference) findPreference(KEY_STYLUS_ICON_ENABLED);
+ PreferenceCategory pointerSettingsCategory = (PreferenceCategory)
+ findPreference(KEY_POINTER_SETTINGS_CATEGORY);
mStylusGestures = (PreferenceScreen) findPreference(KEY_STYLUS_GESTURES);
- // remove stylus preference for non stylus devices
- if (!getResources().getBoolean(com.android.internal.R.bool.config_stylusGestures)) {
- PreferenceCategory pointerSettingsCategory = (PreferenceCategory)
- findPreference(KEY_POINTER_SETTINGS_CATEGORY);
- if(pointerSettingsCategory != null) {
+ mStylusIconEnabled = (CheckBoxPreference) findPreference(KEY_STYLUS_ICON_ENABLED);
+
+ if (pointerSettingsCategory != null) {
+ // remove stylus preference for non stylus devices
+ if (!getResources().getBoolean(com.android.internal.R.bool.config_stylusGestures)) {
pointerSettingsCategory.removePreference(mStylusGestures);
pointerSettingsCategory.removePreference(mStylusIconEnabled);
}
+ Utils.updatePreferenceToSpecificActivityFromMetaDataOrRemove(getActivity(),
+ pointerSettingsCategory, KEY_TRACKPAD_SETTINGS);
+ if (pointerSettingsCategory.getPreferenceCount() == 0) {
+ getPreferenceScreen().removePreference(pointerSettingsCategory);
+ }
}
// Spell Checker
@@ -354,7 +362,10 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
if (Utils.isMonkeyRunning()) {
return false;
}
- if (preference instanceof PreferenceScreen) {
+ if (preference == mStylusIconEnabled) {
+ Settings.System.putInt(getActivity().getContentResolver(),
+ Settings.System.STYLUS_ICON_ENABLED, mStylusIconEnabled.isChecked() ? 1 : 0);
+ } else if (preference instanceof PreferenceScreen) {
if (preference.getFragment() != null) {
// Fragment will be handled correctly by the super class.
} else if (KEY_CURRENT_INPUT_METHOD.equals(preference.getKey())) {
@@ -362,9 +373,6 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showInputMethodPicker();
}
- } else if (preference == mStylusIconEnabled) {
- Settings.System.putInt(getActivity().getContentResolver(),
- Settings.System.STYLUS_ICON_ENABLED, mStylusIconEnabled.isChecked() ? 1 : 0);
} else if (preference instanceof CheckBoxPreference) {
final CheckBoxPreference chkPref = (CheckBoxPreference) preference;
if (!mHardKeyboardPreferenceList.isEmpty()) {
diff --git a/src/com/android/settings/inputmethod/StylusGestures.java b/src/com/android/settings/inputmethod/StylusGestures.java
index 172d7144489..5661adc4d55 100644
--- a/src/com/android/settings/inputmethod/StylusGestures.java
+++ b/src/com/android/settings/inputmethod/StylusGestures.java
@@ -24,7 +24,6 @@
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.Bundle;
-import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceScreen;
@@ -40,7 +39,6 @@ public class StylusGestures extends SettingsPreferenceFragment implements
Preference.OnPreferenceChangeListener {
public static final String TAG = "Stylus Gestures";
- public static final String KEY_SPEN_ENABLE = "enable_spen";
public static final String KEY_SPEN_LEFT = "gestures_left";
public static final String KEY_SPEN_RIGHT = "gestures_right";
public static final String KEY_SPEN_UP = "gestures_up";
@@ -50,7 +48,6 @@ public class StylusGestures extends SettingsPreferenceFragment implements
public static final int KEY_NO_ACTION = 1000;
public static final String TEXT_NO_ACTION = "No Action";
- private CheckBoxPreference mEnableGestures;
private ListPreference mSwipeLeft;
private ListPreference mSwipeRight;
private ListPreference mSwipeUp;
@@ -75,11 +72,6 @@ public void onCreate(Bundle savedInstanceState) {
mActionNames = resources.getStringArray(R.array.gestures_entries);
mActionValues = resources.getStringArray(R.array.gestures_values);
- // Setup the preferences
- mEnableGestures = (CheckBoxPreference) findPreference(KEY_SPEN_ENABLE);
- mEnableGestures.setChecked(Settings.System.getInt(mResolver,
- Settings.System.ENABLE_STYLUS_GESTURES, 0) == 1);
-
// Setup the gestures
mSwipeLeft = setupGesturePref(KEY_SPEN_LEFT, Settings.System.GESTURES_LEFT_SWIPE);
mSwipeRight = setupGesturePref(KEY_SPEN_RIGHT, Settings.System.GESTURES_RIGHT_SWIPE);
@@ -97,18 +89,6 @@ private ListPreference setupGesturePref(String key, String settingName) {
return pref;
}
- @Override
- public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
- Preference preference) {
- if (preference == mEnableGestures) {
- Settings.System.putInt(mResolver,
- Settings.System.ENABLE_STYLUS_GESTURES,
- ((CheckBoxPreference) preference).isChecked() ? 1 : 0);
- return true;
- }
- return super.onPreferenceTreeClick(preferenceScreen, preference);
- }
-
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String settingName = null;
diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java
index 06a6650565d..5f1d4aaf2c5 100644
--- a/src/com/android/settings/location/LocationSettings.java
+++ b/src/com/android/settings/location/LocationSettings.java
@@ -18,17 +18,24 @@
import android.app.ActionBar;
import android.app.Activity;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.location.SettingInjectorService;
import android.os.Bundle;
+import android.preference.CheckBoxPreference;
import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceGroup;
+import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.util.Log;
@@ -37,6 +44,9 @@
import android.widget.Switch;
import com.android.settings.R;
+import org.regulus.amrasettings.utils.LtoService;
+
+import org.cyanogenmod.hardware.LongTermOrbits;
import java.util.Collections;
import java.util.Comparator;
@@ -46,12 +56,14 @@
* Location access settings.
*/
public class LocationSettings extends LocationSettingsBase
- implements CompoundButton.OnCheckedChangeListener {
+ implements CompoundButton.OnCheckedChangeListener, OnPreferenceChangeListener {
private static final String TAG = "LocationSettings";
/** Key for preference screen "Mode" */
private static final String KEY_LOCATION_MODE = "location_mode";
+ /** Key for preference screen "LTO - WiFi Only" */
+ public static final String KEY_GPS_DOWNLOAD_DATA_WIFI_ONLY = "gps_download_data_wifi_only";
/** Key for preference category "Recent location requests" */
private static final String KEY_RECENT_LOCATION_REQUESTS = "recent_location_requests";
/** Key for preference category "Location services" */
@@ -60,6 +72,7 @@ public class LocationSettings extends LocationSettingsBase
private Switch mSwitch;
private boolean mValidListener;
private Preference mLocationMode;
+ private CheckBoxPreference mGpsDownloadDataWifiOnly;
private PreferenceCategory mCategoryRecentLocationRequests;
/** Receives UPDATE_INTENT */
private BroadcastReceiver mReceiver;
@@ -124,6 +137,17 @@ public boolean onPreferenceClick(Preference preference) {
}
});
+ mGpsDownloadDataWifiOnly =
+ (CheckBoxPreference) root.findPreference(KEY_GPS_DOWNLOAD_DATA_WIFI_ONLY);
+ if (mGpsDownloadDataWifiOnly != null) {
+ if (!isLtoSupported() || !checkGpsDownloadWiFiOnly(getActivity())) {
+ root.removePreference(mGpsDownloadDataWifiOnly);
+ mGpsDownloadDataWifiOnly = null;
+ } else {
+ mGpsDownloadDataWifiOnly.setOnPreferenceChangeListener(this);
+ }
+ }
+
mCategoryRecentLocationRequests =
(PreferenceCategory) root.findPreference(KEY_RECENT_LOCATION_REQUESTS);
RecentLocationApps recentApps = new RecentLocationApps(activity);
@@ -229,6 +253,9 @@ public void onModeChanged(int mode, boolean restricted) {
// be disabled but checked.
boolean enabled = (mode != Settings.Secure.LOCATION_MODE_OFF);
mSwitch.setEnabled(!restricted);
+ if (mGpsDownloadDataWifiOnly != null) {
+ mGpsDownloadDataWifiOnly.setEnabled(enabled && !restricted);
+ }
mLocationMode.setEnabled(enabled && !restricted);
mCategoryRecentLocationRequests.setEnabled(enabled);
@@ -250,9 +277,78 @@ public void onModeChanged(int mode, boolean restricted) {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
- setLocationMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
+ final int lastMode = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.LOCATION_LAST_MODE,
+ Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
+ setLocationMode(lastMode);
} else {
setLocationMode(Settings.Secure.LOCATION_MODE_OFF);
}
}
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (mGpsDownloadDataWifiOnly != null && preference.equals(mGpsDownloadDataWifiOnly)) {
+ updateLtoServiceStatus(getActivity(), isLocationModeEnabled(getActivity()));
+ }
+ return true;
+ }
+
+ private static void updateLtoServiceStatus(Context context, boolean start) {
+ Intent intent = new Intent(context, LtoService.class);
+ if (start) {
+ context.startService(intent);
+ } else {
+ context.stopService(intent);
+ }
+ }
+
+ private static boolean checkGpsDownloadWiFiOnly(Context context) {
+ PackageManager pm = context.getPackageManager();
+ boolean supportsTelephony = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+ boolean supportsWifi = pm.hasSystemFeature(PackageManager.FEATURE_WIFI);
+ if (!supportsWifi || !supportsTelephony) {
+ SharedPreferences.Editor editor =
+ PreferenceManager.getDefaultSharedPreferences(context).edit();
+ editor.putBoolean(KEY_GPS_DOWNLOAD_DATA_WIFI_ONLY, supportsWifi);
+ editor.apply();
+ return false;
+ }
+ return true;
+ }
+
+ public static boolean isLocationModeEnabled(Context context) {
+ int mode = Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
+ return (mode != Settings.Secure.LOCATION_MODE_OFF);
+ }
+
+ /**
+ * Restore the properties associated with this preference on boot
+ * @param ctx A valid context
+ */
+ public static void restore(final Context context) {
+ if (isLtoSupported() && isLocationModeEnabled(context)) {
+ // Check and adjust the value for Gps download data on wifi only
+ checkGpsDownloadWiFiOnly(context);
+
+ // Starts the LtoService, but delayed 2 minutes after boot (this should give a
+ // proper time to start all device services)
+ AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ Intent intent = new Intent(context, LtoService.class);
+ PendingIntent pi = PendingIntent.getService(context, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
+ long nextLtoDownload = System.currentTimeMillis() + (1000 * 60 * 2L);
+ am.set(AlarmManager.RTC, nextLtoDownload, pi);
+ }
+ }
+
+ private static boolean isLtoSupported() {
+ try {
+ return LongTermOrbits.isSupported();
+ } catch (NoClassDefFoundError e) {
+ // Hardware abstraction framework isn't installed
+ return false;
+ }
+ }
}
diff --git a/src/com/android/settings/location/LocationSettingsBase.java b/src/com/android/settings/location/LocationSettingsBase.java
index 86c2ee5e873..dec93dc070c 100644
--- a/src/com/android/settings/location/LocationSettingsBase.java
+++ b/src/com/android/settings/location/LocationSettingsBase.java
@@ -94,6 +94,10 @@ public void setLocationMode(int mode) {
intent.putExtra(CURRENT_MODE_KEY, mCurrentMode);
intent.putExtra(NEW_MODE_KEY, mode);
getActivity().sendBroadcast(intent, android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ if (mode != Settings.Secure.LOCATION_MODE_OFF) {
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.LOCATION_LAST_MODE, mode);
+ }
Settings.Secure.putInt(getContentResolver(), Settings.Secure.LOCATION_MODE, mode);
refreshLocationMode();
}
diff --git a/src/com/android/settings/net/NetworkPolicyEditor.java b/src/com/android/settings/net/NetworkPolicyEditor.java
index bfdaf99020d..040c30f026b 100644
--- a/src/com/android/settings/net/NetworkPolicyEditor.java
+++ b/src/com/android/settings/net/NetworkPolicyEditor.java
@@ -17,6 +17,8 @@
package com.android.settings.net;
import static android.net.NetworkPolicy.CYCLE_NONE;
+import static android.net.NetworkPolicy.CYCLE_MONTHLY;
+import static android.net.NetworkPolicy.CYCLE_WEEKLY;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -36,12 +38,12 @@
import android.text.TextUtils;
import android.text.format.Time;
-import com.android.internal.util.Objects;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Objects;
/**
* Utility class to modify list of {@link NetworkPolicy}. Specifically knows
@@ -140,27 +142,30 @@ public NetworkPolicy getPolicyMaybeUnquoted(NetworkTemplate template) {
private static NetworkPolicy buildDefaultPolicy(NetworkTemplate template) {
// TODO: move this into framework to share with NetworkPolicyManagerService
final int cycleDay;
+ final int cycleLength;
final String cycleTimezone;
final boolean metered;
if (template.getMatchRule() == MATCH_WIFI) {
- cycleDay = CYCLE_NONE;
+ cycleDay = cycleLength = CYCLE_NONE;
cycleTimezone = Time.TIMEZONE_UTC;
metered = false;
} else {
final Time time = new Time();
time.setToNow();
cycleDay = time.monthDay;
+ cycleLength = CYCLE_MONTHLY;
cycleTimezone = time.timezone;
metered = true;
}
- return new NetworkPolicy(template, cycleDay, cycleTimezone, WARNING_DISABLED,
+ return new NetworkPolicy(template, cycleDay, cycleLength, cycleTimezone, WARNING_DISABLED,
LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, metered, true);
}
public int getPolicyCycleDay(NetworkTemplate template) {
- return getPolicy(template).cycleDay;
+ final NetworkPolicy policy = getPolicy(template);
+ return (policy != null) ? policy.cycleDay : -1;
}
public void setPolicyCycleDay(NetworkTemplate template, int cycleDay, String cycleTimezone) {
@@ -172,8 +177,21 @@ public void setPolicyCycleDay(NetworkTemplate template, int cycleDay, String cyc
writeAsync();
}
+ public int getPolicyCycleLength(NetworkTemplate template) {
+ return getPolicy(template).cycleLength;
+ }
+
+ public void setPolicyCycleLength(NetworkTemplate template, int cycleLength) {
+ final NetworkPolicy policy = getOrCreatePolicy(template);
+ policy.cycleLength = cycleLength;
+ policy.inferred = false;
+ policy.clearSnooze();
+ writeAsync();
+ }
+
public long getPolicyWarningBytes(NetworkTemplate template) {
- return getPolicy(template).warningBytes;
+ final NetworkPolicy policy = getPolicy(template);
+ return (policy != null) ? policy.warningBytes : WARNING_DISABLED;
}
public void setPolicyWarningBytes(NetworkTemplate template, long warningBytes) {
@@ -185,7 +203,8 @@ public void setPolicyWarningBytes(NetworkTemplate template, long warningBytes) {
}
public long getPolicyLimitBytes(NetworkTemplate template) {
- return getPolicy(template).limitBytes;
+ final NetworkPolicy policy = getPolicy(template);
+ return (policy != null) ? policy.limitBytes : LIMIT_DISABLED;
}
public void setPolicyLimitBytes(NetworkTemplate template, long limitBytes) {
@@ -265,7 +284,7 @@ public boolean isMobilePolicySplit(String subscriberId) {
boolean has4g = false;
for (NetworkPolicy policy : mPolicies) {
final NetworkTemplate template = policy.template;
- if (Objects.equal(subscriberId, template.getSubscriberId())) {
+ if (Objects.equals(subscriberId, template.getSubscriberId())) {
switch (template.getMatchRule()) {
case MATCH_MOBILE_3G_LOWER:
has3g = true;
@@ -309,25 +328,37 @@ private boolean setMobilePolicySplitInternal(String subscriberId, boolean split)
final NetworkPolicy policy3g = getPolicy(template3g);
final NetworkPolicy policy4g = getPolicy(template4g);
- final NetworkPolicy restrictive = policy3g.compareTo(policy4g) < 0 ? policy3g
- : policy4g;
+ NetworkPolicy restrictive = null;
+ if ((policy3g == null) && (policy4g == null)) {
+ return false;
+ } else if (policy3g == null) {
+ restrictive = policy4g;
+ } else if (policy4g == null) {
+ restrictive = policy3g;
+ } else {
+ restrictive = policy3g.compareTo(policy4g) < 0 ? policy3g : policy4g;
+ }
mPolicies.remove(policy3g);
mPolicies.remove(policy4g);
mPolicies.add(new NetworkPolicy(templateAll, restrictive.cycleDay,
- restrictive.cycleTimezone, restrictive.warningBytes, restrictive.limitBytes,
- SNOOZE_NEVER, SNOOZE_NEVER, restrictive.metered, restrictive.inferred));
+ restrictive.cycleLength, restrictive.cycleTimezone, restrictive.warningBytes,
+ restrictive.limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, restrictive.metered,
+ restrictive.inferred));
return true;
} else if (!beforeSplit && split) {
// duplicate existing policy into two rules
final NetworkPolicy policyAll = getPolicy(templateAll);
+ if (policyAll == null) {
+ return false;
+ }
mPolicies.remove(policyAll);
- mPolicies.add(new NetworkPolicy(template3g, policyAll.cycleDay, policyAll.cycleTimezone,
- policyAll.warningBytes, policyAll.limitBytes, SNOOZE_NEVER, SNOOZE_NEVER,
- policyAll.metered, policyAll.inferred));
- mPolicies.add(new NetworkPolicy(template4g, policyAll.cycleDay, policyAll.cycleTimezone,
- policyAll.warningBytes, policyAll.limitBytes, SNOOZE_NEVER, SNOOZE_NEVER,
- policyAll.metered, policyAll.inferred));
+ mPolicies.add(new NetworkPolicy(template3g, policyAll.cycleDay, policyAll.cycleLength,
+ policyAll.cycleTimezone, policyAll.warningBytes, policyAll.limitBytes,
+ SNOOZE_NEVER, SNOOZE_NEVER, policyAll.metered, policyAll.inferred));
+ mPolicies.add(new NetworkPolicy(template4g, policyAll.cycleDay, policyAll.cycleLength,
+ policyAll.cycleTimezone, policyAll.warningBytes, policyAll.limitBytes,
+ SNOOZE_NEVER, SNOOZE_NEVER, policyAll.metered, policyAll.inferred));
return true;
} else {
return false;
diff --git a/src/com/android/settings/slim/InputMethodsSettings.java b/src/com/android/settings/slim/InputMethodsSettings.java
deleted file mode 100644
index fec18fd3a79..00000000000
--- a/src/com/android/settings/slim/InputMethodsSettings.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2013 Slimroms
- *
- * 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.slim;
-
-import android.app.AlertDialog;
-import android.os.Bundle;
-import android.preference.CheckBoxPreference;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
-import android.preference.PreferenceCategory;
-import android.preference.PreferenceScreen;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.util.Log;
-
-import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.Utils;
-
-public class InputMethodsSettings extends SettingsPreferenceFragment implements
- Preference.OnPreferenceChangeListener {
-
- private static final String TAG = "KeyboardInputSettings";
-
- private static final String PREF_DISABLE_FULLSCREEN_KEYBOARD = "disable_fullscreen_keyboard";
- private static final String KEY_IME_SWITCHER = "status_bar_ime_switcher";
- private static final String KEYBOARD_ROTATION_TOGGLE = "keyboard_rotation_toggle";
- private static final String KEYBOARD_ROTATION_TIMEOUT = "keyboard_rotation_timeout";
- private static final String SHOW_ENTER_KEY = "show_enter_key";
-
- private static final int KEYBOARD_ROTATION_TIMEOUT_DEFAULT = 5000; // 5s
-
- private CheckBoxPreference mDisableFullscreenKeyboard;
- private CheckBoxPreference mStatusBarImeSwitcher;
- private CheckBoxPreference mKeyboardRotationToggle;
- private ListPreference mKeyboardRotationTimeout;
- private CheckBoxPreference mShowEnterKey;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- addPreferencesFromResource(R.xml.input_methods_settings);
-
- mDisableFullscreenKeyboard =
- (CheckBoxPreference) findPreference(PREF_DISABLE_FULLSCREEN_KEYBOARD);
- mDisableFullscreenKeyboard.setChecked(Settings.System.getInt(getContentResolver(),
- Settings.System.DISABLE_FULLSCREEN_KEYBOARD, 0) == 1);
- mDisableFullscreenKeyboard.setOnPreferenceChangeListener(this);
-
- mStatusBarImeSwitcher = (CheckBoxPreference) findPreference(KEY_IME_SWITCHER);
- mStatusBarImeSwitcher.setChecked(Settings.System.getInt(getContentResolver(),
- Settings.System.STATUS_BAR_IME_SWITCHER, 0) == 1);
- mStatusBarImeSwitcher.setOnPreferenceChangeListener(this);
-
- mKeyboardRotationToggle = (CheckBoxPreference) findPreference(KEYBOARD_ROTATION_TOGGLE);
- mKeyboardRotationToggle.setChecked(Settings.System.getInt(getContentResolver(),
- Settings.System.KEYBOARD_ROTATION_TIMEOUT, 0) > 0);
- mKeyboardRotationToggle.setOnPreferenceChangeListener(this);
-
- mKeyboardRotationTimeout = (ListPreference) findPreference(KEYBOARD_ROTATION_TIMEOUT);
- mKeyboardRotationTimeout.setOnPreferenceChangeListener(this);
- updateRotationTimeout(Settings.System.getInt(
- getContentResolver(), Settings.System.KEYBOARD_ROTATION_TIMEOUT,
- KEYBOARD_ROTATION_TIMEOUT_DEFAULT));
-
- mShowEnterKey = (CheckBoxPreference) findPreference(SHOW_ENTER_KEY);
- mShowEnterKey.setChecked(Settings.System.getInt(getContentResolver(),
- Settings.System.FORMAL_TEXT_INPUT, 0) == 1);
- mShowEnterKey.setOnPreferenceChangeListener(this);
- }
-
- public void updateRotationTimeout(int timeout) {
- if (timeout == 0)
- timeout = KEYBOARD_ROTATION_TIMEOUT_DEFAULT;
- mKeyboardRotationTimeout.setValue(Integer.toString(timeout));
- mKeyboardRotationTimeout.setSummary(
- getString(R.string.keyboard_rotation_timeout_summary,
- mKeyboardRotationTimeout.getEntry()));
- }
-
- @Override
- public void onPause() {
- super.onPause();
- }
-
- public void mKeyboardRotationDialog() {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- builder.setMessage(R.string.keyboard_rotation_dialog);
- builder.setCancelable(false);
- builder.setPositiveButton(getResources().getString(com.android.internal.R.string.ok), null);
- AlertDialog alert = builder.create();
- alert.show();
- }
-
- public boolean onPreferenceChange(Preference preference, Object objValue) {
- if (preference == mDisableFullscreenKeyboard) {
- Settings.System.putInt(getContentResolver(),
- Settings.System.DISABLE_FULLSCREEN_KEYBOARD, (Boolean) objValue ? 1 : 0);
- return true;
- } else if (preference == mStatusBarImeSwitcher) {
- Settings.System.putInt(getContentResolver(),
- Settings.System.STATUS_BAR_IME_SWITCHER, (Boolean) objValue ? 1 : 0);
- return true;
- } else if (preference == mKeyboardRotationToggle) {
- boolean isAutoRotate = (Settings.System.getInt(getContentResolver(),
- Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
- if (isAutoRotate && mKeyboardRotationToggle.isChecked())
- mKeyboardRotationDialog();
- Settings.System.putInt(getContentResolver(),
- Settings.System.KEYBOARD_ROTATION_TIMEOUT,
- (Boolean) objValue ? KEYBOARD_ROTATION_TIMEOUT_DEFAULT : 0);
- updateRotationTimeout(KEYBOARD_ROTATION_TIMEOUT_DEFAULT);
- return true;
- } else if (preference == mShowEnterKey) {
- Settings.System.putInt(getContentResolver(),
- Settings.System.FORMAL_TEXT_INPUT, (Boolean) objValue ? 1 : 0);
- return true;
- } else if (preference == mKeyboardRotationTimeout) {
- int timeout = Integer.parseInt((String) objValue);
- Settings.System.putInt(getContentResolver(),
- Settings.System.KEYBOARD_ROTATION_TIMEOUT, timeout);
- updateRotationTimeout(timeout);
- return true;
- }
- return false;
- }
-}
diff --git a/src/com/android/settings/slim/QuietHours.java b/src/com/android/settings/slim/QuietHours.java
deleted file mode 100644
index ef1e89da5ff..00000000000
--- a/src/com/android/settings/slim/QuietHours.java
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Copyright (C) 2012 The CyanogenMod 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.slim;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.os.Bundle;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.preference.CheckBoxPreference;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.PreferenceGroup;
-import android.preference.PreferenceManager;
-import android.preference.PreferenceScreen;
-import android.preference.RingtonePreference;
-import android.provider.Settings;
-import android.telephony.TelephonyManager;
-import android.text.InputFilter;
-import android.text.TextUtils;
-import android.widget.EditText;
-
-import com.android.settings.R;
-import com.android.settings.slim.service.SmsCallHelper;
-import com.android.settings.SettingsPreferenceFragment;
-
-public class QuietHours extends SettingsPreferenceFragment implements
- Preference.OnPreferenceChangeListener {
-
- private static final String TAG = "QuietHours";
- private static final String KEY_QUIET_HOURS_ENABLED = "quiet_hours_enabled";
- private static final String KEY_QUIET_HOURS_RING = "quiet_hours_ring";
- private static final String KEY_QUIET_HOURS_MUTE = "quiet_hours_mute";
- private static final String KEY_QUIET_HOURS_STILL = "quiet_hours_still";
- private static final String KEY_QUIET_HOURS_DIM = "quiet_hours_dim";
- private static final String KEY_QUIET_HOURS_HAPTIC = "quiet_hours_haptic";
- private static final String KEY_QUIET_HOURS_NOTE = "quiet_hours_note";
- private static final String KEY_QUIET_HOURS_TIMERANGE = "quiet_hours_timerange";
- private static final String KEY_LOOP_BYPASS_RINGTONE = "loop_bypass_ringtone";
- private static final String KEY_AUTO_SMS = "auto_sms";
- private static final String KEY_AUTO_SMS_CALL = "auto_sms_call";
- private static final String KEY_AUTO_SMS_MESSAGE = "auto_sms_message";
- private static final String KEY_CALL_BYPASS = "call_bypass";
- private static final String KEY_SMS_BYPASS = "sms_bypass";
- private static final String KEY_REQUIRED_CALLS = "required_calls";
- private static final String KEY_SMS_BYPASS_CODE = "sms_bypass_code";
- private static final String KEY_BYPASS_RINGTONE = "bypass_ringtone";
-
- private static final int DLG_AUTO_SMS_MESSAGE = 0;
- private static final int DLG_SMS_BYPASS_CODE = 1;
-
- private CheckBoxPreference mQuietHoursEnabled;
- private Preference mQuietHoursNote;
- private CheckBoxPreference mQuietHoursRing;
- private CheckBoxPreference mQuietHoursMute;
- private CheckBoxPreference mQuietHoursStill;
- private CheckBoxPreference mQuietHoursDim;
- private CheckBoxPreference mQuietHoursHaptic;
- private CheckBoxPreference mRingtoneLoop;
- private ListPreference mAutoSms;
- private ListPreference mAutoSmsCall;
- private ListPreference mSmsBypass;
- private ListPreference mCallBypass;
- private ListPreference mCallBypassNumber;
- private Preference mSmsBypassCode;
- private Preference mAutoSmsMessage;
- private RingtonePreference mBypassRingtone;
- private TimeRangePreference mQuietHoursTimeRange;
-
- private Context mContext;
-
- private int mSmsPref;
- private int mCallPref;
- private int mSmsBypassPref;
- private int mCallBypassPref;
-
- private SharedPreferences mPrefs;
- private OnSharedPreferenceChangeListener mPreferencesChangeListener;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- if (getPreferenceManager() != null) {
- addPreferencesFromResource(R.xml.quiet_hours_settings);
-
- mContext = getActivity().getApplicationContext();
-
- ContentResolver resolver = mContext.getContentResolver();
-
- PreferenceScreen prefSet = getPreferenceScreen();
-
- mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
-
- // Load the preferences
- mQuietHoursNote = prefSet.findPreference(KEY_QUIET_HOURS_NOTE);
- mQuietHoursEnabled =
- (CheckBoxPreference) prefSet.findPreference(KEY_QUIET_HOURS_ENABLED);
- mQuietHoursTimeRange =
- (TimeRangePreference) prefSet.findPreference(KEY_QUIET_HOURS_TIMERANGE);
- mQuietHoursRing =
- (CheckBoxPreference) prefSet.findPreference(KEY_QUIET_HOURS_RING);
- mQuietHoursMute =
- (CheckBoxPreference) prefSet.findPreference(KEY_QUIET_HOURS_MUTE);
- mQuietHoursStill =
- (CheckBoxPreference) prefSet.findPreference(KEY_QUIET_HOURS_STILL);
- mQuietHoursHaptic =
- (CheckBoxPreference) prefSet.findPreference(KEY_QUIET_HOURS_HAPTIC);
- mQuietHoursDim =
- (CheckBoxPreference) findPreference(KEY_QUIET_HOURS_DIM);
- mRingtoneLoop =
- (CheckBoxPreference) findPreference(KEY_LOOP_BYPASS_RINGTONE);
- mAutoSms =
- (ListPreference) findPreference(KEY_AUTO_SMS);
- mAutoSmsCall =
- (ListPreference) findPreference(KEY_AUTO_SMS_CALL);
- mAutoSmsMessage =
- (Preference) findPreference(KEY_AUTO_SMS_MESSAGE);
- mSmsBypass =
- (ListPreference) findPreference(KEY_SMS_BYPASS);
- mCallBypass =
- (ListPreference) findPreference(KEY_CALL_BYPASS);
- mCallBypassNumber =
- (ListPreference) findPreference(KEY_REQUIRED_CALLS);
- mSmsBypassCode =
- (Preference) findPreference(KEY_SMS_BYPASS_CODE);
- mBypassRingtone =
- (RingtonePreference) findPreference(KEY_BYPASS_RINGTONE);
-
-
- // Remove the "Incoming calls behaviour" note if the device does not support phone calls
- if (mQuietHoursNote != null && getResources().getBoolean(
- com.android.internal.R.bool.config_voice_capable) == false) {
- getPreferenceScreen().removePreference(mQuietHoursNote);
- }
-
- // Set the preference state and listeners where applicable
- mQuietHoursEnabled.setChecked(
- Settings.System.getInt(resolver, Settings.System.QUIET_HOURS_ENABLED, 0) == 1);
- mQuietHoursEnabled.setOnPreferenceChangeListener(this);
- mQuietHoursTimeRange.setTimeRange(
- Settings.System.getInt(resolver, Settings.System.QUIET_HOURS_START, 0),
- Settings.System.getInt(resolver, Settings.System.QUIET_HOURS_END, 0));
- mQuietHoursTimeRange.setOnPreferenceChangeListener(this);
- mQuietHoursRing.setChecked(
- Settings.System.getInt(resolver, Settings.System.QUIET_HOURS_RINGER, 0) == 1);
- mQuietHoursRing.setOnPreferenceChangeListener(this);
- mQuietHoursMute.setChecked(
- Settings.System.getInt(resolver, Settings.System.QUIET_HOURS_MUTE, 0) == 1);
- mQuietHoursMute.setOnPreferenceChangeListener(this);
- mQuietHoursStill.setChecked(
- Settings.System.getInt(resolver, Settings.System.QUIET_HOURS_STILL, 0) == 1);
- mQuietHoursStill.setOnPreferenceChangeListener(this);
- mQuietHoursHaptic.setChecked(
- Settings.System.getInt(resolver, Settings.System.QUIET_HOURS_HAPTIC, 0) == 1);
- mQuietHoursHaptic.setOnPreferenceChangeListener(this);
- mRingtoneLoop.setOnPreferenceChangeListener(this);
- mAutoSms.setValue(mPrefs.getString(KEY_AUTO_SMS, "0"));
- mAutoSms.setOnPreferenceChangeListener(this);
- mAutoSmsCall.setValue(mPrefs.getString(KEY_AUTO_SMS_CALL, "0"));
- mAutoSmsCall.setOnPreferenceChangeListener(this);
- mSmsBypass.setValue(mPrefs.getString(KEY_SMS_BYPASS, "0"));
- mSmsBypass.setOnPreferenceChangeListener(this);
- mCallBypass.setValue(mPrefs.getString(KEY_CALL_BYPASS, "0"));
- mCallBypass.setOnPreferenceChangeListener(this);
- mCallBypassNumber.setValue(mPrefs.getString(KEY_REQUIRED_CALLS, "2"));
- mCallBypassNumber.setOnPreferenceChangeListener(this);
- mBypassRingtone.setOnPreferenceChangeListener(this);
-
- TelephonyManager telephonyManager =
- (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE) {
- prefSet.removePreference(mQuietHoursRing);
- prefSet.removePreference((PreferenceGroup) findPreference("sms_respond"));
- prefSet.removePreference((PreferenceGroup) findPreference("quiethours_bypass"));
- } else {
- int callBypassNumber = Integer.parseInt(mPrefs.getString(KEY_REQUIRED_CALLS, "2"));
- boolean loopRingtone = mPrefs.getBoolean(KEY_LOOP_BYPASS_RINGTONE, true);
- mSmsBypassPref = Integer.parseInt(mPrefs.getString(KEY_SMS_BYPASS, "0"));
- mSmsPref = Integer.parseInt(mPrefs.getString(KEY_AUTO_SMS, "0"));
- mCallPref = Integer.parseInt(mPrefs.getString(KEY_AUTO_SMS_CALL, "0"));
- mCallBypassPref = Integer.parseInt(mPrefs.getString(KEY_CALL_BYPASS, "0"));
- Uri alertSoundUri = SmsCallHelper.returnUserRingtone(mContext);
- Ringtone ringtoneAlarm = RingtoneManager.getRingtone(mContext, alertSoundUri);
- mBypassRingtone.setSummary(ringtoneAlarm.getTitle(mContext));
- mRingtoneLoop.setChecked(loopRingtone);
- mRingtoneLoop.setSummary(loopRingtone
- ? R.string.quiet_hours_bypass_ringtone_loop_summary_on
- : R.string.quiet_hours_bypass_ringtone_loop_summary_off);
- mSmsBypass.setSummary(mSmsBypass.getEntries()[mSmsBypassPref]);
- mCallBypass.setSummary(mCallBypass.getEntries()[mCallBypassPref]);
- mCallBypassNumber.setSummary(mCallBypassNumber.getEntries()[callBypassNumber-2]
- + getResources().getString(R.string.quiet_hours_calls_required_summary));
- mAutoSms.setSummary(mAutoSms.getEntries()[mSmsPref]);
- mAutoSmsCall.setSummary(mAutoSmsCall.getEntries()[mCallPref]);
- mCallBypassNumber.setEnabled(mCallBypassPref != 0);
- mSmsBypassCode.setEnabled(mSmsBypassPref != 0);
- shouldDisplayRingerPrefs();
- shouldDisplayTextPref();
- setSmsBypassCodeSummary();
- }
-
- // Remove the notification light setting if the device does not support it
- if (mQuietHoursDim != null && getResources().getBoolean(
- com.android.internal.R.bool.config_intrusiveNotificationLed) == false) {
- getPreferenceScreen().removePreference(mQuietHoursDim);
- } else {
- mQuietHoursDim.setChecked(Settings.System.getInt(
- resolver, Settings.System.QUIET_HOURS_DIM, 0) == 1);
- mQuietHoursDim.setOnPreferenceChangeListener(this);
- }
-
- mPreferencesChangeListener = new OnSharedPreferenceChangeListener() {
- public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
- if (key.equals(KEY_AUTO_SMS_CALL)
- || key.equals(KEY_AUTO_SMS)
- || key.equals(KEY_CALL_BYPASS)
- || key.equals(KEY_SMS_BYPASS)) {
- SmsCallHelper.scheduleService(mContext);
- }
- if (key.equals(KEY_SMS_BYPASS_CODE)) {
- setSmsBypassCodeSummary();
- }
- }
- };
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mPrefs.registerOnSharedPreferenceChangeListener(mPreferencesChangeListener);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- mPrefs.unregisterOnSharedPreferenceChangeListener(mPreferencesChangeListener);
- }
-
- @Override
- public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
- ContentResolver resolver = mContext.getContentResolver();
- if (preference == mAutoSmsMessage) {
- showDialogInner(DLG_AUTO_SMS_MESSAGE);
- return true;
- } else if (preference == mSmsBypassCode) {
- showDialogInner(DLG_SMS_BYPASS_CODE);
- return true;
- }
- return super.onPreferenceTreeClick(preferenceScreen, preference);
- }
-
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- ContentResolver resolver = mContext.getContentResolver();
- if (preference == mQuietHoursTimeRange) {
- Settings.System.putInt(resolver, Settings.System.QUIET_HOURS_START,
- mQuietHoursTimeRange.getStartTime());
- Settings.System.putInt(resolver, Settings.System.QUIET_HOURS_END,
- mQuietHoursTimeRange.getEndTime());
- SmsCallHelper.scheduleService(mContext);
- return true;
- } else if (preference == mQuietHoursEnabled) {
- Settings.System.putInt(resolver, Settings.System.QUIET_HOURS_ENABLED,
- (Boolean) newValue ? 1 : 0);
- SmsCallHelper.scheduleService(mContext);
- return true;
- } else if (preference == mQuietHoursRing) {
- Settings.System.putInt(resolver, Settings.System.QUIET_HOURS_RINGER,
- (Boolean) newValue ? 1 : 0);
- return true;
- } else if (preference == mQuietHoursMute) {
- Settings.System.putInt(resolver, Settings.System.QUIET_HOURS_MUTE,
- (Boolean) newValue ? 1 : 0);
- return true;
- } else if (preference == mQuietHoursStill) {
- Settings.System.putInt(resolver, Settings.System.QUIET_HOURS_STILL,
- (Boolean) newValue ? 1 : 0);
- return true;
- } else if (preference == mQuietHoursDim) {
- Settings.System.putInt(resolver, Settings.System.QUIET_HOURS_DIM,
- (Boolean) newValue ? 1 : 0);
- return true;
- } else if (preference == mQuietHoursHaptic) {
- Settings.System.putInt(resolver, Settings.System.QUIET_HOURS_HAPTIC,
- (Boolean) newValue ? 1 : 0);
- return true;
- } else if (preference == mRingtoneLoop) {
- mRingtoneLoop.setSummary((Boolean) newValue
- ? R.string.quiet_hours_bypass_ringtone_loop_summary_on
- : R.string.quiet_hours_bypass_ringtone_loop_summary_off);
- return true;
- } else if (preference == mAutoSms) {
- mSmsPref = Integer.parseInt((String) newValue);
- mAutoSms.setSummary(mAutoSms.getEntries()[mSmsPref]);
- shouldDisplayTextPref();
- return true;
- } else if (preference == mAutoSmsCall) {
- mCallPref = Integer.parseInt((String) newValue);
- mAutoSmsCall.setSummary(mAutoSmsCall.getEntries()[mCallPref]);
- shouldDisplayTextPref();
- return true;
- } else if (preference == mSmsBypass) {
- mSmsBypassPref = Integer.parseInt((String) newValue);
- mSmsBypass.setSummary(mSmsBypass.getEntries()[mSmsBypassPref]);
- mSmsBypassCode.setEnabled(mSmsBypassPref != 0);
- shouldDisplayRingerPrefs();
- return true;
- } else if (preference == mCallBypass) {
- mCallBypassPref = Integer.parseInt((String) newValue);
- mCallBypass.setSummary(mCallBypass.getEntries()[mCallBypassPref]);
- mCallBypassNumber.setEnabled(mCallBypassPref != 0);
- shouldDisplayRingerPrefs();
- return true;
- } else if (preference == mCallBypassNumber) {
- int val = Integer.parseInt((String) newValue);
- mCallBypassNumber.setSummary(mCallBypassNumber.getEntries()[val-2]
- + getResources().getString(R.string.quiet_hours_calls_required_summary));
- return true;
- } else if (preference == mBypassRingtone) {
- Uri val = Uri.parse((String) newValue);
- SharedPreferences.Editor editor = mPrefs.edit();
- Ringtone ringtone = RingtoneManager.getRingtone(mContext, val);
- if (ringtone != null) {
- editor.putString(KEY_BYPASS_RINGTONE, val.toString()).apply();
- mBypassRingtone.setSummary(ringtone.getTitle(mContext));
- } else {
- // No silent option, won't reach here
- editor.putString(KEY_BYPASS_RINGTONE, null).apply();
- }
- return true;
- }
- return false;
- }
-
- private void shouldDisplayTextPref() {
- mAutoSmsMessage.setEnabled(mSmsPref != 0 || mCallPref != 0);
- }
-
- private void shouldDisplayRingerPrefs() {
- mBypassRingtone.setEnabled(mSmsBypassPref != 0 || mCallBypassPref != 0);
- mRingtoneLoop.setEnabled(mSmsBypassPref != 0 || mCallBypassPref != 0);
- }
-
- private void setSmsBypassCodeSummary() {
- final String defaultCode = getResources().getString(R.string.quiet_hours_sms_code_null);
- final String code = mPrefs.getString(KEY_SMS_BYPASS_CODE, defaultCode);
- mSmsBypassCode.setSummary(code);
- }
-
- private void showDialogInner(int id) {
- DialogFragment newFragment = MyAlertDialogFragment.newInstance(id);
- newFragment.setTargetFragment(this, 0);
- newFragment.show(getFragmentManager(), "dialog " + id);
- }
-
- public static class MyAlertDialogFragment extends DialogFragment {
-
- public static MyAlertDialogFragment newInstance(int id) {
- MyAlertDialogFragment frag = new MyAlertDialogFragment();
- Bundle args = new Bundle();
- args.putInt("id", id);
- frag.setArguments(args);
- return frag;
- }
-
- QuietHours getOwner() {
- return (QuietHours) getTargetFragment();
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- int id = getArguments().getInt("id");
- switch (id) {
- case DLG_AUTO_SMS_MESSAGE:
- final String defaultText =
- getResources().getString(R.string.quiet_hours_auto_sms_null);
- final String autoText =
- getOwner().mPrefs.getString(KEY_AUTO_SMS_MESSAGE, defaultText);
-
- final EditText input = new EditText(getActivity());
- InputFilter[] filter = new InputFilter[1];
- // No multi/split messages for ease of compatibility
- filter[0] = new InputFilter.LengthFilter(160);
- input.append(autoText);
- input.setFilters(filter);
-
- return new AlertDialog.Builder(getActivity())
- .setTitle(R.string.quiet_hours_auto_string_title)
- .setMessage(R.string.quiet_hours_auto_string_explain)
- .setView(input)
- .setNegativeButton(R.string.cancel, null)
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- String value = input.getText().toString();
- if (TextUtils.isEmpty(value)) {
- value = defaultText;
- }
- SharedPreferences.Editor editor = getOwner().mPrefs.edit();
- editor.putString(KEY_AUTO_SMS_MESSAGE, value).apply();
- }
- })
- .create();
- case DLG_SMS_BYPASS_CODE:
- final String defaultCode =
- getResources().getString(R.string.quiet_hours_sms_code_null);
- final String code =
- getOwner().mPrefs.getString(KEY_SMS_BYPASS_CODE, defaultCode);
-
- final EditText inputCode = new EditText(getActivity());
- InputFilter[] filterCode = new InputFilter[1];
- filterCode[0] = new InputFilter.LengthFilter(20);
- inputCode.append(code);
- inputCode.setFilters(filterCode);
-
- return new AlertDialog.Builder(getActivity())
- .setTitle(R.string.quiet_hours_sms_code_title)
- .setMessage(R.string.quiet_hours_sms_code_explain)
- .setView(inputCode)
- .setNegativeButton(R.string.cancel, null)
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- String value = inputCode.getText().toString();
- if (TextUtils.isEmpty(value)) {
- value = defaultCode;
- }
- SharedPreferences.Editor editor = getOwner().mPrefs.edit();
- editor.putString(KEY_SMS_BYPASS_CODE, value).apply();
- }
- })
- .create();
- }
- throw new IllegalArgumentException("unknown id " + id);
- }
-
- @Override
- public void onCancel(DialogInterface dialog) {
-
- }
- }
-
-}
diff --git a/src/com/android/settings/slim/TimeRangePreference.java b/src/com/android/settings/slim/TimeRangePreference.java
deleted file mode 100644
index f52623e5a33..00000000000
--- a/src/com/android/settings/slim/TimeRangePreference.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2012 The CyanogenMod 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.slim;
-
-import java.util.Calendar;
-import java.util.Date;
-
-import android.app.TimePickerDialog;
-import android.content.Context;
-import android.preference.Preference;
-import android.text.format.DateFormat;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.TimePicker;
-
-import com.android.settings.R;
-
-public class TimeRangePreference extends Preference implements
- View.OnClickListener {
-
- private static final String TAG = TimeRangePreference.class.getSimpleName();
- private static final int DIALOG_START_TIME = 1;
- private static final int DIALOG_END_TIME = 2;
-
- private TextView mStartTimeText;
- private TextView mEndTimeText;
- private int mStartTime;
- private int mEndTime;
-
- /**
- * @param context
- * @param attrs
- */
- public TimeRangePreference(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- /**
- * @param context
- * @param stime
- * @param etime
- */
- public TimeRangePreference(Context context, int stime, int etime) {
- super(context);
- mStartTime = stime;
- mEndTime = etime;
- init();
- }
-
- @Override
- protected void onBindView(View view) {
- super.onBindView(view);
-
- View startTimeLayout = view.findViewById(R.id.start_time);
- if ((startTimeLayout != null) && startTimeLayout instanceof LinearLayout) {
- startTimeLayout.setOnClickListener(this);
- }
-
- View endTimeLayout = view.findViewById(R.id.end_time);
- if ((endTimeLayout != null) && endTimeLayout instanceof LinearLayout) {
- endTimeLayout.setOnClickListener(this);
- }
-
- mStartTimeText = (TextView) view.findViewById(R.id.start_time_text);
- mEndTimeText = (TextView) view.findViewById(R.id.end_time_text);
-
- updatePreferenceViews();
- }
-
- private void init() {
- setLayoutResource(R.layout.preference_time_range);
- }
-
- private void updatePreferenceViews() {
- if (mStartTimeText != null) {
- mStartTimeText.setText(returnTime(mStartTime));
- }
- if (mEndTimeText != null) {
- mEndTimeText.setText(returnTime(mEndTime));
- }
- }
-
- public void setStartTime(int time) {
- mStartTime = time;
- updatePreferenceViews();
- }
-
- public void setEndTime(int time) {
- mEndTime = time;
- updatePreferenceViews();
- }
-
- public void setTimeRange(int stime, int etime) {
- mStartTime = stime;
- mEndTime = etime;
- updatePreferenceViews();
- }
-
- public int getStartTime() {
- return(mStartTime);
- }
-
- public int getEndTime() {
- return(mEndTime);
- }
-
- @Override
- public void onClick(android.view.View v) {
- if (v != null) {
- if (R.id.start_time == v.getId()) {
- TimePicker(DIALOG_START_TIME);
- } else if (R.id.end_time == v.getId()) {
- TimePicker(DIALOG_END_TIME);
- }
- }
- }
-
- private void TimePicker(final int key) {
- int hour;
- int minutes;
- int value = (key == DIALOG_START_TIME ? mStartTime : mEndTime);
-
- if (value < 0) {
- Calendar calendar = Calendar.getInstance();
- hour = calendar.get(Calendar.HOUR_OF_DAY);
- minutes = calendar.get(Calendar.MINUTE);
- } else {
- hour = value / 60;
- minutes = value % 60;
- }
-
- Context context = getContext();
- TimePickerDialog dlg = new TimePickerDialog(context,
- new TimePickerDialog.OnTimeSetListener() {
- @Override
- public void onTimeSet(TimePicker v, int hours, int minutes) {
- int time = hours * 60 + minutes;
- if (key == DIALOG_START_TIME) {
- mStartTime = time;
- mStartTimeText.setText(returnTime(time));
- } else {
- mEndTime = time;
- mEndTimeText.setText(returnTime(time));
- }
- callChangeListener(this);
- };
- }, hour, minutes, DateFormat.is24HourFormat(context));
- dlg.show();
- }
-
- private String returnTime(int t) {
- if (t < 0) {
- return "";
- }
-
- int hr = t;
- int mn = t;
-
- hr = hr / 60;
- mn = mn % 60;
- Calendar cal = Calendar.getInstance();
- cal.set(Calendar.HOUR_OF_DAY, hr);
- cal.set(Calendar.MINUTE, mn);
- Date date = cal.getTime();
- return DateFormat.getTimeFormat(getContext()).format(date);
- }
-}
diff --git a/src/com/android/settings/slim/service/AlarmReceiver.java b/src/com/android/settings/slim/service/AlarmReceiver.java
deleted file mode 100644
index 63e45844ec7..00000000000
--- a/src/com/android/settings/slim/service/AlarmReceiver.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2013 Android Open Kang 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.slim.service;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-public class AlarmReceiver extends BroadcastReceiver {
-
- private final static String TAG = "AlarmReceiver";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- SmsCallHelper.scheduleService(context);
- }
-
-}
diff --git a/src/com/android/settings/slim/service/AlarmService.java b/src/com/android/settings/slim/service/AlarmService.java
deleted file mode 100644
index efdb40f813e..00000000000
--- a/src/com/android/settings/slim/service/AlarmService.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2013 Android Open Kang 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.slim.service;
-
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.media.AudioManager;
-import android.media.MediaPlayer;
-import android.media.MediaPlayer.OnSeekCompleteListener;
-import android.media.MediaPlayer.OnErrorListener;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.support.v4.app.NotificationCompat;
-
-import com.android.settings.R;
-
-public class AlarmService extends Service {
-
- private static final int NOTI_ID = 286;
-
- private NotificationManager mManager;
- private MediaPlayer mMediaPlayer;
- private AudioManager mAudioManager;
-
- private int mAlarmVolumeSetting;
- private boolean mPlaying = false;
-
- @Override
- public void onCreate() {
- mAudioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
- mManager = (NotificationManager)
- this.getSystemService(Context.NOTIFICATION_SERVICE);
- }
-
- @Override
- public void onDestroy() {
- stopAlarm();
- mManager.cancel(NOTI_ID);
- super.onDestroy();
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- try {
- startAlarmSound();
- } catch (Exception e) {
- // Do nothing
- }
-
- Bundle extras = intent.getExtras();
- String names = extras.getString("number");
- String title = getResources().getString(
- R.string.quiet_hours_alarm_dialog_title);
- Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_quiethours);
-
- NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
- .setTicker(title)
- .setContentTitle(title)
- .setContentText(names)
- .setAutoCancel(false)
- .setOngoing(true)
- .setSmallIcon(R.drawable.ic_quiethours)
- .setLargeIcon(bm)
- .setStyle(new NotificationCompat.BigTextStyle()
- .bigText(names + getResources().getString(
- R.string.quiet_hours_alarm_message)));
-
- Intent alarmDialog = new Intent();
- alarmDialog.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_SINGLE_TOP
- | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- alarmDialog.setClass(this, com.android.settings.slim.service.BypassAlarm.class);
- alarmDialog.putExtra("number", names);
- alarmDialog.putExtra("norun", true);
-
- PendingIntent result = PendingIntent.getActivity(
- this, 0, alarmDialog, PendingIntent.FLAG_CANCEL_CURRENT);
-
- builder.setContentIntent(result);
- mManager.notify(NOTI_ID, builder.build());
- return START_STICKY;
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- public void startAlarmSound()
- throws java.io.IOException, IllegalArgumentException, IllegalStateException {
-
- Uri alertSound = SmsCallHelper.returnUserRingtone(this);
-
- if (mPlaying) {
- stopAlarm();
- } else {
- mAlarmVolumeSetting = mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM);
- }
-
- if (mMediaPlayer == null) {
- mMediaPlayer = new MediaPlayer();
- mMediaPlayer.setOnErrorListener(new OnErrorListener() {
- @Override
- public boolean onError(MediaPlayer mp, int what, int extra) {
- mp.stop();
- mp.release();
- mMediaPlayer = null;
- return true;
- }
- });
- }
-
- mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM,
- mAudioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM), 0);
-
- mMediaPlayer.setDataSource(this, alertSound);
- mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
-
- if (SmsCallHelper.returnUserRingtoneLoop(this)) {
- mMediaPlayer.setLooping(true);
- } else {
- mMediaPlayer.setLooping(false);
- mMediaPlayer.setOnSeekCompleteListener(stopSelf);
- }
- mMediaPlayer.prepare();
- mMediaPlayer.start();
- mPlaying = true;
- }
-
- public void stopAlarm() {
- if (mPlaying) {
-
- if (mMediaPlayer != null) {
- mMediaPlayer.stop();
- mMediaPlayer.release();
- mMediaPlayer = null;
- mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM,
- mAlarmVolumeSetting, 0);
- }
-
- mPlaying = false;
- }
- }
-
- final OnSeekCompleteListener stopSelf = new OnSeekCompleteListener() {
- public void onSeekComplete(MediaPlayer mp) {
- stopAlarm();
- }
- };
-}
diff --git a/src/com/android/settings/slim/service/BootReceiver.java b/src/com/android/settings/slim/service/BootReceiver.java
deleted file mode 100644
index 3ec13926b9e..00000000000
--- a/src/com/android/settings/slim/service/BootReceiver.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2013 Android Open Kang 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.slim.service;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-public class BootReceiver extends BroadcastReceiver {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- SmsCallHelper.scheduleService(context);
- }
-}
diff --git a/src/com/android/settings/slim/service/BypassAlarm.java b/src/com/android/settings/slim/service/BypassAlarm.java
deleted file mode 100644
index 77a8b9b3649..00000000000
--- a/src/com/android/settings/slim/service/BypassAlarm.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2013 Android Open Kang 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.slim.service;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import com.android.settings.R;
-
-public class BypassAlarm extends Activity {
-
- private FrameLayout mDismissButton;
-
- private String mNumbers;
-
- private boolean mUserDestroy;
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- mUserDestroy = false;
-
- final Window win = getWindow();
- win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
- | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
- | WindowManager.LayoutParams.FLAG_FULLSCREEN
- | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
-
- if (SmsCallHelper.returnUserRingtoneLoop(this)) {
- win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
-
- Bundle extras = getIntent().getExtras();
- mNumbers = extras.getString("number");
-
- final LayoutInflater inflater = LayoutInflater.from(this);
- final View view = inflater.inflate(getLayoutResId(), null);
- view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
- setContentView(view);
-
- mDismissButton = ((FrameLayout)
- this.findViewById(R.id.dismissalert));
- mDismissButton.setOnClickListener(mDismissButtonListener);
-
- setAlertText(mNumbers);
-
- startService();
- }
-
- @Override
- protected void onDestroy() {
- if (mUserDestroy) {
- stopService();
- }
- super.onDestroy();
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- Bundle extras = intent.getExtras();
- boolean noSound = intent.getBooleanExtra("norun", false);
- String newNumber = extras.getString("number");
- if (!mNumbers.contains(newNumber)) {
- mNumbers += getResources().getString(
- R.string.quiet_hours_alarm_and) + newNumber;
- setAlertText(mNumbers);
- }
- if (!noSound) {
- startService();
- }
- }
-
- @Override
- public void onBackPressed() {
- // Don't allow dismissal
- return;
- }
-
- protected int getLayoutResId() {
- return R.layout.bypass_alarm;
- }
-
- private void setAlertText(String numbers) {
- TextView alertText = (TextView) findViewById(R.id.bypasstext);
- alertText.setText(numbers + getResources().getString(
- R.string.quiet_hours_alarm_message));
- }
-
- private FrameLayout.OnClickListener mDismissButtonListener = new FrameLayout.OnClickListener() {
- public void onClick(View v) {
- mUserDestroy = true;
- finish();
- }
- };
-
- private void startService() {
- Intent serviceIntent = new Intent(this, AlarmService.class);
- serviceIntent.putExtra("number", mNumbers);
- this.startService(serviceIntent);
- }
-
- private void stopService() {
- Intent serviceIntent = new Intent(this, AlarmService.class);
- this.stopService(serviceIntent);
- }
-}
diff --git a/src/com/android/settings/slim/service/SmsCallHelper.java b/src/com/android/settings/slim/service/SmsCallHelper.java
deleted file mode 100644
index 524f1cd7a9f..00000000000
--- a/src/com/android/settings/slim/service/SmsCallHelper.java
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * Copyright (C) 2013 Android Open Kang 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.slim.service;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.provider.ContactsContract.PhoneLookup;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.UserHandle;
-import android.preference.PreferenceManager;
-import android.provider.Settings;
-import android.telephony.SmsManager;
-
-import java.util.Calendar;
-
-import com.android.settings.R;
-
-public class SmsCallHelper {
-
- private final static String TAG = "SmsCallHelper";
-
- private static final String KEY_AUTO_SMS = "auto_sms";
- private static final String KEY_AUTO_SMS_CALL = "auto_sms_call";
- private static final String KEY_AUTO_SMS_MESSAGE = "auto_sms_message";
- private static final String KEY_LOOP_BYPASS_RINGTONE = "loop_bypass_ringtone";
- private static final String KEY_BYPASS_RINGTONE = "bypass_ringtone";
- private static final String KEY_CALL_BYPASS = "call_bypass";
- private static final String KEY_SMS_BYPASS = "sms_bypass";
- private static final String KEY_REQUIRED_CALLS = "required_calls";
- private static final String KEY_SMS_BYPASS_CODE = "sms_bypass_code";
- private static final String SCHEDULE_SERVICE_COMMAND =
- "com.android.settings.service.SCHEDULE_SERVICE_COMMAND";
-
- private static final int FULL_DAY = 1440; // 1440 minutes in a day
- private static final int TIME_LIMIT = 30; // 30 minute bypass limit
- public static final int DEFAULT_DISABLED = 0;
- public static final int ALL_NUMBERS = 1;
- public static final int CONTACTS_ONLY = 2;
- public static final int DEFAULT_TWO = 2;
-
- // Return the current time
- public static int returnTimeInMinutes() {
- Calendar calendar = Calendar.getInstance();
- int currentMinutes = calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE);
- return currentMinutes;
- }
-
- // Return current day of month
- public static int returnDayOfMonth() {
- Calendar calendar = Calendar.getInstance();
- int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
- return dayOfMonth;
- }
-
- // Return if last call versus current call less than 30 minute apart
- public static boolean returnTimeConstraintMet(
- Context context, int firstCallTime, int dayOfFirstCall) {
- int currentMinutes = returnTimeInMinutes();
- int dayOfMonth = returnDayOfMonth();
- // New Day, start at zero
- if (dayOfMonth != dayOfFirstCall) {
- // Less or Equal to 30 minutes until midnight
- if (firstCallTime >= (FULL_DAY - TIME_LIMIT)) {
- if ((currentMinutes >= 0) && (currentMinutes <= TIME_LIMIT)) {
- int remainderDayOne = FULL_DAY - firstCallTime;
- if ((remainderDayOne + currentMinutes) <= TIME_LIMIT) {
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- } else {
- // new day and prior call happened with more than
- // 30 minutes remaining in day
- return false;
- }
- } else {
- // Same day - simple subtraction: or you need to get out more
- // and it's been a month since your last call, reboot, or reschedule
- if ((currentMinutes - firstCallTime) <= TIME_LIMIT) {
- return true;
- } else {
- return false;
- }
- }
- }
-
- /* True: Ringtone loops until alert dismissed
- * False: Ringtone plays only once
- */
- public static boolean returnUserRingtoneLoop(Context context) {
- SharedPreferences prefs =
- PreferenceManager.getDefaultSharedPreferences(context);
- boolean loop = prefs.getBoolean(KEY_LOOP_BYPASS_RINGTONE, true);
- return loop;
- }
-
- /* Returns user-selected alert Ringtone
- * Parsed from saved string or default ringtone
- */
- public static Uri returnUserRingtone(Context context) {
- SharedPreferences prefs =
- PreferenceManager.getDefaultSharedPreferences(context);
- String ringtoneString = prefs.getString(KEY_BYPASS_RINGTONE, null);
- if (ringtoneString == null) {
- // Value not set, defaults to Default Ringtone
- Uri alertSoundUri = RingtoneManager.getDefaultUri(
- RingtoneManager.TYPE_RINGTONE);
- return alertSoundUri;
- } else {
- Uri ringtoneUri = Uri.parse(ringtoneString);
- return ringtoneUri;
- }
- }
-
- // Code sender can deliver to start an alert
- public static String returnUserTextBypassCode(Context context) {
- String code = null;
- String defaultCode = context.getResources().getString(
- R.string.quiet_hours_sms_code_null);
- SharedPreferences prefs =
- PreferenceManager.getDefaultSharedPreferences(context);
- code = prefs.getString(KEY_SMS_BYPASS_CODE, defaultCode);
- return code;
- }
-
- // Number of missed calls within time constraint to start alert
- public static int returnUserCallBypassCount(Context context) {
- SharedPreferences prefs =
- PreferenceManager.getDefaultSharedPreferences(context);
- return Integer.parseInt(prefs.getString(
- KEY_REQUIRED_CALLS, String.valueOf(DEFAULT_TWO)));
- }
-
- /* Default: Off
- * All Numbers
- * Contacts Only
- */
- public static int returnUserTextBypass(Context context) {
- SharedPreferences prefs =
- PreferenceManager.getDefaultSharedPreferences(context);
- return Integer.parseInt(prefs.getString(
- KEY_SMS_BYPASS, String.valueOf(DEFAULT_DISABLED)));
- }
-
- /* Default: Off
- * All Numbers
- * Contacts Only
- */
- public static int returnUserCallBypass(Context context) {
- SharedPreferences prefs =
- PreferenceManager.getDefaultSharedPreferences(context);
- return Integer.parseInt(prefs.getString(
- KEY_CALL_BYPASS, String.valueOf(DEFAULT_DISABLED)));
- }
-
- /* Default: Off
- * All Numbers
- * Contacts Only
- */
- public static int returnUserAutoCall(Context context) {
- SharedPreferences prefs =
- PreferenceManager.getDefaultSharedPreferences(context);
- return Integer.parseInt(prefs.getString(
- KEY_AUTO_SMS_CALL, String.valueOf(DEFAULT_DISABLED)));
- }
-
- /* Default: Off
- * All Numbers
- * Contacts Only
- */
- public static int returnUserAutoText(Context context) {
- SharedPreferences prefs =
- PreferenceManager.getDefaultSharedPreferences(context);
- return Integer.parseInt(prefs.getString(
- KEY_AUTO_SMS, String.valueOf(DEFAULT_DISABLED)));
- }
-
- // Pull current settings and send message if applicable
- public static void checkSmsQualifiers(Context context, String incomingNumber,
- int userAutoSms, boolean isContact) {
- String message = null;
- String defaultSms = context.getResources().getString(
- R.string.quiet_hours_auto_sms_null);
- SharedPreferences prefs =
- PreferenceManager.getDefaultSharedPreferences(context);
- message = prefs.getString(KEY_AUTO_SMS_MESSAGE, defaultSms);
- switch (userAutoSms) {
- case ALL_NUMBERS:
- sendAutoReply(message, incomingNumber);
- break;
- case CONTACTS_ONLY:
- if (isContact) {
- sendAutoReply(message, incomingNumber);
- }
- break;
- }
- }
-
- /* True: Contact
- * False: Not a contact
- */
- public static boolean isContact(Context context, String phoneNumber) {
- boolean isContact = false;
- Uri lookupUri = Uri.withAppendedPath(
- PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
- String[] numberProject = {
- PhoneLookup._ID,
- PhoneLookup.NUMBER,
- PhoneLookup.DISPLAY_NAME };
- Cursor c = context.getContentResolver().query(
- lookupUri, numberProject, null, null, null);
- try {
- if (c.moveToFirst()) {
- isContact = true;
- }
- } finally {
- if (c != null) {
- c.close();
- }
- }
- return isContact;
- }
-
- // Returns the contact name or number
- public static String returnContactName(Context context, String phoneNumber) {
- String contactName = null;
- Uri lookupUri = Uri.withAppendedPath(
- PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
- String[] numberProject = { PhoneLookup.DISPLAY_NAME };
- Cursor c = context.getContentResolver().query(
- lookupUri, numberProject, null, null, null);
-
- try {
- if (c.moveToFirst()) {
- contactName = c.getString(c.getColumnIndex(PhoneLookup.DISPLAY_NAME));
- } else {
- // Not in contacts, return number again
- contactName = phoneNumber;
- }
- } finally {
- if (c != null) {
- c.close();
- }
- }
-
- return contactName;
- }
-
- // Send the message
- private static void sendAutoReply(String message, String phoneNumber) {
- SmsManager sms = SmsManager.getDefault();
- try {
- sms.sendTextMessage(phoneNumber, null, message, null, null);
- } catch (IllegalArgumentException e) {
- }
- }
-
- // Pending intent to start/stop SmsCallservice
- private static PendingIntent makeServiceIntent(Context context,
- String action, int requestCode) {
- Intent intent = new Intent(context, AlarmReceiver.class);
- intent.setAction(action);
- return PendingIntent.getBroadcast(
- context, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
- }
-
- /*
- * Called when:
- * QuietHours Toggled
- * QuietHours TimeChanged
- * AutoSMS Preferences Changed
- * At Boot
- * Time manually adjusted or Timezone Changed
- * AutoSMS service Stopped - Schedule again for next day
- */
- public static void scheduleService(Context context) {
- boolean quietHoursEnabled = Settings.System.getIntForUser(context.getContentResolver(),
- Settings.System.QUIET_HOURS_ENABLED, 0,
- UserHandle.USER_CURRENT_OR_SELF) != 0;
- int quietHoursStart = Settings.System.getIntForUser(context.getContentResolver(),
- Settings.System.QUIET_HOURS_START, 0,
- UserHandle.USER_CURRENT_OR_SELF);
- int quietHoursEnd = Settings.System.getIntForUser(context.getContentResolver(),
- Settings.System.QUIET_HOURS_END, 0,
- UserHandle.USER_CURRENT_OR_SELF);
- int autoCall = returnUserAutoCall(context);
- int autoText = returnUserAutoText(context);
- int callBypass = returnUserCallBypass(context);
- int smsBypass = returnUserTextBypass(context);
- Intent serviceTriggerIntent = new Intent(context, SmsCallService.class);
- PendingIntent startIntent = makeServiceIntent(context, SCHEDULE_SERVICE_COMMAND, 1);
- PendingIntent stopIntent = makeServiceIntent(context, SCHEDULE_SERVICE_COMMAND, 2);
- AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-
- am.cancel(startIntent);
- am.cancel(stopIntent);
-
- if (!quietHoursEnabled
- || (autoCall == DEFAULT_DISABLED
- && autoText == DEFAULT_DISABLED
- && callBypass == DEFAULT_DISABLED
- && smsBypass == DEFAULT_DISABLED)) {
- context.stopService(serviceTriggerIntent);
- return;
- }
-
- if (quietHoursStart == quietHoursEnd) {
- // 24 hours, start without stop
- context.startService(serviceTriggerIntent);
- return;
- }
-
-
- Calendar calendar = Calendar.getInstance();
- int currentMinutes = calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE);
-
- boolean inQuietHours = false;
- // time from now on (in minutes) when the service start/stop should be scheduled
- int serviceStartMinutes = -1, serviceStopMinutes = -1;
-
- if (quietHoursEnd < quietHoursStart) {
- // Starts at night, ends in the morning.
- if (currentMinutes >= quietHoursStart) {
- // In QuietHours - quietHoursEnd in new day
- inQuietHours = true;
- serviceStopMinutes = FULL_DAY - currentMinutes + quietHoursEnd;
- } else if (currentMinutes <= quietHoursEnd) {
- // In QuietHours - quietHoursEnd in same day
- inQuietHours = true;
- serviceStopMinutes = quietHoursEnd - currentMinutes;
- } else {
- // Out of QuietHours
- // Current time less than quietHoursStart, greater than quietHoursEnd
- inQuietHours = false;
- serviceStartMinutes = quietHoursStart - currentMinutes;
- serviceStopMinutes = FULL_DAY - currentMinutes + quietHoursEnd;
- }
- } else {
- // Starts in the morning, ends at night.
- if (currentMinutes >= quietHoursStart && currentMinutes <= quietHoursEnd) {
- // In QuietHours
- inQuietHours = true;
- serviceStopMinutes = quietHoursEnd - currentMinutes;
- } else {
- // Out of QuietHours
- inQuietHours = false;
- if (currentMinutes <= quietHoursStart) {
- serviceStartMinutes = quietHoursStart - currentMinutes;
- serviceStopMinutes = quietHoursEnd - currentMinutes;
- } else {
- // Current Time greater than quietHoursEnd
- serviceStartMinutes = FULL_DAY - currentMinutes + quietHoursStart;
- serviceStopMinutes = FULL_DAY - currentMinutes + quietHoursEnd;
- }
- }
- }
-
- if (inQuietHours) {
- context.startService(serviceTriggerIntent);
- } else {
- context.stopService(serviceTriggerIntent);
- }
-
- if (serviceStartMinutes >= 0) {
- // Start service a minute early
- serviceStartMinutes--;
- calendar.add(Calendar.MINUTE, serviceStartMinutes);
- am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), startIntent);
- calendar.add(Calendar.MINUTE, -serviceStartMinutes);
- }
-
- if (serviceStopMinutes >= 0) {
- // Stop service a minute late
- serviceStopMinutes++;
- calendar.add(Calendar.MINUTE, serviceStopMinutes);
- am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), stopIntent);
- calendar.add(Calendar.MINUTE, -serviceStopMinutes);
- }
- }
-}
diff --git a/src/com/android/settings/slim/service/SmsCallService.java b/src/com/android/settings/slim/service/SmsCallService.java
deleted file mode 100644
index 445a7e4b7ca..00000000000
--- a/src/com/android/settings/slim/service/SmsCallService.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright (C) 2013 Android Open Kang 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.slim.service;
-
-import android.app.Service;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.IBinder;
-import android.provider.Telephony.Sms.Intents;
-import android.telephony.PhoneStateListener;
-import android.telephony.SmsMessage;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.util.slim.QuietHoursHelper;
-
-import com.android.settings.R;
-
-public class SmsCallService extends Service {
-
- private final static String TAG = "SmsCallService";
-
- private static TelephonyManager mTelephony;
-
- private boolean mIncomingCall = false;
-
- private boolean mKeepCounting = false;
-
- private String mIncomingNumber;
-
- private String mNumberSent;
-
- private int mMinuteSent;
-
- private int mBypassCallCount;
-
- private int mMinutes;
-
- private int mDay;
-
- private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-
- @Override
- public void onCallStateChanged(int state, String incomingNumber) {
- if (state == TelephonyManager.CALL_STATE_RINGING) {
- mIncomingCall = true;
- mIncomingNumber = incomingNumber;
- int bypassPreference = SmsCallHelper.returnUserCallBypass(SmsCallService.this);
- boolean isContact = SmsCallHelper.isContact(SmsCallService.this, mIncomingNumber);
-
- if (!mKeepCounting) {
- mKeepCounting = true;
- mBypassCallCount = 0;
- mDay = SmsCallHelper.returnDayOfMonth();
- mMinutes = SmsCallHelper.returnTimeInMinutes();
- }
-
- boolean timeConstraintMet = SmsCallHelper.returnTimeConstraintMet(
- SmsCallService.this, mMinutes, mDay);
- if (timeConstraintMet) {
- switch (bypassPreference) {
- case SmsCallHelper.DEFAULT_DISABLED:
- break;
- case SmsCallHelper.ALL_NUMBERS:
- mBypassCallCount++;
- break;
- case SmsCallHelper.CONTACTS_ONLY:
- if (isContact) {
- mBypassCallCount++;
- }
- break;
- }
-
- if (mBypassCallCount == 0) {
- mKeepCounting = false;
- }
- } else {
- switch (bypassPreference) {
- case SmsCallHelper.DEFAULT_DISABLED:
- break;
- case SmsCallHelper.ALL_NUMBERS:
- mBypassCallCount = 1;
- break;
- case SmsCallHelper.CONTACTS_ONLY:
- if (isContact) {
- mBypassCallCount = 1;
- } else {
- // Reset call count and time at next call
- mKeepCounting = false;
- }
- break;
- }
- mDay = SmsCallHelper.returnDayOfMonth();
- mMinutes = SmsCallHelper.returnTimeInMinutes();
- }
- if ((mBypassCallCount
- == SmsCallHelper.returnUserCallBypassCount(SmsCallService.this))
- && QuietHoursHelper.inQuietHours(SmsCallService.this, null)
- && timeConstraintMet) {
- // Don't auto-respond if alarm fired
- mIncomingCall = false;
- mKeepCounting = false;
- startAlarm(SmsCallService.this, mIncomingNumber);
- }
- }
- if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
- // Don't message or alarm if call was answered
- mIncomingCall = false;
- // Call answered, reset Incoming number
- // Stop AlarmSound
- mKeepCounting = false;
- Intent serviceIntent = new Intent(SmsCallService.this, AlarmService.class);
- SmsCallService.this.stopService(serviceIntent);
- }
- if (state == TelephonyManager.CALL_STATE_IDLE && mIncomingCall) {
- // Call Received and now inactive
- mIncomingCall = false;
- int userAutoSms = SmsCallHelper.returnUserAutoCall(SmsCallService.this);
-
- if (userAutoSms != SmsCallHelper.DEFAULT_DISABLED
- && QuietHoursHelper.inQuietHours(SmsCallService.this, null)) {
- boolean isContact =
- SmsCallHelper.isContact(SmsCallService.this, mIncomingNumber);
- checkTimeAndNumber(
- SmsCallService.this, mIncomingNumber, userAutoSms, isContact);
- }
- }
- super.onCallStateChanged(state, incomingNumber);
- }
- };
-
- private BroadcastReceiver smsReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- SmsMessage[] msgs = Intents.getMessagesFromIntent(intent);
- SmsMessage msg = msgs[0];
- String incomingNumber = msg.getOriginatingAddress();
- boolean nawDawg = false;
- int userAutoSms = SmsCallHelper.returnUserAutoText(context);
- int bypassCodePref = SmsCallHelper.returnUserTextBypass(context);
- boolean isContact = SmsCallHelper.isContact(context, incomingNumber);
-
- if ((bypassCodePref != SmsCallHelper.DEFAULT_DISABLED
- || userAutoSms != SmsCallHelper.DEFAULT_DISABLED)
- && QuietHoursHelper.inQuietHours(context, null)) {
- String bypassCode = SmsCallHelper.returnUserTextBypassCode(context);
- String messageBody = msg.getMessageBody();
- if (messageBody.contains(bypassCode)) {
- switch (bypassCodePref) {
- case SmsCallHelper.DEFAULT_DISABLED:
- break;
- case SmsCallHelper.ALL_NUMBERS:
- // Sound Alarm && Don't auto-respond
- nawDawg = true;
- startAlarm(SmsCallService.this, incomingNumber);
- break;
- case SmsCallHelper.CONTACTS_ONLY:
- if (isContact) {
- // Sound Alarm && Don't auto-respond
- nawDawg = true;
- startAlarm(SmsCallService.this, incomingNumber);
- }
- break;
- }
- }
- if (userAutoSms != SmsCallHelper.DEFAULT_DISABLED && nawDawg == false) {
- checkTimeAndNumber(context, incomingNumber, userAutoSms, isContact);
- }
- }
- }
- };
-
- @Override
- public void onCreate() {
- mTelephony = (TelephonyManager)
- this.getSystemService(Context.TELEPHONY_SERVICE);
- mTelephony.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intents.SMS_RECEIVED_ACTION);
- registerReceiver(smsReceiver, filter);
- }
-
- @Override
- public void onDestroy() {
- if (mTelephony != null) {
- mTelephony.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
- }
- mPhoneStateListener = null;
- unregisterReceiver(smsReceiver);
- super.onDestroy();
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- return START_STICKY;
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- /*
- * Dont send if alarm fired
- * If in same minute, don't send. This prevents message looping if sent to self
- * or another quiet-hours enabled device with this feature on.
- */
- private void checkTimeAndNumber(Context context, String incomingNumber,
- int userSetting, boolean isContact) {
- int minutesNow = SmsCallHelper.returnTimeInMinutes();
- if (minutesNow != mMinuteSent) {
- mNumberSent = incomingNumber;
- mMinuteSent = SmsCallHelper.returnTimeInMinutes();
- SmsCallHelper.checkSmsQualifiers(
- context, incomingNumber, userSetting, isContact);
- } else {
- // Let's try to send if number doesn't match prior
- if (!incomingNumber.equals(mNumberSent)) {
- mNumberSent = incomingNumber;
- mMinuteSent = SmsCallHelper.returnTimeInMinutes();
- SmsCallHelper.checkSmsQualifiers(
- context, incomingNumber, userSetting, isContact);
- }
- }
- }
-
- private void startAlarm(Context context, String phoneNumber) {
- String contactName = SmsCallHelper.returnContactName(context, phoneNumber);
- Intent alarmDialog = new Intent();
- alarmDialog.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_SINGLE_TOP
- | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- alarmDialog.setClass(context, com.android.settings.slim.service.BypassAlarm.class);
- alarmDialog.putExtra("number", contactName);
- startActivity(alarmDialog);
- }
-}
diff --git a/src/com/android/settings/tts/TextToSpeechSettings.java b/src/com/android/settings/tts/TextToSpeechSettings.java
index 0ff7f4f9c7e..3a3aec46181 100644
--- a/src/com/android/settings/tts/TextToSpeechSettings.java
+++ b/src/com/android/settings/tts/TextToSpeechSettings.java
@@ -46,6 +46,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
+import java.util.MissingResourceException;
import java.util.Set;
public class TextToSpeechSettings extends SettingsPreferenceFragment implements
@@ -278,25 +279,32 @@ private boolean evaluateDefaultLocale() {
if (mCurrentDefaultLocale == null || mAvailableStrLocals == null) {
return false;
}
- int defaultAvailable = mTts.setLanguage(mCurrentDefaultLocale);
- // Check if language is listed in CheckVoices Action result as available voice.
- String defaultLocaleStr = mCurrentDefaultLocale.getISO3Language();
boolean notInAvailableLangauges = true;
- if (!TextUtils.isEmpty(mCurrentDefaultLocale.getISO3Country())) {
- defaultLocaleStr += "-" + mCurrentDefaultLocale.getISO3Country();
- }
- if (!TextUtils.isEmpty(mCurrentDefaultLocale.getVariant())) {
- defaultLocaleStr += "-" + mCurrentDefaultLocale.getVariant();
- }
+ try {
+ // Check if language is listed in CheckVoices Action result as available voice.
+ String defaultLocaleStr = mCurrentDefaultLocale.getISO3Language();
+ if (!TextUtils.isEmpty(mCurrentDefaultLocale.getISO3Country())) {
+ defaultLocaleStr += "-" + mCurrentDefaultLocale.getISO3Country();
+ }
+ if (!TextUtils.isEmpty(mCurrentDefaultLocale.getVariant())) {
+ defaultLocaleStr += "-" + mCurrentDefaultLocale.getVariant();
+ }
- for (String loc : mAvailableStrLocals) {
- if (loc.equalsIgnoreCase(defaultLocaleStr)) {
- notInAvailableLangauges = false;
- break;
+ for (String loc : mAvailableStrLocals) {
+ if (loc.equalsIgnoreCase(defaultLocaleStr)) {
+ notInAvailableLangauges = false;
+ break;
+ }
}
+ } catch (MissingResourceException e) {
+ if (DBG) Log.wtf(TAG, "MissingResourceException", e);
+ updateEngineStatus(R.string.tts_status_not_supported);
+ updateWidgetState(false);
+ return false;
}
+ int defaultAvailable = mTts.setLanguage(mCurrentDefaultLocale);
if (defaultAvailable == TextToSpeech.LANG_NOT_SUPPORTED ||
defaultAvailable == TextToSpeech.LANG_MISSING_DATA ||
notInAvailableLangauges) {
@@ -315,7 +323,6 @@ private boolean evaluateDefaultLocale() {
}
}
-
/**
* Ask the current default engine to return a string of sample text to be
* spoken to the user.
@@ -358,16 +365,21 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
private String getDefaultSampleString() {
if (mTts != null && mTts.getLanguage() != null) {
- final String currentLang = mTts.getLanguage().getISO3Language();
- String[] strings = getActivity().getResources().getStringArray(
- R.array.tts_demo_strings);
- String[] langs = getActivity().getResources().getStringArray(
- R.array.tts_demo_string_langs);
-
- for (int i = 0; i < strings.length; ++i) {
- if (langs[i].equals(currentLang)) {
- return strings[i];
+ try {
+ final String currentLang = mTts.getLanguage().getISO3Language();
+ String[] strings = getActivity().getResources().getStringArray(
+ R.array.tts_demo_strings);
+ String[] langs = getActivity().getResources().getStringArray(
+ R.array.tts_demo_string_langs);
+
+ for (int i = 0; i < strings.length; ++i) {
+ if (langs[i].equals(currentLang)) {
+ return strings[i];
+ }
}
+ } catch (MissingResourceException e) {
+ if (DBG) Log.wtf(TAG, "MissingResourceException", e);
+ // Ignore and fall back to default sample string
}
}
return getString(R.string.tts_default_sample_string);
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index bbae37d035c..c5ee77964fd 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -286,7 +286,7 @@ private void finishLoadProfile(String profileName) {
private boolean hasLockscreenSecurity() {
LockPatternUtils lpu = new LockPatternUtils(getActivity());
- return lpu.isLockPasswordEnabled() || lpu.isLockPatternEnabled();
+ return lpu.isLockPasswordEnabled() || lpu.isLockPatternEnabled() || lpu.isLockGestureEnabled();
}
private void launchChooseLockscreen() {
diff --git a/src/com/android/settings/util/AbstractAsyncSuCMDProcessor.java b/src/com/android/settings/util/AbstractAsyncSuCMDProcessor.java
new file mode 100644
index 00000000000..f1a16fae1f2
--- /dev/null
+++ b/src/com/android/settings/util/AbstractAsyncSuCMDProcessor.java
@@ -0,0 +1,104 @@
+
+package com.android.settings.util;
+
+import android.os.AsyncTask;
+
+/**
+ * An abstract implentation of AsyncTask
+ *
+ * since our needs are simple send a command, perform a task when we finish
+ * this implentation requires you send the command as String...
+ * in the .execute(String) so you can send String[] of commands if needed
+ *
+ * This class is not for you if...
+ * 1) You do not need to perform any action after command execution
+ * you want a Thread not this.
+ * 2) You need to perform more complex tasks in doInBackground
+ * than simple script/command sequence of commands
+ * you want your own AsyncTask not this.
+ *
+ * This class is for you if...
+ * 1) You need to run a command/script/sequence of commands without
+ * blocking the UI thread and you must perform actions after the
+ * task completes.
+ * 2) see #1.
+ */
+public abstract class AbstractAsyncSuCMDProcessor extends AsyncTask {
+ // if /system needs to be mounted before command
+ private boolean mMountSystem;
+ // return if we recieve a null command or empty command
+ public final String FAILURE = "failed_no_command";
+
+ /**
+ * Constructor that allows mounting/dismounting
+ * of /system partition while in background thread
+ */
+ public AbstractAsyncSuCMDProcessor(boolean mountSystem) {
+ this.mMountSystem = mountSystem;
+ }
+
+ /**
+ * Constructor that assumes /system should not be mounted
+ */
+ public AbstractAsyncSuCMDProcessor() {
+ this.mMountSystem = false;
+ }
+
+ /**
+ * DO NOT override this method you should simply send your commands off
+ * as params and expect to handle results in {@link #onPostExecute}
+ *
+ * if you find a need to @Override this method then you should
+ * consider using a new AsyncTask implentation instead
+ *
+ * @param params The parameters of the task.
+ *
+ * @return A result, defined by the subclass of this task.
+ */
+ @Override
+ protected String doInBackground(String... params) {
+ // don't bother if we don't get a command
+ if (params[0] == null || params[0].trim().equals(""))
+ return FAILURE;
+
+ String stdout = null;
+
+ // conditionally enforce mounting
+ if (mMountSystem) {
+ Helpers.getMount("rw");
+ }
+ try {
+ // process all commands ***DO NOT SEND null OR ""; you have been warned***
+ for (int i = 0; params.length > i; i++) {
+ // always watch for null and empty strings, lazy devs :/
+ if (params[i] != null && !params[i].trim().equals("")) {
+ stdout = CMDProcessor.runSuCommand(params[i]).getStdout();
+ } else {
+ // bail because of careless devs
+ return FAILURE;
+ }
+ }
+ // always unmount
+ } finally {
+ if (mMountSystem)
+ Helpers.getMount("ro");
+ }
+ // return the stdout from the command
+ return stdout;
+ }
+
+ /**
+ * Runs on the UI thread after {@link #doInBackground}. The
+ * specified result is the value returned by {@link #doInBackground}.
+ *
+ * This method won't be invoked if the task was cancelled.
+ *
+ * You MUST @Override this method if you don't need the result
+ * then you should consider using a new Thread implentation instead
+ *
+ * @param result The result of the operation computed by {@link #doInBackground}.
+ */
+ @Override
+ protected abstract void onPostExecute(String result);
+}
+
diff --git a/src/com/android/settings/util/CMDProcessor.java b/src/com/android/settings/util/CMDProcessor.java
new file mode 100644
index 00000000000..b950d849eb8
--- /dev/null
+++ b/src/com/android/settings/util/CMDProcessor.java
@@ -0,0 +1,69 @@
+package com.android.settings.util;
+
+import android.util.Log;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+// convenience import for quick referencing of this method
+
+public final class CMDProcessor {
+ private static final String TAG = "CMDProcessor";
+
+ private CMDProcessor() {
+ // Cannot instantiate this class
+ throw new AssertionError();
+ }
+
+ /* Run a system command with full redirection */
+ public static ChildProcess startSysCmd(String[] cmdarray, String childStdin) {
+ return new ChildProcess(cmdarray, childStdin);
+ }
+
+ public static CommandResult runSysCmd(String[] cmdarray, String childStdin) {
+ ChildProcess proc = startSysCmd(cmdarray, childStdin);
+ proc.waitFinished();
+ return proc.getResult();
+ }
+
+ public static ChildProcess startShellCommand(String cmd) {
+ String[] cmdarray = new String[3];
+ cmdarray[0] = "sh";
+ cmdarray[1] = "-c";
+ cmdarray[2] = cmd;
+ return startSysCmd(cmdarray, null);
+ }
+
+ public static CommandResult runShellCommand(String cmd) {
+ ChildProcess proc = startShellCommand(cmd);
+ proc.waitFinished();
+ return proc.getResult();
+ }
+
+ public static ChildProcess startSuCommand(String cmd) {
+ String[] cmdarray = new String[3];
+ cmdarray[0] = "su";
+ cmdarray[1] = "-c";
+ cmdarray[2] = cmd;
+ return startSysCmd(cmdarray, null);
+ }
+
+ public static CommandResult runSuCommand(String cmd) {
+ ChildProcess proc = startSuCommand(cmd);
+ proc.waitFinished();
+ return proc.getResult();
+ }
+
+ public static boolean canSU() {
+ CommandResult r = runShellCommand("id");
+ StringBuilder out = new StringBuilder(0);
+ out.append(r.getStdout());
+ out.append(" ; ");
+ out.append(r.getStderr());
+ Log.d(TAG, "canSU() su[" + r.getExitValue() + "]: " + out);
+ return r.success();
+ }
+}
diff --git a/src/com/android/settings/util/CMDProcessor2.java b/src/com/android/settings/util/CMDProcessor2.java
new file mode 100644
index 00000000000..47239964200
--- /dev/null
+++ b/src/com/android/settings/util/CMDProcessor2.java
@@ -0,0 +1,154 @@
+/*
+ * Performance Control - An Android CPU Control application Copyright (C) 2012
+ * Jared Rummler Copyright (C) 2012 James Roberts
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+package com.android.settings.util;
+
+import android.util.Log;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.InputStream;
+
+public class CMDProcessor2 implements Constants {
+
+ private static final String LD_LIBRARY_PATH = System.getenv("LD_LIBRARY_PATH");
+ private static final String TAG = "CMD Processor";
+
+ private Boolean can_su;
+ public SH sh;
+ public SH su;
+
+ public CMDProcessor2() {
+ sh = new SH("sh");
+ su = new SH("su");
+ }
+
+ public SH suOrSH() {
+ return canSU() ? su : sh;
+ }
+
+ public boolean canSU() {
+ return canSU(false);
+ }
+
+ public class CommandResult {
+ public final String stdout;
+ public final String stderr;
+ public final Integer exit_value;
+
+ CommandResult(final Integer exit_value_in) {
+ this(exit_value_in, null, null);
+ }
+
+ CommandResult(final Integer exit_value_in, final String stdout_in,
+ final String stderr_in) {
+ exit_value = exit_value_in;
+ stdout = stdout_in;
+ stderr = stderr_in;
+ }
+
+ public boolean success() {
+ return exit_value != null && exit_value == 0;
+ }
+ }
+
+ public class SH {
+ private String SHELL = "sh";
+
+ public SH(final String SHELL_in) {
+ SHELL = SHELL_in;
+ }
+
+ private String getStreamLines(final InputStream is) {
+ String out = null;
+ StringBuffer buffer = null;
+ final DataInputStream dis = new DataInputStream(is);
+
+ try {
+ if (dis.available() > 0) {
+ buffer = new StringBuffer(dis.readLine());
+ while (dis.available() > 0) {
+ buffer.append("\n").append(dis.readLine());
+ }
+ }
+ dis.close();
+ } catch (final Exception ex) {
+ Log.e(TAG, ex.getMessage());
+ }
+ if (buffer != null) {
+ out = buffer.toString();
+ }
+ return out;
+ }
+
+ public Process run(final String s) {
+ Process process;
+ try {
+ process = Runtime.getRuntime().exec(SHELL);
+ final DataOutputStream toProcess = new DataOutputStream(
+ process.getOutputStream());
+ toProcess.writeBytes("exec " + s + "\n");
+ toProcess.flush();
+ } catch (final Exception e) {
+ Log.e(TAG,
+ "Exception while trying to run: '" + s + "' "
+ + e.getMessage());
+ process = null;
+ }
+ return process;
+ }
+
+ public CommandResult runWaitFor(final String s) {
+ final Process process = run(s);
+ Integer exit_value = null;
+ String stdout = null;
+ String stderr = null;
+ if (process != null) {
+ try {
+ exit_value = process.waitFor();
+
+ stdout = getStreamLines(process.getInputStream());
+ stderr = getStreamLines(process.getErrorStream());
+
+ } catch (final Exception e) {
+ Log.e(TAG, "runWaitFor " + e.toString());
+ }
+ }
+ return new CommandResult(exit_value, stdout, stderr);
+ }
+ }
+
+ public boolean canSU(final boolean force_check) {
+ if (can_su == null || force_check) {
+ final CommandResult r = su.runWaitFor("id");
+ final StringBuilder out = new StringBuilder();
+
+ if (r.stdout != null) {
+ out.append(r.stdout).append(" ; ");
+ }
+ if (r.stderr != null) {
+ out.append(r.stderr);
+ }
+
+ Log.d(TAG, "canSU() su[" + r.exit_value + "]: " + out);
+ can_su = r.success();
+ }
+ return can_su;
+ }
+}
+
diff --git a/src/com/android/settings/util/ChildProcess.java b/src/com/android/settings/util/ChildProcess.java
new file mode 100644
index 00000000000..58b73afc1e5
--- /dev/null
+++ b/src/com/android/settings/util/ChildProcess.java
@@ -0,0 +1,149 @@
+package com.android.settings.util;
+
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+import static java.lang.System.nanoTime;
+
+public class ChildProcess {
+ private String TAG = getClass().getSimpleName();
+
+ private static final int PIPE_SIZE = 1024;
+
+ private class ChildReader extends Thread {
+ InputStream mStream;
+ StringBuffer mBuffer;
+ ChildReader(InputStream is, StringBuffer buf) {
+ mStream = is;
+ mBuffer = buf;
+ }
+ public void run() {
+ byte[] buf = new byte[PIPE_SIZE];
+ try {
+ int len;
+ while ((len = mStream.read(buf)) != -1) {
+ String s = new String(buf, 0, len);
+ mBuffer.append(s);
+ }
+ }
+ catch (IOException e) {
+ // Ignore
+ }
+ try {
+ mStream.close();
+ }
+ catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+ private class ChildWriter extends Thread {
+ OutputStream mStream;
+ String mBuffer;
+ ChildWriter(OutputStream os, String buf) {
+ mStream = os;
+ mBuffer = buf;
+ }
+ public void run() {
+ int off = 0;
+ byte[] buf = mBuffer.getBytes();
+ try {
+ while (off < buf.length) {
+ int len = Math.min(PIPE_SIZE, buf.length - off);
+ mStream.write(buf, off, len);
+ off += len;
+ }
+ }
+ catch (IOException e) {
+ // Ignore
+ }
+ try {
+ mStream.close();
+ }
+ catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+
+ private long mStartTime;
+ private Process mChildProc;
+ private ChildWriter mChildStdinWriter;
+ private ChildReader mChildStdoutReader;
+ private ChildReader mChildStderrReader;
+ private StringBuffer mChildStdout;
+ private StringBuffer mChildStderr;
+ private int mExitValue;
+ private long mEndTime;
+
+ public ChildProcess(String[] cmdarray, String childStdin) {
+ mStartTime = nanoTime();
+ try {
+ mChildProc = Runtime.getRuntime().exec(cmdarray);
+ if (childStdin != null) {
+ mChildStdinWriter = new ChildWriter(mChildProc.getOutputStream(), childStdin);
+ mChildStdinWriter.start();
+ }
+ mChildStdout = new StringBuffer();
+ mChildStdoutReader = new ChildReader(mChildProc.getInputStream(), mChildStdout);
+ mChildStdoutReader.start();
+ mChildStderr = new StringBuffer();
+ mChildStderrReader = new ChildReader(mChildProc.getErrorStream(), mChildStderr);
+ mChildStderrReader.start();
+ }
+ catch (IOException e) {
+ // XXX: log
+ }
+ }
+
+ public boolean isFinished() {
+ boolean finished = true;
+ if (mChildProc != null) {
+ try {
+ mChildProc.exitValue();
+ }
+ catch (IllegalStateException e) {
+ finished = false;
+ }
+ }
+ return finished;
+ }
+
+ public int waitFinished() {
+ while (mChildProc != null) {
+ try {
+ mExitValue = mChildProc.waitFor();
+ mEndTime = nanoTime();
+ mChildProc = null;
+ mChildStderrReader.join();
+ mChildStderrReader = null;
+ mChildStdoutReader.join();
+ mChildStdoutReader = null;
+ if (mChildStdinWriter != null) {
+ mChildStdinWriter.join();
+ mChildStdinWriter = null;
+ }
+ }
+ catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ return mExitValue;
+ }
+
+ public CommandResult getResult() {
+ if (!isFinished()) {
+ throw new IllegalThreadStateException("Child process running");
+ }
+ return new CommandResult(
+ mStartTime,
+ mExitValue,
+ mChildStdout.toString(),
+ mChildStderr.toString(),
+ mEndTime);
+ }
+}
diff --git a/src/com/android/settings/util/CommandResult.java b/src/com/android/settings/util/CommandResult.java
new file mode 100644
index 00000000000..cf80ef89b29
--- /dev/null
+++ b/src/com/android/settings/util/CommandResult.java
@@ -0,0 +1,168 @@
+package com.android.settings.util;
+
+import android.os.Environment;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+@SuppressWarnings("AccessOfSystemProperties")
+public class CommandResult implements Parcelable {
+ private final String TAG = getClass().getSimpleName();
+ private final long mStartTime;
+ private final int mExitValue;
+ private final String mStdout;
+ private final String mStderr;
+ private final long mEndTime;
+
+ public CommandResult(long startTime,
+ int exitValue,
+ String stdout,
+ String stderr,
+ long endTime) {
+ mStartTime = startTime;
+ mExitValue = exitValue;
+ mStdout = stdout;
+ mStderr = stderr;
+ mEndTime = endTime;
+
+ Log.d(TAG, "Time to execute: " + (mEndTime - mStartTime) + " ns (nanoseconds)");
+ // this is set last so log from here
+ checkForErrors();
+ }
+
+ // pretty much just forward the constructor from parcelable to our main
+ // loading constructor
+ @SuppressWarnings("CastToConcreteClass")
+ public CommandResult(Parcel inParcel) {
+ this(inParcel.readLong(),
+ inParcel.readInt(),
+ inParcel.readString(),
+ inParcel.readString(),
+ inParcel.readLong());
+ }
+
+ public boolean success() {
+ return (mExitValue == 0);
+ }
+
+ public long getEndTime() {
+ return mEndTime;
+ }
+
+ public String getStderr() {
+ return new String(mStderr);
+ }
+
+ public String getStdout() {
+ return new String(mStdout);
+ }
+
+ public Integer getExitValue() {
+ return mExitValue;
+ }
+
+ public long getStartTime() {
+ return mStartTime;
+ }
+
+ @SuppressWarnings("UnnecessaryExplicitNumericCast")
+ private void checkForErrors() {
+ if (mExitValue != 0
+ || !"".equals(mStderr.trim())) {
+ // don't log the commands that failed
+ // because the cpu was offline
+ boolean skipOfflineCpu =
+ // if core is off locking fails
+ mStderr.contains("chmod: /sys/devices/system/cpu/cpu")
+ // if core is off applying cpu freqs fails
+ || mStderr.contains(": can't create /sys/devices/system/cpu/cpu");
+ String lineEnding = System.getProperty("line.separator");
+ FileWriter errorWriter = null;
+ try {
+ File errorLogFile = new File(
+ Environment.getExternalStorageDirectory()
+ + "/aokp/error.txt");
+ if (!errorLogFile.exists()) {
+ errorLogFile.createNewFile();
+ }
+ errorWriter = new FileWriter(errorLogFile, true);
+ // only log the cpu state as offline while writing
+ if (skipOfflineCpu) {
+ errorWriter.write(lineEnding);
+ errorWriter.write("Attempted to write to an offline cpu core (ignore me).");
+ } else {
+ errorWriter.write(TAG + " shell error detected!");
+ errorWriter.write(lineEnding);
+ errorWriter.write("CommandResult {" + this.toString() + '}');
+ errorWriter.write(lineEnding);
+ }
+ errorWriter.write(lineEnding);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to write command result to error file", e);
+ } finally {
+ if (errorWriter != null) {
+ try {
+ errorWriter.close();
+ } catch (IOException ignored) {
+ // let it go
+ }
+ }
+ }
+ }
+ }
+
+ // implement parcelable
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ parcel.writeLong(mStartTime);
+ parcel.writeInt(mExitValue);
+ parcel.writeString(mStdout);
+ parcel.writeString(mStderr);
+ parcel.writeLong(mEndTime);
+ }
+
+ @Override
+ public String toString() {
+ return "CommandResult{" +
+ ", mStartTime=" + mStartTime +
+ ", mExitValue=" + mExitValue +
+ ", stdout='" + mStdout + "'" +
+ ", stderr='" + mStderr + "'" +
+ ", mEndTime=" + mEndTime +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof CommandResult)) return false;
+
+ CommandResult that = (CommandResult) o;
+
+ return (mStartTime == that.mStartTime &&
+ mExitValue == that.mExitValue &&
+ mStdout == that.mStdout &&
+ mStderr == that.mStderr &&
+ mEndTime == that.mEndTime);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 0;
+ result = 31 * result + (int) (mStartTime ^ (mStartTime >>> 32));
+ result = 31 * result + mExitValue;
+ result = 31 * result + (mStdout != null ? mStdout.hashCode() : 0);
+ result = 31 * result + (mStderr != null ? mStderr.hashCode() : 0);
+ result = 31 * result + (int) (mEndTime ^ (mEndTime >>> 32));
+ return result;
+ }
+}
diff --git a/src/com/android/settings/util/Constants.java b/src/com/android/settings/util/Constants.java
new file mode 100644
index 00000000000..906e4006dc5
--- /dev/null
+++ b/src/com/android/settings/util/Constants.java
@@ -0,0 +1,221 @@
+/*
+ * Performance Control - An Android CPU Control application Copyright (C) 2012
+ * James Roberts
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+package com.android.settings.util;
+
+public interface Constants {
+
+ //hide flashing kernel/recovery options
+ // NO_FLASH=true > hide flash options
+ // NO_FLASH=false > show flash options
+ public static final Boolean NO_FLASH = false;
+
+ // Fragment IDs
+ public static final int FRAGMENT_ID_CPUSETTINGS = 0;
+ public static final int FRAGMENT_ID_BATTERYINFO = 1;
+ public static final int FRAGMENT_ID_OOMSETTINGS = 2;
+ public static final int FRAGMENT_ID_VM = 3;
+ public static final int FRAGMENT_ID_VOLTAGECONROL = 4;
+ public static final int FRAGMENT_ID_ADVANCED = 5;
+ public static final int FRAGMENT_ID_TIMEINSTATE = 6;
+ public static final int FRAGMENT_ID_CPUINFO = 7;
+ public static final int FRAGMENT_ID_DISKINFO = 8;
+ public static final int FRAGMENT_ID_TOOLS = 9;
+
+ // CPU settings
+ public static final String CPU_PATH = "/sys/devices/system/cpu/cpu";
+ public static final String CPU_FREQ_TAIL = "/cpufreq/scaling_cur_freq";
+ public static final String CUR_CPU_PATH = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq";
+ public static final String MAX_FREQ_PATH = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq";
+ public static final String TEGRA_MAX_FREQ_PATH = "/sys/module/cpu_tegra/parameters/cpu_user_cap";
+ public static final String MIN_FREQ_PATH = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq";
+ public static final String STEPS_PATH = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies";
+ public static final String GOVERNORS_LIST_PATH = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors";
+ public static final String GOVERNOR_PATH = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor";
+ public static final String[] IO_SCHEDULER_PATH = {"/sys/block/mmcblk0/queue/scheduler", "/sys/block/mmcblk1/queue/scheduler"};
+ //Dynamic frequency scaling
+ public static final String DYN_MAX_FREQ_PATH = "/sys/power/cpufreq_max_limit";
+ public static final String DYN_MIN_FREQ_PATH = "/sys/power/cpufreq_min_limit";
+
+ public static final String NUM_OF_CPUS_PATH = "/sys/devices/system/cpu/present";
+
+ public static final String PREF_MAX_CPU = "pref_max_cpu";
+ public static final String PREF_MIN_CPU = "pref_min_cpu";
+ public static final String PREF_GOV = "pref_gov";
+ public static final String PREF_IO = "pref_io";
+ public static final String CPU_SOB = "cpu_sob";
+ public static final String GOV_SOB = "gov_settings_sob";
+ public static final String GOV_SETTINGS = "gov_settings";
+ public static final String GOV_NAME = "gov_name";
+ public static final String GOV_SETTINGS_PATH = "/sys/devices/system/cpu/cpufreq/";
+
+ // CPU info
+ public static String KERNEL_INFO_PATH = "/proc/version";
+ public static String CPU_INFO_PATH = "/proc/cpuinfo";
+ public static String MEM_INFO_PATH = "/proc/meminfo";
+
+ // Time in state
+ public static final String TIME_IN_STATE_PATH = "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state";
+ public static final String TIME_IN_STATE_TAIL = "/cpufreq/stats/time_in_state";
+ public static final String PREF_OFFSETS = "pref_offsets";
+ // Battery
+ public static final String BAT_VOLT_PATH = "/sys/class/power_supply/battery/voltage_now";
+
+ // Other settings
+ public static final String MINFREE_PATH = "/sys/module/lowmemorykiller/parameters/minfree";
+ public static final String MINFREE_ADJ_PATH = "/sys/module/lowmemorykiller/parameters/adj";
+ public static final String READ_AHEAD_PATH = "/sys/block/mmcblk0/bdi/read_ahead_kb";
+ //"/sys/devices/virtual/bdi/default/read_ahead_kb"
+
+ public static final String INTENT_ACTION_FASTCHARGE = "com.aokp.romcontrol.FCHARGE_CHANGED";
+ public static final String PREF_MINFREE = "pref_minfree";
+ public static final String PREF_MINFREE_BOOT = "pref_minfree_boot";
+ public static final String PREF_READ_AHEAD = "pref_read_ahead";
+ public static final String PREF_READ_AHEAD_BOOT = "pref_read_ahead_boot";
+ public static final String PREF_FASTCHARGE = "pref_fast_charge";
+ //------ MinFree ------
+ public static final String OOM_FOREGROUND_APP = "oom_foreground_app";
+ public static final String OOM_VISIBLE_APP = "oom_visible_app";
+ public static final String OOM_SECONDARY_SERVER = "oom_secondary_server";
+ public static final String OOM_HIDDEN_APP = "oom_hidden_app";
+ public static final String OOM_CONTENT_PROVIDERS = "oom_content_providers";
+ public static final String OOM_EMPTY_APP = "oom_empty_app";
+ //------ KSM
+ public static final String KSM_RUN_PATH = "/sys/kernel/mm/ksm/run";
+ public static final String KSM_FULLSCANS_PATH = "/sys/kernel/mm/ksm/full_scans";
+ public static final String KSM_PAGESSHARED_PATH = "/sys/kernel/mm/ksm/pages_shared";
+ public static final String KSM_PAGESSHARING_PATH = "/sys/kernel/mm/ksm/pages_sharing";
+ public static final String KSM_PAGESTOSCAN_PATH = "/sys/kernel/mm/ksm/pages_to_scan";
+ public static final String KSM_PAGESUNSHERED_PATH = "/sys/kernel/mm/ksm/pages_unshared";
+ public static final String KSM_PAGESVOLATILE_PATH = "/sys/kernel/mm/ksm/pages_volatile";
+ public static final String KSM_SLEEP_PATH = "/sys/kernel/mm/ksm/sleep_millisecs";
+ public static final String PREF_RUN_KSM = "pref_run_ksm";
+ public static final String KSM_SOB = "ksm_boot";
+
+ //------ DoNotKillProc
+ public static final String USER_PROC_PATH = "/sys/module/lowmemorykiller/parameters/donotkill_proc";
+ public static final String SYS_PROC_PATH = "/sys/module/lowmemorykiller/parameters/donotkill_sysproc";
+ public static final String USER_PROC_NAMES_PATH = "/sys/module/lowmemorykiller/parameters/donotkill_proc_names";
+ public static final String USER_SYS_NAMES_PATH = "/sys/module/lowmemorykiller/parameters/donotkill_sysproc_names";
+ public static final String USER_PROC_SOB = "user_proc_boot";
+ public static final String SYS_PROC_SOB = "sys_proc_boot";
+ public static final String PREF_USER_PROC = "pref_user_proc";
+ public static final String PREF_SYS_PROC = "pref_sys_proc";
+ public static final String PREF_USER_NAMES = "pref_user_names_proc";
+ public static final String PREF_SYS_NAMES = "pref_sys_names_proc";
+ //-------BLX---------
+ public static final String PREF_BLX = "pref_blx";
+ public static final String BLX_PATH = "/sys/class/misc/batterylifeextender/charging_limit";
+ public static final String BLX_SOB = "blx_sob";
+ //-------DFsync---------
+ public static final String DSYNC_PATH = "/sys/kernel/dyn_fsync/Dyn_fsync_active";
+ public static final String PREF_DSYNC = "pref_dsync";
+ //-------BL----
+ public static final String PREF_BLTIMEOUT = "pref_bltimeout";
+ public static final String BLTIMEOUT_SOB = "bltimeout_sob";
+ public static final String PREF_BLTOUCH = "pref_bltouch";
+ public static final String BL_TIMEOUT_PATH = "/sys/class/misc/notification/bl_timeout";
+ public static final String BL_TOUCH_ON_PATH = "/sys/class/misc/notification/touchlight_enabled";
+ //-------BLN---------
+ public static final String PREF_BLN = "pref_bln";
+ //-------PFK---------
+ public static final String PFK_VER = "/sys/class/misc/phantom_kp_filter/version";
+ public static final String PFK_HOME_ON = "pfk_home_on";
+ public static final String PREF_HOME_ALLOWED_IRQ = "pref_home_allowed_irq";
+ public static final String PREF_HOME_REPORT_WAIT = "pref_home_report_wait";
+ public static final String PFK_MENUBACK_ON = "pfk_menuback_on";
+ public static final String PREF_MENUBACK_INTERRUPT_CHECKS = "pref_menuback_interrupt_checks";
+ public static final String PREF_MENUBACK_FIRST_ERR_WAIT = "pref_menuback_first_err_wait";
+ public static final String PREF_MENUBACK_LAST_ERR_WAIT = "pref_menuback_last_err_wait";
+
+ public static final String PFK_HOME_ENABLED = "/sys/class/misc/phantom_kp_filter/home_enabled";
+ public static final String PFK_HOME_ALLOWED_IRQ = "/sys/class/misc/phantom_kp_filter/home_allowed_irqs";
+ public static final String PFK_HOME_REPORT_WAIT = "/sys/class/misc/phantom_kp_filter/home_report_wait";
+ public static final String PFK_HOME_IGNORED_KP = "/sys/class/misc/phantom_kp_filter/home_ignored_kp";
+ public static final String PFK_MENUBACK_ENABLED = "/sys/class/misc/phantom_kp_filter/menuback_enabled";
+ public static final String PFK_MENUBACK_INTERRUPT_CHECKS = "/sys/class/misc/phantom_kp_filter/menuback_interrupt_checks";
+ public static final String PFK_MENUBACK_FIRST_ERR_WAIT = "/sys/class/misc/phantom_kp_filter/menuback_first_err_wait";
+ public static final String PFK_MENUBACK_LAST_ERR_WAIT = "/sys/class/misc/phantom_kp_filter/menuback_last_err_wait";
+ public static final String PFK_MENUBACK_IGNORED_KP = "/sys/class/misc/phantom_kp_filter/menuback_ignored_kp";
+ public static final String PFK_SOB = "pfk_sob";
+ //------------------
+ public static final String DYNAMIC_DIRTY_WRITEBACK_PATH = "/proc/sys/vm/dynamic_dirty_writeback";
+ public static final String DIRTY_WRITEBACK_ACTIVE_PATH = "/proc/sys/vm/dirty_writeback_active_centisecs";
+ public static final String DIRTY_WRITEBACK_SUSPEND_PATH = "/proc/sys/vm/dirty_writeback_suspend_centisecs";
+ public static final String PREF_DYNAMIC_DIRTY_WRITEBACK = "pref_dynamic_dirty_writeback";
+ public static final String PREF_DIRTY_WRITEBACK_ACTIVE = "pref_dynamic_writeback_active";
+ public static final String PREF_DIRTY_WRITEBACK_SUSPEND = "pref_dynamic_writeback_suspend";
+ public static final String DYNAMIC_DIRTY_WRITEBACK_SOB = "dynamic_write_back_sob";
+
+ // VM settings
+ public static final String PREF_DIRTY_RATIO = "pref_dirty_ratio";
+ public static final String PREF_DIRTY_BACKGROUND = "pref_dirty_background";
+ public static final String PREF_DIRTY_EXPIRE = "pref_dirty_expire";
+ public static final String PREF_DIRTY_WRITEBACK = "pref_dirty_writeback";
+ public static final String PREF_MIN_FREE_KB = "pref_min_free_kb";
+ public static final String PREF_OVERCOMMIT = "pref_overcommit";
+ public static final String PREF_SWAPPINESS = "pref_swappiness";
+ public static final String PREF_VFS = "pref_vfs";
+ public static final String DIRTY_RATIO_PATH = "/proc/sys/vm/dirty_ratio";
+ public static final String DIRTY_BACKGROUND_PATH = "/proc/sys/vm/dirty_background_ratio";
+ public static final String DIRTY_EXPIRE_PATH = "/proc/sys/vm/dirty_expire_centisecs";
+ public static final String DIRTY_WRITEBACK_PATH = "/proc/sys/vm/dirty_writeback_centisecs";
+ public static final String MIN_FREE_PATH = "/proc/sys/vm/min_free_kbytes";
+ public static final String OVERCOMMIT_PATH = "/proc/sys/vm/overcommit_ratio";
+ public static final String SWAPPINESS_PATH = "/proc/sys/vm/swappiness";
+ public static final String VFS_CACHE_PRESSURE_PATH = "/proc/sys/vm/vfs_cache_pressure";
+ public static final String VM_SOB = "vm_sob";
+
+ // Voltage control
+ public static final String VOLTAGE_SOB = "voltage_sob";
+ public static final String UV_MV_PATH = "/sys/devices/system/cpu/cpu0/cpufreq/UV_mV_table";
+ public static final String VDD_PATH = "/sys/devices/system/cpu/cpu0/cpufreq/vdd_levels";
+ public static final String COMMON_VDD_PATH = "/sys/devices/system/cpu/cpufreq/vdd_levels";
+ public static final String VDD_SYSFS_PATH = "/sys/devices/system/cpu/cpu0/cpufreq/vdd_sysfs_levels";
+
+ //Tools
+ public static final String PREF_SH = "pref_sh";
+ public static final String PREF_WIPE_CACHE = "pref_wipe_cache";
+ public static final String NOT_FOUND = "not found";
+ public static final String FLASH_KERNEL = "pref_kernel_img";
+ public static final String FLASH_RECOVERY = "pref_recovery_img";
+ public static final String RESIDUAL_FILES = "pref_residual_files";
+ public static final String residualfiles[] = {"/data/log", "/data/tombstones", "/data/system/dropbox", "/data/system/usagestats", "/data/anr", "/data/local/tmp"};//add coresponding info in strings
+ public static final String PREF_FIX_PERMS = "pref_fix_perms";
+ public static final String PREF_LOG = "pref_log";
+ public static final String PREF_OPTIM_DB = "pref_optim_db";
+
+ //Freezer
+ public static final String PREF_FRREZE = "freeze_packs";
+ public static final String PREF_UNFRREZE = "unfreeze_packs";
+
+ //zRam
+ public static final String ISZRAM = "busybox echo `busybox zcat /proc/config.gz | busybox grep ZRAM | busybox grep -v ^#'`";
+ public static final String ZRAM_DEV = "/dev/block/zram0";
+ public static final String ZRAM_SIZE_PATH = "/sys/block/zram0/disksize";
+ public static final String ZRAM_RESET_PATH = "/sys/block/zram0/reset";
+ public static final String ZRAM_COMPR_PATH = "/sys/block/zram0/compr_data_size";
+ public static final String ZRAM_ORIG_PATH = "/sys/block/zram0/orig_data_size";
+ public static final String ZRAM_MEMTOT_PATH = "/sys/block/zram0/mem_used_total";
+
+ // PC Settings
+ public static final String PREF_USE_LIGHT_THEME = "use_light_theme";
+ public static final String PREF_WIDGET_BG_COLOR = "widget_bg_color";
+ public static final String PREF_WIDGET_TEXT_COLOR = "widget_text_color";
+
+}
diff --git a/src/com/android/settings/util/Helpers.java b/src/com/android/settings/util/Helpers.java
new file mode 100644
index 00000000000..1017f8c6701
--- /dev/null
+++ b/src/com/android/settings/util/Helpers.java
@@ -0,0 +1,319 @@
+
+package com.android.settings.util;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.SystemProperties;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Date;
+
+// don't show unavoidable warnings
+@SuppressWarnings({
+ "UnusedDeclaration",
+ "MethodWithMultipleReturnPoints",
+ "ReturnOfNull",
+ "NestedAssignment",
+ "DynamicRegexReplaceableByCompiledPattern",
+ "BreakStatement"})
+public class Helpers {
+ // avoids hardcoding the tag
+ private static final String TAG = Thread.currentThread().getStackTrace()[1].getClassName();
+
+ public Helpers() {
+ // dummy constructor
+ }
+
+ /**
+ * Checks device for SuperUser permission
+ *
+ * @return If SU was granted or denied
+ */
+ @SuppressWarnings("MethodWithMultipleReturnPoints")
+ public static boolean checkSu() {
+ if (!new File("/system/bin/su").exists()
+ && !new File("/system/xbin/su").exists()) {
+ Log.e(TAG, "su binary does not exist!!!");
+ return false; // tell caller to bail...
+ }
+ try {
+ if (CMDProcessor.runSuCommand("ls /data/app-private").success()) {
+ Log.i(TAG, " SU exists and we have permission");
+ return true;
+ } else {
+ Log.i(TAG, " SU exists but we don't have permission");
+ return false;
+ }
+ } catch (NullPointerException e) {
+ Log.e(TAG, "NullPointer throw while looking for su binary", e);
+ return false;
+ }
+ }
+
+ /**
+ * Checks device for network connectivity
+ *
+ * @return If the device has data connectivity
+ */
+ public static boolean isNetworkAvailable(Context context) {
+ boolean state = false;
+ if (context != null) {
+ ConnectivityManager cm =
+ (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo netInfo = cm.getActiveNetworkInfo();
+ if (netInfo != null && netInfo.isConnected()) {
+ Log.i(TAG, "The device currently has data connectivity");
+ state = true;
+ } else {
+ Log.i(TAG, "The device does not currently have data connectivity");
+ state = false;
+ }
+ }
+ return state;
+ }
+
+ /**
+ * Checks to see if Busybox is installed in "/system/"
+ *
+ * @return If busybox exists
+ */
+ public static boolean checkBusybox() {
+ if (!new File("/system/bin/busybox").exists()
+ && !new File("/system/xbin/busybox").exists()) {
+ Log.e(TAG, "Busybox not in xbin or bin!");
+ return false;
+ }
+ try {
+ if (!CMDProcessor.runSuCommand("busybox mount").success()) {
+ Log.e(TAG, "Busybox is there but it is borked! ");
+ return false;
+ }
+ } catch (NullPointerException e) {
+ Log.e(TAG, "NullpointerException thrown while testing busybox", e);
+ return false;
+ }
+ return true;
+ }
+
+ public static String[] getMounts(CharSequence path) {
+ BufferedReader bufferedReader = null;
+ try {
+ bufferedReader = new BufferedReader(new FileReader("/proc/mounts"), 256);
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ if (line.contains(path)) {
+ return line.split(" ");
+ }
+ }
+ } catch (FileNotFoundException ignored) {
+ Log.d(TAG, "/proc/mounts does not exist");
+ } catch (IOException ignored) {
+ Log.d(TAG, "Error reading /proc/mounts");
+ } finally {
+ if (bufferedReader != null) {
+ try {
+ bufferedReader.close();
+ } catch (IOException ignored) {
+ // ignored
+ }
+ }
+ }
+ return null;
+ }
+
+ public static boolean getMount(String mount) {
+ String[] mounts = getMounts("/system");
+ if (mounts != null && mounts.length >= 3) {
+ String device = mounts[0];
+ String path = mounts[1];
+ String point = mounts[2];
+ String preferredMountCmd = new String("mount -o " + mount + ",remount -t " + point + ' ' + device + ' ' + path);
+ if (CMDProcessor.runSuCommand(preferredMountCmd).success()) {
+ return true;
+ }
+ }
+ String fallbackMountCmd = new String("busybox mount -o remount," + mount + " /system");
+ return CMDProcessor.runSuCommand(fallbackMountCmd).success();
+ }
+
+ public static String readOneLine(String fname) {
+ BufferedReader br = null;
+ String line = null;
+ try {
+ br = new BufferedReader(new FileReader(fname), 1024);
+ line = br.readLine();
+ } catch (FileNotFoundException ignored) {
+ Log.d(TAG, "File was not found! trying via shell...");
+ return readFileViaShell(fname, true);
+ } catch (IOException e) {
+ Log.d(TAG, "IOException while reading system file", e);
+ return readFileViaShell(fname, true);
+ } finally {
+ if (br != null) {
+ try {
+ br.close();
+ } catch (IOException ignored) {
+ // failed to close reader
+ }
+ }
+ }
+ return line;
+ }
+
+ public static String readFileViaShell(String filePath, boolean useSu) {
+ String command = new String("cat " + filePath);
+ return useSu ? CMDProcessor.runSuCommand(command).getStdout()
+ : CMDProcessor.runShellCommand(command).getStdout();
+ }
+
+ public static boolean writeOneLine(String filename, String value) {
+ FileWriter fileWriter = null;
+ try {
+ fileWriter = new FileWriter(filename);
+ fileWriter.write(value);
+ } catch (IOException e) {
+ String Error = "Error writing { " + value + " } to file: " + filename;
+ Log.e(TAG, Error, e);
+ return false;
+ } finally {
+ if (fileWriter != null) {
+ try {
+ fileWriter.close();
+ } catch (IOException ignored) {
+ // failed to close writer
+ }
+ }
+ }
+ return true;
+ }
+
+ public static String[] getAvailableIOSchedulers() {
+ String[] schedulers = null;
+ String[] aux = readStringArray("/sys/block/mmcblk0/queue/scheduler");
+ if (aux != null) {
+ schedulers = new String[aux.length];
+ for (int i = 0; i < aux.length; i++) {
+ schedulers[i] = aux[i].charAt(0) == '['
+ ? aux[i].substring(1, aux[i].length() - 1)
+ : aux[i];
+ }
+ }
+ return schedulers;
+ }
+
+ private static String[] readStringArray(String fname) {
+ String line = readOneLine(fname);
+ if (line != null) {
+ return line.split(" ");
+ }
+ return null;
+ }
+
+ public static String getIOScheduler() {
+ String scheduler = null;
+ String[] schedulers = readStringArray("/sys/block/mmcblk0/queue/scheduler");
+ if (schedulers != null) {
+ for (String s : schedulers) {
+ if (s.charAt(0) == '[') {
+ scheduler = s.substring(1, s.length() - 1);
+ break;
+ }
+ }
+ }
+ return scheduler;
+ }
+
+ /**
+ * Long toast message
+ *
+ * @param context Application Context
+ * @param msg Message to send
+ */
+ public static void msgLong(Context context, String msg) {
+ if (context != null && msg != null) {
+ Toast.makeText(context, msg.trim(), Toast.LENGTH_LONG).show();
+ }
+ }
+
+ /**
+ * Short toast message
+ *
+ * @param context Application Context
+ * @param msg Message to send
+ */
+ public static void msgShort(Context context, String msg) {
+ if (context != null && msg != null) {
+ Toast.makeText(context, msg.trim(), Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ /**
+ * Long toast message
+ *
+ * @param context Application Context
+ * @param msg Message to send
+ */
+ public static void sendMsg(Context context, String msg) {
+ if (context != null && msg != null) {
+ msgLong(context, msg);
+ }
+ }
+
+ /**
+ * Return a timestamp
+ *
+ * @param context Application Context
+ */
+ @SuppressWarnings("UnnecessaryFullyQualifiedName")
+ public static String getTimestamp(Context context) {
+ String timestamp = "unknown";
+ Date now = new Date();
+ java.text.DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(context);
+ java.text.DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(context);
+ if (dateFormat != null && timeFormat != null) {
+ timestamp = dateFormat.format(now) + ' ' + timeFormat.format(now);
+ }
+ return timestamp;
+ }
+
+ public static boolean isPackageInstalled(String packageName, PackageManager pm) {
+ try {
+ String mVersion = pm.getPackageInfo(packageName, 0).versionName;
+ if (mVersion == null) {
+ return false;
+ }
+ } catch (NameNotFoundException notFound) {
+ Log.e(TAG, "Package could not be found!", notFound);
+ return false;
+ }
+ return true;
+ }
+
+ public static void restartSystemUI() {
+ CMDProcessor.startSuCommand("pkill -TERM -f com.android.systemui");
+ }
+
+ public static void setSystemProp(String prop, String val) {
+ CMDProcessor.startSuCommand("setprop " + prop + " " + val);
+ }
+
+ public static String getSystemProp(String prop, String def) {
+ String result = null;
+ try {
+ result = SystemProperties.get(prop, def);
+ } catch (IllegalArgumentException iae) {
+ Log.e(TAG, "Failed to get prop: " + prop);
+ }
+ return result == null ? def : result;
+ }
+}
diff --git a/src/com/android/settings/util/Helpers2.java b/src/com/android/settings/util/Helpers2.java
new file mode 100644
index 00000000000..931926e3ef3
--- /dev/null
+++ b/src/com/android/settings/util/Helpers2.java
@@ -0,0 +1,581 @@
+/*
+ * Performance Control - An Android CPU Control application Copyright (C) 2012
+ * Jared Rummler Copyright (C) 2012 James Roberts
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+package com.android.settings.util;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.support.v4.view.ViewPager;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+
+import com.android.settings.R;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class Helpers2 implements Constants {
+
+ private static final String TAG = "Helpers2";
+
+ private static String mVoltagePath;
+
+ /**
+ * Checks device for SuperUser permission
+ *
+ * @return If SU was granted or denied
+ */
+ public static boolean checkSu() {
+ if (!new File("/system/bin/su").exists() && !new File("/system/xbin/su").exists()) {
+ Log.e(TAG, "su does not exist!!!");
+ return false; // tell caller to bail...
+ }
+ try {
+ if ((new CMDProcessor2().su.runWaitFor("ls /data/app-private")).success()) {
+ Log.i(TAG, " SU exists and we have permission");
+ return true;
+ } else {
+ Log.i(TAG, " SU exists but we dont have permission");
+ return false;
+ }
+ } catch (final NullPointerException e) {
+ Log.e(TAG, e.getMessage());
+ return false;
+ }
+ }
+
+ /**
+ * Checks to see if Busybox is installed in "/system/"
+ *
+ * @return If busybox exists
+ */
+ public static boolean checkBusybox() {
+ if (!new File("/system/bin/busybox").exists() && !new File("/system/xbin/busybox").exists()) {
+ Log.e(TAG, "Busybox not in xbin or bin!");
+ return false;
+ }
+ try {
+ if (!new CMDProcessor2().su.runWaitFor("busybox mount").success()) {
+ Log.e(TAG, " Busybox is there but it is borked! ");
+ return false;
+ }
+ } catch (final NullPointerException e) {
+ Log.e(TAG, e.getMessage());
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Return mount points
+ *
+ * @param path
+ * @return line if present
+ */
+ public static String[] getMounts(final String path) {
+ try {
+ BufferedReader br = new BufferedReader(new FileReader("/proc/mounts"), 256);
+ String line = null;
+ while ((line = br.readLine()) != null) {
+ if (line.contains(path)) {
+ return line.split(" ");
+ }
+ }
+ br.close();
+ } catch (FileNotFoundException e) {
+ Log.d(TAG, "/proc/mounts does not exist");
+ } catch (IOException e) {
+ Log.d(TAG, "Error reading /proc/mounts");
+ }
+ return null;
+ }
+
+ /**
+ * Get mounts
+ *
+ * @param mount
+ * @return success or failure
+ */
+ public static boolean getMount(final String mount) {
+ final CMDProcessor2 cmd = new CMDProcessor2();
+ final String mounts[] = getMounts("/system");
+ if (mounts != null && mounts.length >= 3) {
+ final String device = mounts[0];
+ final String path = mounts[1];
+ final String point = mounts[2];
+ if (cmd.su.runWaitFor("mount -o " + mount + ",remount -t " + point + " " + device + " " + path).success()) {
+ return true;
+ }
+ }
+ return (cmd.su.runWaitFor("busybox mount -o remount," + mount + " /system").success());
+ }
+
+ /**
+ * Read one line from file
+ *
+ * @param fname
+ * @return line
+ */
+ public static String readOneLine(String fname) {
+ String line = null;
+ if (new File(fname).exists()) {
+ BufferedReader br;
+ try {
+ br = new BufferedReader(new FileReader(fname), 512);
+ try {
+ line = br.readLine();
+ } finally {
+ br.close();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "IO Exception when reading sys file", e);
+ // attempt to do magic!
+ return readFileViaShell(fname, true);
+ }
+ }
+ return line;
+ }
+
+ public static boolean fileExists(String fname) {
+ return new File(fname).exists();
+ }
+
+ /**
+ * Read file via shell
+ *
+ * @param filePath
+ * @param useSu
+ * @return file output
+ */
+ public static String readFileViaShell(String filePath, boolean useSu) {
+ CMDProcessor2.CommandResult cr = null;
+ if (useSu) {
+ cr = new CMDProcessor2().su.runWaitFor("cat " + filePath);
+ } else {
+ cr = new CMDProcessor2().sh.runWaitFor("cat " + filePath);
+ }
+ if (cr.success())
+ return cr.stdout;
+ return null;
+ }
+
+ /**
+ * Write one line to a file
+ *
+ * @param fname
+ * @param value
+ * @return if line was written
+ */
+ public static boolean writeOneLine(String fname, String value) {
+ if (!new File(fname).exists()) {
+ return false;
+ }
+ try {
+ FileWriter fw = new FileWriter(fname);
+ try {
+ fw.write(value);
+ } finally {
+ fw.close();
+ }
+ } catch (IOException e) {
+ String Error = "Error writing to " + fname + ". Exception: ";
+ Log.e(TAG, Error, e);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Gets available schedulers from file
+ *
+ * @return available schedulers
+ */
+ public static String[] getAvailableIOSchedulers() {
+ String[] schedulers = null;
+ String[] aux = readStringArray(IO_SCHEDULER_PATH[0]);
+ if (aux != null) {
+ schedulers = new String[aux.length];
+ for (int i = 0; i < aux.length; i++) {
+ if (aux[i].charAt(0) == '[') {
+ schedulers[i] = aux[i].substring(1, aux[i].length() - 1);
+ } else {
+ schedulers[i] = aux[i];
+ }
+ }
+ }
+ return schedulers;
+ }
+
+ /**
+ * Reads string array from file
+ *
+ * @param fname
+ * @return string array
+ */
+ private static String[] readStringArray(String fname) {
+ String line = readOneLine(fname);
+ if (line != null) {
+ return line.split(" ");
+ }
+ return null;
+ }
+
+ /**
+ * Get current IO Scheduler
+ *
+ * @return current io scheduler
+ */
+ public static String getIOScheduler() {
+ String scheduler = null;
+ String[] schedulers = readStringArray(IO_SCHEDULER_PATH[0]);
+ if (schedulers != null) {
+ for (String s : schedulers) {
+ if (s.charAt(0) == '[') {
+ scheduler = s.substring(1, s.length() - 1);
+ break;
+ }
+ }
+ }
+ return scheduler;
+ }
+
+ /*
+ * @return available performance scheduler
+ */
+ public static Boolean GovernorExist(String gov) {
+ return readOneLine(GOVERNORS_LIST_PATH).contains(gov);
+ }
+
+ /**
+ * Get total number of cpus
+ *
+ * @return total number of cpus
+ */
+ public static int getNumOfCpus() {
+ int numOfCpu = 1;
+ String numOfCpus = Helpers2.readOneLine(NUM_OF_CPUS_PATH);
+ String[] cpuCount = numOfCpus.split("-");
+ if (cpuCount.length > 1) {
+ try {
+ int cpuStart = Integer.parseInt(cpuCount[0]);
+ int cpuEnd = Integer.parseInt(cpuCount[1]);
+
+ numOfCpu = cpuEnd - cpuStart + 1;
+
+ if (numOfCpu < 0)
+ numOfCpu = 1;
+ } catch (NumberFormatException ex) {
+ numOfCpu = 1;
+ }
+ }
+ return numOfCpu;
+ }
+
+ /**
+ * Check if any voltage control tables exist and set the voltage path if a
+ * file is found.
+ *
+ * If false is returned, there was no tables found and none will be used.
+ *
+ * @return true/false if uv table exists
+ */
+ public static boolean voltageFileExists() {
+ if (new File(UV_MV_PATH).exists()) {
+ setVoltagePath(UV_MV_PATH);
+ return true;
+ } else if (new File(VDD_PATH).exists()) {
+ setVoltagePath(VDD_PATH);
+ return true;
+ } else if (new File(VDD_SYSFS_PATH).exists()) {
+ setVoltagePath(VDD_SYSFS_PATH);
+ return true;
+ } else if (new File(COMMON_VDD_PATH).exists()) {
+ setVoltagePath(COMMON_VDD_PATH);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sets the voltage file to be used by the rest of the app elsewhere.
+ *
+ * @param voltageFile
+ */
+ public static void setVoltagePath(String voltageFile) {
+ Log.d(TAG, "UV table path detected: " + voltageFile);
+ mVoltagePath = voltageFile;
+ }
+
+ /**
+ * Gets the currently set voltage path
+ *
+ * @return voltage path
+ */
+ public static String getVoltagePath() {
+ return mVoltagePath;
+ }
+
+ /**
+ * Convert to MHz and append a tag
+ *
+ * @param mhzString
+ * @return tagged and converted String
+ */
+ public static String toMHz(String mhzString) {
+ return String.valueOf(Integer.parseInt(mhzString) / 1000) + " MHz";
+ }
+
+ /**
+ * Restart the activity smoothly
+ *
+ * @param activity
+ */
+ public static void restartPC(final Activity activity) {
+ if (activity == null)
+ return;
+ final int enter_anim = android.R.anim.fade_in;
+ final int exit_anim = android.R.anim.fade_out;
+ activity.overridePendingTransition(enter_anim, exit_anim);
+ activity.finish();
+ activity.overridePendingTransition(enter_anim, exit_anim);
+ activity.startActivity(activity.getIntent());
+ }
+
+ /**
+ * Helper to update the app widget
+ *
+ * @param context
+ * @note OMNI: The widget has been disabled
+ */
+ public static void updateAppWidget(Context context) {
+/*
+ AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
+ ComponentName widgetComponent = new ComponentName(context, PCWidget.class);
+ int[] widgetIds = widgetManager.getAppWidgetIds(widgetComponent);
+ Intent update = new Intent();
+ update.setAction("com.brewcrewfoo.performance.ACTION_FREQS_CHANGED");
+ update.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds);
+ context.sendBroadcast(update);
+*/
+ }
+
+ /**
+ * Helper to create a bitmap to set as imageview or bg
+ *
+ * @param bgcolor
+ * @return bitmap
+ */
+ public static Bitmap getBackground(int bgcolor) {
+ try {
+ Bitmap.Config config = Bitmap.Config.ARGB_8888;
+ Bitmap bitmap = Bitmap.createBitmap(2, 2, config);
+ Canvas canvas = new Canvas(bitmap);
+ canvas.drawColor(bgcolor);
+ return bitmap;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public static String binExist(String b) {
+ CMDProcessor2.CommandResult cr = null;
+ cr = new CMDProcessor2().sh.runWaitFor("busybox which " + b);
+ if (cr.success()) {
+ return cr.stdout;
+ } else {
+ return NOT_FOUND;
+ }
+ }
+
+ public static String getCachePartition() {
+ CMDProcessor2.CommandResult cr = null;
+ cr = new CMDProcessor2().sh.runWaitFor("busybox echo `busybox mount | busybox grep cache | busybox cut -d' ' -f1`");
+ if (cr.success() && !cr.stdout.equals("")) {
+ return cr.stdout;
+ } else {
+ return NOT_FOUND;
+ }
+ }
+
+ public static long getTotMem() {
+ long v = 0;
+ CMDProcessor2.CommandResult cr = new CMDProcessor2().sh.runWaitFor("busybox echo `busybox grep MemTot /proc/meminfo | busybox grep -E --only-matching '[[:digit:]]+'`");
+ if (cr.success()) {
+ try {
+ v = (long) Integer.parseInt(cr.stdout) * 1024;
+ } catch (NumberFormatException e) {
+ Log.d(TAG, "MemTot conversion err: " + e);
+ }
+ }
+ return v;
+ }
+
+ public static boolean showBattery() {
+ return (new File(BLX_PATH).exists() || (fastcharge_path() != null) || new File(BAT_VOLT_PATH).exists());
+ }
+
+ public static String shExec(StringBuilder s, Context c, Boolean su) {
+ get_assetsScript("run", c, s.toString(), "");
+ if (isSystemApp(c)) {
+ new CMDProcessor2().sh.runWaitFor("busybox chmod 750 " + c.getFilesDir() + "/run");
+ } else {
+ new CMDProcessor2().su.runWaitFor("busybox chmod 750 " + c.getFilesDir() + "/run");
+ }
+ CMDProcessor2.CommandResult cr = null;
+ if (su && !isSystemApp(c))
+ cr = new CMDProcessor2().su.runWaitFor(c.getFilesDir() + "/run");
+ else
+ cr = new CMDProcessor2().sh.runWaitFor(c.getFilesDir() + "/run");
+ if (cr.success()) {
+ return cr.stdout;
+ } else {
+ Log.d(TAG, "execute: " + cr.stderr);
+ return null;
+ }
+ }
+
+ public static void get_assetsScript(String fn, Context c, String prefix, String postfix) {
+ byte[] buffer;
+ final AssetManager assetManager = c.getAssets();
+ try {
+ InputStream f = assetManager.open(fn);
+ buffer = new byte[f.available()];
+ f.read(buffer);
+ f.close();
+ final String s = new String(buffer);
+ final StringBuilder sb = new StringBuilder(s);
+ if (!postfix.equals("")) {
+ sb.append("\n\n").append(postfix);
+ }
+ if (!prefix.equals("")) {
+ sb.insert(0, prefix + "\n");
+ }
+ sb.insert(0, "#!" + Helpers2.binExist("sh") + "\n\n");
+ try {
+ FileOutputStream fos;
+ fos = c.openFileOutput(fn, Context.MODE_PRIVATE);
+ fos.write(sb.toString().getBytes());
+ fos.close();
+
+ } catch (IOException e) {
+ Log.d(TAG, "error write " + fn + " file");
+ e.printStackTrace();
+ }
+
+ } catch (IOException e) {
+ Log.d(TAG, "error read " + fn + " file");
+ e.printStackTrace();
+ }
+ }
+
+ public static void get_assetsBinary(String fn, Context c) {
+ byte[] buffer;
+ final AssetManager assetManager = c.getAssets();
+ try {
+ InputStream f = assetManager.open(fn);
+ buffer = new byte[f.available()];
+ f.read(buffer);
+ f.close();
+ try {
+ FileOutputStream fos;
+ fos = c.openFileOutput(fn, Context.MODE_PRIVATE);
+ fos.write(buffer);
+ fos.close();
+
+ } catch (IOException e) {
+ Log.d(TAG, "error write " + fn + " file");
+ e.printStackTrace();
+ }
+
+ } catch (IOException e) {
+ Log.d(TAG, "error read " + fn + " file");
+ e.printStackTrace();
+ }
+ }
+
+ public static String ReadableByteCount(long bytes) {
+ if (bytes < 1024) return bytes + " B";
+ int exp = (int) (Math.log(bytes) / Math.log(1024));
+ String pre = String.valueOf("KMGTPE".charAt(exp - 1));
+ return String.format("%.1f %sB", bytes / Math.pow(1024, exp), pre);
+ }
+
+ public static void removeCurItem(MenuItem item, int idx, ViewPager vp) {
+ for (int i = 0; i < vp.getAdapter().getCount(); i++) {
+ if (item.getItemId() == idx + i + 1) {
+ vp.setCurrentItem(i);
+ }
+ }
+ }
+
+ public static void addItems2Menu(Menu menu, int idx, String nume, ViewPager vp) {
+ final SubMenu smenu = menu.addSubMenu(0, idx, 0, nume);
+ for (int i = 0; i < vp.getAdapter().getCount(); i++) {
+ if (i != vp.getCurrentItem())
+ smenu.add(0, idx + i + 1, 0, vp.getAdapter().getPageTitle(i));
+ }
+ }
+
+ public static String bln_path() {
+ if (new File("/sys/class/misc/backlightnotification/enabled").exists()) {
+ return "/sys/class/misc/backlightnotification/enabled";
+ } else if (new File("/sys/class/leds/button-backlight/blink_buttons").exists()) {
+ return "/sys/class/leds/button-backlight/blink_buttons";
+ } else {
+ return null;
+ }
+ }
+
+ public static String fastcharge_path() {
+ if (new File("/sys/kernel/fast_charge/force_fast_charge").exists()) {
+ return "/sys/kernel/fast_charge/force_fast_charge";
+ } else if (new File("/sys/module/msm_otg/parameters/fast_charge").exists()) {
+ return "/sys/module/msm_otg/parameters/fast_charge";
+ } else if (new File("/sys/devices/platform/htc_battery/fast_charge").exists()) {
+ return "/sys/devices/platform/htc_battery/fast_charge";
+ } else {
+ return null;
+ }
+ }
+
+ public static String fsync_path() {
+ if (new File("/sys/class/misc/fsynccontrol/fsync_enabled").exists()) {
+ return "/sys/class/misc/fsynccontrol/fsync_enabled";
+ } else if (new File("/sys/module/sync/parameters/fsync_enabled").exists()) {
+ return "/sys/module/sync/parameters/fsync_enabled";
+ } else {
+ return null;
+ }
+ }
+
+ public static boolean isSystemApp(Context c) {
+ boolean mIsSystemApp;
+ return mIsSystemApp = c.getResources().getBoolean(R.bool.config_isSystemApp);
+ }
+}
diff --git a/src/com/android/settings/util/ShortcutPickerHelper.java b/src/com/android/settings/util/ShortcutPickerHelper.java
new file mode 100644
index 00000000000..6d848061690
--- /dev/null
+++ b/src/com/android/settings/util/ShortcutPickerHelper.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2011 The CyanogenMod 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.util;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.Intent;
+import android.content.Intent.ShortcutIconResource;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.Log;
+
+import com.android.settings.R;
+public class ShortcutPickerHelper {
+
+ private Fragment mParent;
+ private OnPickListener mListener;
+
+ public static final int REQUEST_PICK_SHORTCUT = 100;
+ public static final int REQUEST_PICK_APPLICATION = 101;
+ public static final int REQUEST_CREATE_SHORTCUT = 102;
+
+ public interface OnPickListener {
+ /**
+ * Callback after a shortcut is picked
+ *
+ * @param uri Intent for the shortcut
+ * @param friendlyName Title
+ * @param icon Icon for the shortcut, or null
+ * @param isApplication true for standard app, false for "shortcut"
+ */
+ void shortcutPicked(String uri, String friendlyName, Bitmap icon, boolean isApplication);
+ }
+
+ public ShortcutPickerHelper(Fragment parent, OnPickListener listener) {
+ mParent = parent;
+ mListener = listener;
+ }
+
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode == Activity.RESULT_OK) {
+ switch (requestCode) {
+ case REQUEST_PICK_APPLICATION:
+ completeSetCustomApp(data);
+ break;
+ case REQUEST_CREATE_SHORTCUT:
+ completeSetCustomShortcut(data);
+ break;
+ case REQUEST_PICK_SHORTCUT:
+ processShortcut(data, REQUEST_PICK_APPLICATION, REQUEST_CREATE_SHORTCUT);
+ break;
+ }
+ }
+ }
+
+ public void pickShortcut() {
+ Bundle bundle = new Bundle();
+
+ ArrayList shortcutNames = new ArrayList();
+ shortcutNames.add(mParent.getString(R.string.group_applications));
+ bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
+
+ ArrayList shortcutIcons = new ArrayList();
+ shortcutIcons.add(ShortcutIconResource.fromContext(mParent.getActivity(),
+ R.drawable.ic_launcher));
+ bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
+
+ Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
+ pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(Intent.ACTION_CREATE_SHORTCUT));
+ pickIntent.putExtra(Intent.EXTRA_TITLE, mParent.getText(R.string.select_custom_app_title));
+ pickIntent.putExtras(bundle);
+
+ mParent.startActivityForResult(pickIntent, REQUEST_PICK_SHORTCUT);
+ }
+
+ private void processShortcut(Intent intent, int requestCodeApplication, int requestCodeShortcut) {
+ // Handle case where user selected "Applications"
+ String applicationName = mParent.getResources().getString(R.string.group_applications);
+ String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+
+ if (applicationName != null && applicationName.equals(shortcutName)) {
+ Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+ mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+
+ Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
+ pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
+ mParent.startActivityForResult(pickIntent, requestCodeApplication);
+ } else {
+ mParent.startActivityForResult(intent, requestCodeShortcut);
+ }
+ }
+
+ private void completeSetCustomApp(Intent data) {
+ mListener.shortcutPicked(data.toUri(0), getFriendlyActivityName(data, false), null, true);
+ }
+
+ private void completeSetCustomShortcut(Intent data) {
+ Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
+ /* preserve shortcut name, we want to restore it later */
+ intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME));
+ String appUri = intent.toUri(0);
+ appUri = appUri.replaceAll("com.android.contacts.action.QUICK_CONTACT",
+ "android.intent.action.VIEW");
+ /* Try to get the icon (if any) */
+ Bitmap bmp = null;
+ Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
+ if (extra != null && extra instanceof Bitmap)
+ bmp = (Bitmap) extra;
+ if (bmp == null) {
+ extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
+ if (extra != null && extra instanceof Intent.ShortcutIconResource) {
+ try {
+ Intent.ShortcutIconResource iconResource = (ShortcutIconResource) extra;
+ final PackageManager packageManager = mParent.getActivity().getPackageManager();
+ Resources resources = packageManager.getResourcesForApplication(iconResource.packageName);
+ final int id = resources.getIdentifier(iconResource.resourceName, null, null);
+ bmp = BitmapFactory.decodeResource(resources, id);
+ } catch (Exception e) {
+ Log.w("ROMControl.ShortcutPicker", "Could not load shortcut icon: " + extra);
+ }
+ }
+ }
+ mListener.shortcutPicked(appUri, getFriendlyShortcutName(intent), bmp, false);
+ }
+
+ private String getFriendlyActivityName(Intent intent, boolean labelOnly) {
+ PackageManager pm = mParent.getActivity().getPackageManager();
+ ActivityInfo ai = intent.resolveActivityInfo(pm, PackageManager.GET_ACTIVITIES);
+ String friendlyName = null;
+
+ if (ai != null) {
+ friendlyName = ai.loadLabel(pm).toString();
+ if (friendlyName == null && !labelOnly) {
+ friendlyName = ai.name;
+ }
+ }
+
+ return friendlyName != null || labelOnly ? friendlyName : intent.toUri(0);
+ }
+
+ private String getFriendlyShortcutName(Intent intent) {
+ String activityName = getFriendlyActivityName(intent, true);
+ String name = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+
+ if (activityName != null && name != null) {
+ return activityName + ": " + name;
+ }
+ return name != null ? name : intent.toUri(0);
+ }
+
+ public String getFriendlyNameForUri(String uri) {
+ if (uri == null) {
+ return null;
+ }
+
+ try {
+ Intent intent = Intent.parseUri(uri, 0);
+ if (Intent.ACTION_MAIN.equals(intent.getAction())) {
+ return getFriendlyActivityName(intent, false);
+ }
+ return getFriendlyShortcutName(intent);
+ } catch (URISyntaxException e) {
+ }
+
+ return uri;
+ }
+}
diff --git a/src/com/android/settings/widget/ChartDataUsageView.java b/src/com/android/settings/widget/ChartDataUsageView.java
index 19de100b1b7..4e16bfc9f8d 100644
--- a/src/com/android/settings/widget/ChartDataUsageView.java
+++ b/src/com/android/settings/widget/ChartDataUsageView.java
@@ -34,12 +34,12 @@
import android.view.MotionEvent;
import android.view.View;
-import com.android.internal.util.Objects;
import com.android.settings.R;
import com.android.settings.widget.ChartSweepView.OnSweepListener;
import java.util.Arrays;
import java.util.Calendar;
+import java.util.Objects;
/**
* Specific {@link ChartView} that displays {@link ChartNetworkSeriesView} along
@@ -466,7 +466,7 @@ public TimeAxis() {
@Override
public int hashCode() {
- return Objects.hashCode(mMin, mMax, mSize);
+ return Objects.hash(mMin, mMax, mSize);
}
@Override
@@ -548,7 +548,7 @@ public static class DataAxis implements ChartAxis {
@Override
public int hashCode() {
- return Objects.hashCode(mMin, mMax, mSize);
+ return Objects.hash(mMin, mMax, mSize);
}
@Override
diff --git a/src/com/android/settings/widget/CubicSplinePreviewView.java b/src/com/android/settings/widget/CubicSplinePreviewView.java
new file mode 100644
index 00000000000..36b8388e748
--- /dev/null
+++ b/src/com/android/settings/widget/CubicSplinePreviewView.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod 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.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Spline;
+import android.view.SurfaceView;
+import android.view.View;
+
+import com.android.settings.R;
+
+public class CubicSplinePreviewView extends SurfaceView {
+ private static final String TAG = "CubicSplinePreviewView";
+ private static final boolean DEBUG = false;
+
+ private float[] mXPoints;
+ private float[] mYPoints;
+ private Spline mSpline;
+
+ private static final int POINTS = 100;
+
+ private final Paint mFgPaint, mGridLinePaint;
+ private final Paint mXTextPaint, mYTextPaint;
+ private final Paint mPointPaint;
+ private final int mBgColor;
+ private final float mMarkerRadius;
+ private final int mMargin;
+
+ public CubicSplinePreviewView(Context context) {
+ this(context, null);
+ }
+
+ public CubicSplinePreviewView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CubicSplinePreviewView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.CubicSplinePreviewView, defStyle, 0);
+
+ int fgColor = a.getColor(R.styleable.CubicSplinePreviewView_foregroundColor, Color.WHITE);
+ int markerColor = a.getColor(R.styleable.CubicSplinePreviewView_markerColor, 0x22ffffff);
+ int gridColor = a.getColor(R.styleable.CubicSplinePreviewView_gridColor, Color.WHITE);
+ mBgColor = a.getColor(R.styleable.CubicSplinePreviewView_backgroundColor, Color.BLACK);
+
+ float textSize = a.getDimensionPixelSize(R.styleable.CubicSplinePreviewView_textSize, 0);
+ float strokeWidth = a.getDimensionPixelSize(R.styleable.CubicSplinePreviewView_strokeWidth, 0);
+ mMarkerRadius = a.getDimensionPixelSize(R.styleable.CubicSplinePreviewView_markerSize, 1);
+ mMargin = a.getDimensionPixelSize(R.styleable.CubicSplinePreviewView_margin, 0);
+
+ a.recycle();
+
+ mFgPaint = new Paint();
+ mFgPaint.setColor(fgColor);
+ mFgPaint.setStyle(Style.STROKE);
+ mFgPaint.setStrokeWidth(strokeWidth);
+ mFgPaint.setTextSize(textSize);
+ mFgPaint.setAntiAlias(true);
+
+ mGridLinePaint = new Paint();
+ mGridLinePaint.setColor(gridColor);
+ mGridLinePaint.setStyle(Style.STROKE);
+
+ mXTextPaint = new Paint(mFgPaint);
+ mXTextPaint.setTextAlign(Align.CENTER);
+ mXTextPaint.setStrokeWidth(0);
+ mXTextPaint.setShadowLayer(2, 0, 0, 0xff000000);
+
+ mYTextPaint = new Paint(mXTextPaint);
+ mYTextPaint.setTextAlign(Align.LEFT);
+
+ mPointPaint = new Paint();
+ mPointPaint.setStyle(Style.FILL);
+ mPointPaint.setColor(markerColor);
+ mPointPaint.setAntiAlias(true);
+
+ setWillNotDraw(false);
+ }
+
+ /**
+ * Sets the spline control points.
+ *
+ * @param xPoints Array of X coordinates of control points
+ * @param yPoints Array of Y coordinates of control points
+ *
+ * There are some assumptions made about those arrays:
+ * - xPoints and yPoints must be of equal length
+ * - The value range of yPoints is 0..1
+ */
+ public void setSpline(float[] xPoints, float[] yPoints) {
+ mXPoints = xPoints;
+ mYPoints = yPoints;
+ if (DEBUG) {
+ for (int i = 0; i < xPoints.length; i++) {
+ Log.d(TAG, "Spline data[" + i + "]: x = " + xPoints[i] + " y = " + yPoints[i]);
+ }
+ }
+ mSpline = Spline.createMonotoneCubicSpline(xPoints, yPoints);
+ postInvalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ /* clear canvas */
+ canvas.drawRGB(Color.red(mBgColor), Color.green(mBgColor), Color.blue(mBgColor));
+
+ if (mSpline == null) {
+ return;
+ }
+
+ Path curve = new Path();
+
+ int width = getWidth() - 2 * mMargin;
+ int height = getHeight() - 2 * mMargin;
+ double dist = (double) width / (POINTS - 1);
+
+ for (int i = 0; i < POINTS; i++) {
+ double xPixel = dist * i;
+ float x = (float) reverseProjectX(xPixel / width);
+ float y = mSpline.interpolate(x);
+ float yPixel = (float) ((1.0 - projectY(y)) * height);
+
+ xPixel += mMargin;
+ yPixel += mMargin;
+
+ if (DEBUG) {
+ Log.d(TAG, "point[" + i + "]: X = (" + x + "," + xPixel + "), Y = (" + y + "," + yPixel + ")");
+ }
+
+ if (i == 0) {
+ curve.moveTo((float) xPixel, yPixel);
+ } else {
+ curve.lineTo((float) xPixel, yPixel);
+ }
+ }
+
+ canvas.drawPath(curve, mFgPaint);
+
+ /* draw vertical lines */
+ float minX = getMinX();
+ float maxX = getMaxX();
+ float minY = getMinY();
+ float maxY = getMaxY();
+
+ for (float xPos = minX; xPos <= maxX; ) {
+ float x = (float) (projectX(xPos) * width + mMargin);
+ canvas.drawLine(x, mMargin, x, mMargin + height, mGridLinePaint);
+ if (xPos < 10) {
+ xPos += 1;
+ } else if (xPos < 100) {
+ xPos += 10;
+ } else if (xPos < 1000) {
+ xPos += 100;
+ } else if (xPos < 10000) {
+ xPos += 1000;
+ } else {
+ xPos += 10000;
+ }
+ }
+
+ /* draw horizontal lines */
+ canvas.drawLine(mMargin, mMargin + height, mMargin + width, mMargin + height, mGridLinePaint);
+ float yDist = (maxY - minY) / 10;
+ for (int i = 1; i <= 10; i++) {
+ float y = (float) ((1.0 - projectY(yDist * i + minY)) * height + mMargin);
+ canvas.drawLine(mMargin, y, mMargin + width, y, mGridLinePaint);
+ canvas.drawText(String.format("%.0f%%", yDist * i * 100), mMargin + 1,
+ y + mYTextPaint.getTextSize(), mYTextPaint);
+ }
+
+ for (int i = 0; i < mXPoints.length; i ++) {
+ /* take special care of the first control point that's likely 0 */
+ float x = (i == 0) ? getMinX() : mXPoints[i];
+ float y = (x != mXPoints[i]) ? mSpline.interpolate(x) : mYPoints[i];
+ float xPixel = (float) (projectX(x) * width + mMargin);
+ float yPixel = (float) ((1.0 - projectY(y)) * height + mMargin);
+
+ if (DEBUG) {
+ Log.d(TAG, "Print control point " + x + " at (" + xPixel + "," + (height - 2) + ")");
+ }
+
+ if (i == 0) {
+ mXTextPaint.setTextAlign(Align.LEFT);
+ } else if (i == (mXPoints.length - 1)) {
+ mXTextPaint.setTextAlign(Align.RIGHT);
+ } else {
+ mXTextPaint.setTextAlign(Align.CENTER);
+ }
+ canvas.drawCircle(xPixel, yPixel, mMarkerRadius, mPointPaint);
+ canvas.drawText(String.format("%.0f", mXPoints[i]), xPixel, mMargin + height - 2, mXTextPaint);
+ }
+ }
+
+ private double projectX(double value) {
+ double pos = Math.log(value);
+ double minPos = Math.log(getMinX());
+ double maxPos = Math.log(getMaxX());
+ return (pos - minPos) / (maxPos - minPos);
+ }
+
+ private double reverseProjectX(double pos) {
+ double minPos = Math.log(getMinX());
+ double maxPos = Math.log(getMaxX());
+ return Math.exp(pos * (maxPos - minPos) + minPos);
+ }
+
+ private double projectY(double value) {
+ double min = getMinY();
+ double max = getMaxY();
+ return (value - min) / (max - min);
+ }
+
+ private float getMinX() {
+ return Math.max(mXPoints[0], 1);
+ }
+
+ private float getMaxX() {
+ return mXPoints[mXPoints.length - 1];
+ }
+
+ private float getMinY() {
+ return Math.min(mYPoints[0], 0);
+ }
+
+ private float getMaxY() {
+ return Math.max(mYPoints[mYPoints.length - 1], 1);
+ }
+}
diff --git a/src/com/android/settings/wifi/AccessPoint.java b/src/com/android/settings/wifi/AccessPoint.java
index c4d1f7c65fd..555147a1775 100644
--- a/src/com/android/settings/wifi/AccessPoint.java
+++ b/src/com/android/settings/wifi/AccessPoint.java
@@ -62,6 +62,8 @@ enum PskType {
int security;
int networkId;
boolean wpsAvailable = false;
+ boolean isIBSS = false;
+ int frequency;
PskType pskType = PskType.UNKNOWN;
@@ -188,6 +190,8 @@ private void loadConfig(WifiConfiguration config) {
security = getSecurity(config);
networkId = config.networkId;
mRssi = Integer.MAX_VALUE;
+ isIBSS = config.isIBSS;
+ frequency = config.frequency;
mConfig = config;
}
@@ -196,6 +200,8 @@ private void loadResult(ScanResult result) {
bssid = result.BSSID;
security = getSecurity(result);
wpsAvailable = security != SECURITY_EAP && result.capabilities.contains("WPS");
+ isIBSS = result.capabilities.contains("[IBSS]");
+ frequency = result.frequency;
if (security == SECURITY_PSK)
pskType = getPskType(result);
networkId = -1;
@@ -339,24 +345,31 @@ private void refresh() {
setTitle(ssid);
Context context = getContext();
+ StringBuilder summary = new StringBuilder();
+
+ if (isIBSS)
+ summary.append(context.getString(R.string.wifi_mode_ibss_short)).append(" ");
+
if (mConfig != null && mConfig.status == WifiConfiguration.Status.DISABLED) {
switch (mConfig.disableReason) {
case WifiConfiguration.DISABLED_AUTH_FAILURE:
- setSummary(context.getString(R.string.wifi_disabled_password_failure));
+ summary.append(context.getString(R.string.wifi_disabled_password_failure));
break;
case WifiConfiguration.DISABLED_DHCP_FAILURE:
case WifiConfiguration.DISABLED_DNS_FAILURE:
- setSummary(context.getString(R.string.wifi_disabled_network_failure));
+ summary.append(context.getString(R.string.wifi_disabled_network_failure));
+ break;
+ case WifiConfiguration.DISABLED_ASSOCIATION_REJECT:
+ summary.append(context.getString(R.string.wifi_disabled_association_rejected));
break;
case WifiConfiguration.DISABLED_UNKNOWN_REASON:
- setSummary(context.getString(R.string.wifi_disabled_generic));
+ summary.append(context.getString(R.string.wifi_disabled_generic));
}
} else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
- setSummary(context.getString(R.string.wifi_not_in_range));
+ summary.append(context.getString(R.string.wifi_not_in_range));
} else if (mState != null) { // This is the active connection
- setSummary(Summary.get(context, mState));
+ summary.append(Summary.get(context, mState));
} else { // In range, not disabled.
- StringBuilder summary = new StringBuilder();
if (mConfig != null) { // Is saved network
summary.append(context.getString(R.string.wifi_remembered));
}
@@ -378,8 +391,8 @@ private void refresh() {
summary.append(context.getString(R.string.wifi_wps_available_second_item));
}
}
- setSummary(summary.toString());
}
+ setSummary(summary.toString());
}
/**
diff --git a/src/com/android/settings/wifi/AdvancedWifiSettings.java b/src/com/android/settings/wifi/AdvancedWifiSettings.java
index f2e8a071489..143204a90d9 100644
--- a/src/com/android/settings/wifi/AdvancedWifiSettings.java
+++ b/src/com/android/settings/wifi/AdvancedWifiSettings.java
@@ -44,26 +44,29 @@ public class AdvancedWifiSettings extends SettingsPreferenceFragment
private static final String KEY_MAC_ADDRESS = "mac_address";
private static final String KEY_CURRENT_IP_ADDRESS = "current_ip_address";
private static final String KEY_FREQUENCY_BAND = "frequency_band";
- private static final String KEY_COUNTRY_CODE = "wifi_countrycode";
private static final String KEY_NOTIFY_OPEN_NETWORKS = "notify_open_networks";
private static final String KEY_SLEEP_POLICY = "sleep_policy";
private static final String KEY_POOR_NETWORK_DETECTION = "wifi_poor_network_detection";
private static final String KEY_SCAN_ALWAYS_AVAILABLE = "wifi_scan_always_available";
private static final String KEY_INSTALL_CREDENTIALS = "install_credentials";
private static final String KEY_SUSPEND_OPTIMIZATIONS = "suspend_optimizations";
+ private static final String KEY_COUNTRY_CODE = "wifi_countrycode";
private WifiManager mWifiManager;
+ private ListPreference mCcodePref;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.wifi_advanced_settings);
- }
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+
+ mCcodePref = (ListPreference) findPreference(KEY_COUNTRY_CODE);
+ mCcodePref.setOnPreferenceChangeListener(this);
+
+ updateWifiCodeSummary();
}
@Override
@@ -128,17 +131,6 @@ private void initPreferences() {
}
}
- ListPreference ccodePref = (ListPreference) findPreference(KEY_COUNTRY_CODE);
- if (ccodePref != null) {
- ccodePref.setOnPreferenceChangeListener(this);
- String value = mWifiManager.getCountryCode();
- if (value != null) {
- ccodePref.setValue(value);
- } else {
- Log.e(TAG, "Failed to fetch country code");
- }
- }
-
ListPreference sleepPolicyPref = (ListPreference) findPreference(KEY_SLEEP_POLICY);
if (sleepPolicyPref != null) {
if (Utils.isWifiOnly(getActivity())) {
@@ -209,23 +201,29 @@ public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference prefere
public boolean onPreferenceChange(Preference preference, Object newValue) {
String key = preference.getKey();
- if (KEY_FREQUENCY_BAND.equals(key)) {
+ if (KEY_COUNTRY_CODE.equals(key)) {
try {
- int value = Integer.parseInt((String) newValue);
- mWifiManager.setFrequencyBand(value, true);
- updateFrequencyBandSummary(preference, value);
- } catch (NumberFormatException e) {
- Toast.makeText(getActivity(), R.string.wifi_setting_frequency_band_error,
+ Settings.Global.putString(getContentResolver(),
+ Settings.Global.WIFI_COUNTRY_CODE_USER,
+ (String) newValue);
+ mWifiManager.setCountryCode((String) newValue, true);
+ int index = mCcodePref.findIndexOfValue((String) newValue);
+ mCcodePref.setSummary(mCcodePref.getEntries()[index]);
+ return true;
+ } catch (IllegalArgumentException e) {
+ Toast.makeText(getActivity(), R.string.wifi_setting_countrycode_error,
Toast.LENGTH_SHORT).show();
return false;
}
}
- if (KEY_COUNTRY_CODE.equals(key)) {
+ if (KEY_FREQUENCY_BAND.equals(key)) {
try {
- mWifiManager.setCountryCode((String) newValue, true);
- } catch (IllegalArgumentException e) {
- Toast.makeText(getActivity(), R.string.wifi_setting_countrycode_error,
+ int value = Integer.parseInt((String) newValue);
+ mWifiManager.setFrequencyBand(value, true);
+ updateFrequencyBandSummary(preference, value);
+ } catch (NumberFormatException e) {
+ Toast.makeText(getActivity(), R.string.wifi_setting_frequency_band_error,
Toast.LENGTH_SHORT).show();
return false;
}
@@ -261,4 +259,21 @@ private void refreshWifiInfo() {
getActivity().getString(R.string.status_unavailable) : ipAddress);
}
+ private void updateWifiCodeSummary() {
+ if (mCcodePref != null) {
+ String value = (mWifiManager.getCountryCode()).toUpperCase();
+ if (value != null) {
+ mCcodePref.setValue(value);
+ mCcodePref.setSummary(mCcodePref.getEntry());
+ } else {
+ Log.e(TAG, "Failed to fetch country code");
+ }
+ if (mWifiManager.isWifiEnabled()) {
+ mCcodePref.setEnabled(true);
+ } else {
+ mCcodePref.setEnabled(false);
+ mCcodePref.setSummary(R.string.wifi_setting_countrycode_disabled);
+ }
+ }
+ }
}
diff --git a/src/com/android/settings/wifi/WifiApDialog.java b/src/com/android/settings/wifi/WifiApDialog.java
index 211e85db857..7c9d74fb02e 100644
--- a/src/com/android/settings/wifi/WifiApDialog.java
+++ b/src/com/android/settings/wifi/WifiApDialog.java
@@ -32,6 +32,7 @@
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
+import android.widget.Toast;
import com.android.settings.R;
@@ -50,6 +51,8 @@ public class WifiApDialog extends AlertDialog implements View.OnClickListener,
public static final int WPA_INDEX = 1;
public static final int WPA2_INDEX = 2;
+ private static final int WIFI_SSID_MAX_LENGTH_BYTES = 32;
+
private View mView;
private TextView mSsid;
private int mSecurityTypeIndex = OPEN_INDEX;
@@ -164,6 +167,18 @@ private void validate() {
}
}
+ // If the ssid size is beyond 32 bytes, limit the input.
+ private void LimitSsidLength(Editable editable) {
+ int editEnd = mSsid.getSelectionEnd();
+ int strlength = mSsid.getText().toString().getBytes().length;
+
+ if (strlength > WIFI_SSID_MAX_LENGTH_BYTES) {
+ editable.delete(editEnd - 1, editEnd);
+ Toast.makeText(getContext(), R.string.wifi_ssid_input_limit,
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+
public void onClick(View view) {
mPassword.setInputType(
InputType.TYPE_CLASS_TEXT | (((CheckBox) view).isChecked() ?
@@ -179,6 +194,10 @@ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
public void afterTextChanged(Editable editable) {
validate();
+
+ if (mSsid.getEditableText() == editable) {
+ LimitSsidLength(editable);
+ }
}
@Override
diff --git a/src/com/android/settings/wifi/WifiApEnabler.java b/src/com/android/settings/wifi/WifiApEnabler.java
index 9a3b49d8ff3..0b13f7a3889 100644
--- a/src/com/android/settings/wifi/WifiApEnabler.java
+++ b/src/com/android/settings/wifi/WifiApEnabler.java
@@ -49,6 +49,8 @@ public class WifiApEnabler {
ConnectivityManager mCm;
private String[] mWifiRegexs;
+ /* Indicates if we have to wait for WIFI_STATE_CHANGED intent */
+ private boolean mWaitForWifiStateChange;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -57,6 +59,11 @@ public void onReceive(Context context, Intent intent) {
if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(action)) {
handleWifiApStateChanged(intent.getIntExtra(
WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED));
+ } else if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
+ if (mWaitForWifiStateChange == true) {
+ handleWifiStateChanged(intent.getIntExtra(
+ WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN));
+ }
} else if (ConnectivityManager.ACTION_TETHER_STATE_CHANGED.equals(action)) {
ArrayList available = intent.getStringArrayListExtra(
ConnectivityManager.EXTRA_AVAILABLE_TETHER);
@@ -77,6 +84,7 @@ public WifiApEnabler(Context context, CheckBoxPreference checkBox) {
mCheckBox = checkBox;
mOriginalSummary = checkBox.getSummary();
checkBox.setPersistent(false);
+ mWaitForWifiStateChange = false;
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mCm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
@@ -86,6 +94,7 @@ public WifiApEnabler(Context context, CheckBoxPreference checkBox) {
mIntentFilter = new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
mIntentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
}
public void resume() {
@@ -110,6 +119,7 @@ private void enableWifiCheckBox() {
public void setSoftapEnabled(boolean enable) {
final ContentResolver cr = mContext.getContentResolver();
+ int wifiSavedState = 0;
/**
* Disable Wifi if enabling tethering
*/
@@ -119,6 +129,21 @@ public void setSoftapEnabled(boolean enable) {
mWifiManager.setWifiEnabled(false);
Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 1);
}
+ /**
+ * Check if we have to wait for the WIFI_STATE_CHANGED intent
+ * before we re-enable the Checkbox.
+ */
+ if (!enable) {
+ try {
+ wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE);
+ } catch (Settings.SettingNotFoundException e) {
+ ;
+ }
+
+ if (wifiSavedState == 1) {
+ mWaitForWifiStateChange = true;
+ }
+ }
if (mWifiManager.setWifiApEnabled(null, enable)) {
/* Disable here, enabled on receiving success broadcast */
@@ -128,15 +153,9 @@ public void setSoftapEnabled(boolean enable) {
}
/**
- * If needed, restore Wifi on tether disable
+ * If needed, restore Wifi on tether disable
*/
if (!enable) {
- int wifiSavedState = 0;
- try {
- wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE);
- } catch (Settings.SettingNotFoundException e) {
- ;
- }
if (wifiSavedState == 1) {
mWifiManager.setWifiEnabled(true);
Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
@@ -199,7 +218,9 @@ private void handleWifiApStateChanged(int state) {
case WifiManager.WIFI_AP_STATE_DISABLED:
mCheckBox.setChecked(false);
mCheckBox.setSummary(mOriginalSummary);
- enableWifiCheckBox();
+ if (mWaitForWifiStateChange == false) {
+ enableWifiCheckBox();
+ }
break;
default:
mCheckBox.setChecked(false);
@@ -207,4 +228,15 @@ private void handleWifiApStateChanged(int state) {
enableWifiCheckBox();
}
}
+
+ private void handleWifiStateChanged(int state) {
+ switch (state) {
+ case WifiManager.WIFI_STATE_ENABLED:
+ case WifiManager.WIFI_STATE_UNKNOWN:
+ enableWifiCheckBox();
+ mWaitForWifiStateChange = false;
+ break;
+ default:
+ }
+ }
}
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index 55dc0337566..50eb961ec89 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -35,6 +35,7 @@
import android.net.wifi.WifiEnterpriseConfig.Eap;
import android.net.wifi.WifiEnterpriseConfig.Phase2;
import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiChannel;
import android.os.Handler;
import android.security.Credentials;
import android.security.KeyStore;
@@ -59,7 +60,9 @@
import com.android.settings.R;
import java.net.InetAddress;
+import java.util.ArrayList;
import java.util.Iterator;
+import java.util.List;
/**
* The class for allowing UIs like {@link WifiDialog} and {@link WifiConfigUiBase} to
@@ -72,8 +75,13 @@ public class WifiConfigController implements TextWatcher,
private final AccessPoint mAccessPoint;
private boolean mEdit;
+ private boolean mIbssSupported;
+ private List mSupportedIbssChannels;
+ private int mSelectedIbssChannelPos;
private TextView mSsidView;
+ private CheckBox mIbssView;
+ private Spinner mIbssFreqSpinner;
// e.g. AccessPoint.SECURITY_NONE
private int mAccessPointSecurity;
@@ -140,7 +148,8 @@ public class WifiConfigController implements TextWatcher,
private final Handler mTextViewChangedHandler;
public WifiConfigController(
- WifiConfigUiBase parent, View view, AccessPoint accessPoint, boolean edit) {
+ WifiConfigUiBase parent, View view, AccessPoint accessPoint, boolean edit,
+ boolean ibssSupported, List chans) {
mConfigUi = parent;
mInXlSetupWizard = (parent instanceof WifiConfigUiForSetupWizardXL);
@@ -149,6 +158,7 @@ public WifiConfigController(
mAccessPointSecurity = (accessPoint == null) ? AccessPoint.SECURITY_NONE :
accessPoint.security;
mEdit = edit;
+ mIbssSupported = ibssSupported;
mTextViewChangedHandler = new Handler();
final Context context = mConfigUi.getContext();
@@ -169,6 +179,9 @@ public WifiConfigController(
mIpSettingsSpinner.setOnItemSelectedListener(this);
mProxySettingsSpinner = (Spinner) mView.findViewById(R.id.proxy_settings);
mProxySettingsSpinner.setOnItemSelectedListener(this);
+ mIbssView = (CheckBox) mView.findViewById(R.id.wifi_ibss_checkbox);
+ mIbssView.setOnCheckedChangeListener(this);
+ mIbssFreqSpinner = (Spinner) mView.findViewById(R.id.wifi_ibss_freq);
if (mAccessPoint == null) { // new network
mConfigUi.setTitle(R.string.wifi_add_network);
@@ -196,6 +209,28 @@ public WifiConfigController(
((CheckBox)mView.findViewById(R.id.wifi_advanced_togglebox))
.setOnCheckedChangeListener(this);
+ if (mIbssSupported) {
+ mView.findViewById(R.id.wifi_ibss_toggle).setVisibility(View.VISIBLE);
+
+ mSupportedIbssChannels = new ArrayList();
+ List freqSpinnerList = new ArrayList();
+
+ for (WifiChannel c : chans) {
+ if (c.ibssAllowed) {
+ mSupportedIbssChannels.add(c);
+ freqSpinnerList.add(context.getString(R.string.wifi_channel) + " " +
+ Integer.toString(c.channel) + " (" +
+ Integer.toString(c.frequency) + " " +
+ context.getString(R.string.wifi_mhz) + ")");
+ }
+ }
+
+ ArrayAdapter freqAdapter = new ArrayAdapter(context,
+ android.R.layout.simple_spinner_item, freqSpinnerList);
+ freqAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mIbssFreqSpinner.setAdapter(freqAdapter);
+ mIbssFreqSpinner.setOnItemSelectedListener(this);
+ }
mConfigUi.setSubmitButton(context.getString(R.string.wifi_save));
} else {
@@ -203,6 +238,13 @@ public WifiConfigController(
ViewGroup group = (ViewGroup) mView.findViewById(R.id.info);
+ if (mAccessPoint.isIBSS) {
+ addRow(group, R.string.wifi_mode, context.getString(R.string.wifi_mode_ibss));
+ addRow(group, R.string.wifi_ibss_freq_title,
+ Integer.toString(mAccessPoint.frequency) + " " +
+ context.getString(R.string.wifi_mhz));
+ }
+
DetailedState state = mAccessPoint.getState();
if (state != null) {
addRow(group, R.string.wifi_status, Summary.get(mConfigUi.getContext(), state));
@@ -221,7 +263,8 @@ public WifiConfigController(
addRow(group, R.string.wifi_security, mAccessPoint.getSecurityString(false));
- boolean showAdvancedFields = false;
+ // always show advanced fields for IBSS, because we usually need a static IP
+ boolean showAdvancedFields = mAccessPoint.isIBSS;
if (mAccessPoint.networkId != INVALID_NETWORK_ID) {
WifiConfiguration config = mAccessPoint.getConfig();
if (config.ipAssignment == IpAssignment.STATIC) {
@@ -267,7 +310,7 @@ public WifiConfigController(
if (mEdit) {
mConfigUi.setSubmitButton(context.getString(R.string.wifi_save));
} else {
- if (state == null && level != -1) {
+ if (state == null && (level != -1 || mAccessPoint.isIBSS)) {
mConfigUi.setSubmitButton(context.getString(R.string.wifi_connect));
} else {
mView.findViewById(R.id.ip_fields).setVisibility(View.GONE);
@@ -330,13 +373,23 @@ void enableSubmitIfAppropriate() {
if (mAccessPoint == null) {
config.SSID = AccessPoint.convertToQuotedString(
mSsidView.getText().toString());
- // If the user adds a network manually, assume that it is hidden.
- config.hiddenSSID = true;
+
+ if (mIbssView.isChecked()) {
+ config.isIBSS = true;
+ config.frequency = mSupportedIbssChannels.get(mSelectedIbssChannelPos).frequency;
+ } else {
+ // If the user adds a network manually, assume that it is hidden.
+ config.hiddenSSID = true;
+ }
} else if (mAccessPoint.networkId == INVALID_NETWORK_ID) {
config.SSID = AccessPoint.convertToQuotedString(
mAccessPoint.ssid);
+ config.isIBSS = mAccessPoint.isIBSS;
+ config.frequency = mAccessPoint.frequency;
} else {
config.networkId = mAccessPoint.networkId;
+ config.isIBSS = mAccessPoint.isIBSS;
+ config.frequency = mAccessPoint.frequency;
}
switch (mAccessPointSecurity) {
@@ -893,6 +946,12 @@ public void onCheckedChanged(CompoundButton view, boolean isChecked) {
} else {
mView.findViewById(R.id.wifi_advanced_fields).setVisibility(View.GONE);
}
+ } else if (view.getId() == R.id.wifi_ibss_checkbox) {
+ if (((CheckBox) view).isChecked()) {
+ mView.findViewById(R.id.wifi_ibss_freq_fields).setVisibility(View.VISIBLE);
+ } else {
+ mView.findViewById(R.id.wifi_ibss_freq_fields).setVisibility(View.GONE);
+ }
}
}
@@ -905,6 +964,8 @@ public void onItemSelected(AdapterView> parent, View view, int position, long
showSecurityFields();
} else if (parent == mProxySettingsSpinner) {
showProxyFields();
+ } else if (parent == mIbssFreqSpinner) {
+ mSelectedIbssChannelPos = position;
} else {
showIpConfigFields();
}
diff --git a/src/com/android/settings/wifi/WifiConfigUiForSetupWizardXL.java b/src/com/android/settings/wifi/WifiConfigUiForSetupWizardXL.java
index 440e6946fce..f86b9c8680e 100644
--- a/src/com/android/settings/wifi/WifiConfigUiForSetupWizardXL.java
+++ b/src/com/android/settings/wifi/WifiConfigUiForSetupWizardXL.java
@@ -68,7 +68,7 @@ public WifiConfigUiForSetupWizardXL(
mInflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mView = mInflater.inflate(R.layout.wifi_config_ui_for_setup_wizard, parent, true);
- mController = new WifiConfigController(this, mView, mAccessPoint, edit);
+ mController = new WifiConfigController(this, mView, mAccessPoint, edit, false, null);
mInputMethodManager = (InputMethodManager)
activity.getSystemService(Context.INPUT_METHOD_SERVICE);
diff --git a/src/com/android/settings/wifi/WifiDialog.java b/src/com/android/settings/wifi/WifiDialog.java
index f1720c1c7df..ecd9d29124a 100644
--- a/src/com/android/settings/wifi/WifiDialog.java
+++ b/src/com/android/settings/wifi/WifiDialog.java
@@ -18,18 +18,23 @@
import com.android.settings.R;
+import java.util.List;
+
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
+import android.net.wifi.WifiChannel;
class WifiDialog extends AlertDialog implements WifiConfigUiBase {
static final int BUTTON_SUBMIT = DialogInterface.BUTTON_POSITIVE;
static final int BUTTON_FORGET = DialogInterface.BUTTON_NEUTRAL;
private final boolean mEdit;
+ private final boolean mIbssSupported;
+ private List mSupportedChannels;
private final DialogInterface.OnClickListener mListener;
private final AccessPoint mAccessPoint;
@@ -37,9 +42,11 @@ class WifiDialog extends AlertDialog implements WifiConfigUiBase {
private WifiConfigController mController;
public WifiDialog(Context context, DialogInterface.OnClickListener listener,
- AccessPoint accessPoint, boolean edit) {
+ AccessPoint accessPoint, boolean edit, boolean ibssSupported, List chan) {
super(context);
mEdit = edit;
+ mIbssSupported = ibssSupported;
+ mSupportedChannels = chan;
mListener = listener;
mAccessPoint = accessPoint;
}
@@ -54,7 +61,7 @@ protected void onCreate(Bundle savedInstanceState) {
mView = getLayoutInflater().inflate(R.layout.wifi_dialog, null);
setView(mView);
setInverseBackgroundForced(true);
- mController = new WifiConfigController(this, mView, mAccessPoint, mEdit);
+ mController = new WifiConfigController(this, mView, mAccessPoint, mEdit, mIbssSupported, mSupportedChannels);
super.onCreate(savedInstanceState);
/* During creation, the submit button can be unavailable to determine
* visibility. Right after creation, update button visibility */
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 1caf58bcd1c..e72b88a4783 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -45,6 +45,7 @@
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WpsInfo;
+import android.net.wifi.WifiChannel;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -100,7 +101,8 @@ public class WifiSettings extends RestrictedSettingsFragment
private static final int MENU_ID_SCAN = Menu.FIRST + 5;
private static final int MENU_ID_CONNECT = Menu.FIRST + 6;
private static final int MENU_ID_FORGET = Menu.FIRST + 7;
- private static final int MENU_ID_MODIFY = Menu.FIRST + 8;
+ private static final int MENU_ID_FORGET_ALL = Menu.FIRST + 8;
+ private static final int MENU_ID_MODIFY = Menu.FIRST + 9;
private static final int WIFI_DIALOG_ID = 1;
private static final int WPS_PBC_DIALOG_ID = 2;
@@ -127,6 +129,8 @@ public class WifiSettings extends RestrictedSettingsFragment
private WifiManager.ActionListener mSaveListener;
private WifiManager.ActionListener mForgetListener;
private boolean mP2pSupported;
+ private boolean mIbssSupported;
+ List mSupportedChannels;
private WifiEnabler mWifiEnabler;
// An access point being editted is stored here.
@@ -474,6 +478,9 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.add(Menu.NONE, MENU_ID_WPS_PIN, 0, R.string.wifi_menu_wps_pin)
.setEnabled(wifiIsEnabled)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ menu.add(Menu.NONE, MENU_ID_FORGET_ALL, 0, R.string.wifi_menu_forget_all)
+ .setEnabled(wifiIsEnabled)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
if (mP2pSupported) {
menu.add(Menu.NONE, MENU_ID_P2P, 0, R.string.wifi_menu_p2p)
.setEnabled(wifiIsEnabled)
@@ -535,6 +542,9 @@ public boolean onOptionsItemSelected(MenuItem item) {
onAddNetworkPressed();
}
return true;
+ case MENU_ID_FORGET_ALL:
+ forgetAll();
+ return true;
case MENU_ID_ADVANCED:
if (getActivity() instanceof PreferenceActivity) {
((PreferenceActivity) getActivity()).startPreferencePanel(
@@ -609,7 +619,8 @@ public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference prefere
mSelectedAccessPoint = (AccessPoint) preference;
/** Bypass dialog for unsecured, unsaved networks */
if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE &&
- mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) {
+ mSelectedAccessPoint.networkId == INVALID_NETWORK_ID &&
+ !mSelectedAccessPoint.isIBSS) {
mSelectedAccessPoint.generateOpenNetworkConfig();
mWifiManager.connect(mSelectedAccessPoint.getConfig(), mConnectListener);
} else {
@@ -650,7 +661,7 @@ public Dialog onCreateDialog(int dialogId) {
}
// If it's still null, fine, it's for Add Network
mSelectedAccessPoint = ap;
- mDialog = new WifiDialog(getActivity(), this, ap, mDlgEdit);
+ mDialog = new WifiDialog(getActivity(), this, ap, mDlgEdit, mIbssSupported, mSupportedChannels);
return mDialog;
case WPS_PBC_DIALOG_ID:
return new WpsDialog(getActivity(), WpsInfo.PBC);
@@ -785,9 +796,13 @@ private List constructAccessPoints() {
final List results = mWifiManager.getScanResults();
if (results != null) {
for (ScanResult result : results) {
- // Ignore hidden and ad-hoc networks.
- if (result.SSID == null || result.SSID.length() == 0 ||
- result.capabilities.contains("[IBSS]")) {
+ // Ignore hidden networks.
+ if (result.SSID == null || result.SSID.length() == 0) {
+ continue;
+ }
+
+ // Ignore IBSS if chipset does not support them
+ if (!mIbssSupported && result.capabilities.contains("[IBSS]")) {
continue;
}
@@ -910,6 +925,10 @@ private void updateWifiState(int state) {
switch (state) {
case WifiManager.WIFI_STATE_ENABLED:
+ // this function only returns valid results in enabled state
+ mIbssSupported = mWifiManager.isIbssSupported();
+ mSupportedChannels = mWifiManager.getSupportedChannels();
+
mScanner.resume();
return; // not break, to avoid the call to pause() below
@@ -1032,6 +1051,22 @@ public void onClick(DialogInterface dialogInterface, int button) {
changeNextButtonState(false);
}
+ private void forgetAll() {
+ List configs = mWifiManager.getConfiguredNetworks();
+ if (configs != null) {
+ for (int i=0; i DEVICE_NAME_MAX_LENGTH_BYTES) {
+ editable.delete(selectionEnd - 1, selectionEnd);
+ Toast.makeText(getActivity(), R.string.p2p_device_name_input_limit,
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ if (mDeviceNameText.getEditableText() == editable) {
+ LimitDeviceNameLength(editable);
+ }
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
+ }
}