diff options
Diffstat (limited to 'src/com/android/settings')
-rw-r--r-- | src/com/android/settings/ChooseEncryptionPassword.java | 682 | ||||
-rw-r--r-- | src/com/android/settings/DevelopmentSettings.java | 2 | ||||
-rw-r--r-- | src/com/android/settings/ReplaceEncryptionPassword.java | 105 | ||||
-rw-r--r-- | src/com/android/settings/SecuritySettings.java | 11 | ||||
-rw-r--r-- | src/com/android/settings/Settings.java | 1 | ||||
-rw-r--r-- | src/com/android/settings/SettingsActivity.java | 4 | ||||
-rw-r--r-- | src/com/android/settings/cmstats/AnonymousStats.java | 81 | ||||
-rw-r--r-- | src/com/android/settings/cmstats/PreviewData.java | 55 | ||||
-rw-r--r-- | src/com/android/settings/cmstats/ReportingService.java | 82 | ||||
-rw-r--r-- | src/com/android/settings/cmstats/ReportingServiceManager.java | 109 | ||||
-rw-r--r-- | src/com/android/settings/cmstats/StatsUploadJobService.java | 205 | ||||
-rw-r--r-- | src/com/android/settings/cmstats/Utilities.java | 102 |
12 files changed, 800 insertions, 639 deletions
diff --git a/src/com/android/settings/ChooseEncryptionPassword.java b/src/com/android/settings/ChooseEncryptionPassword.java new file mode 100644 index 000000000..43e2b0e08 --- /dev/null +++ b/src/com/android/settings/ChooseEncryptionPassword.java @@ -0,0 +1,682 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.PasswordEntryKeyboardHelper; +import com.android.internal.widget.PasswordEntryKeyboardView; +import com.android.internal.widget.TextViewInputDisabler; +import com.android.internal.widget.LockPatternUtils.RequestThrottledException; +import com.android.settings.notification.RedactionInterstitial; + +import android.app.Activity; +import android.app.Fragment; +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.content.Intent; +import android.inputmethodservice.KeyboardView; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.UserHandle; +import android.text.Editable; +import android.text.InputType; +import android.text.Selection; +import android.text.Spannable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.Log; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.View.OnClickListener; +import android.view.inputmethod.EditorInfo; +import android.widget.Button; +import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; + +public class ChooseEncryptionPassword extends SettingsActivity { + public static final String PASSWORD_MIN_KEY = "lockscreen.password_min"; + public static final String PASSWORD_MAX_KEY = "lockscreen.password_max"; + public static final String PASSWORD_MIN_LETTERS_KEY = "lockscreen.password_min_letters"; + public static final String PASSWORD_MIN_LOWERCASE_KEY = "lockscreen.password_min_lowercase"; + public static final String PASSWORD_MIN_UPPERCASE_KEY = "lockscreen.password_min_uppercase"; + public static final String PASSWORD_MIN_NUMERIC_KEY = "lockscreen.password_min_numeric"; + public static final String PASSWORD_MIN_SYMBOLS_KEY = "lockscreen.password_min_symbols"; + public static final String PASSWORD_MIN_NONLETTER_KEY = "lockscreen.password_min_nonletter"; + + private static final String TAG = "ChooseEncryptionPassword"; + + @Override + public Intent getIntent() { + Intent modIntent = new Intent(super.getIntent()); + modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName()); + return modIntent; + } + + public static Intent createIntent(Context context, int quality, + int minLength, final int maxLength, boolean requirePasswordToDecrypt, + boolean confirmCredentials) { + Intent intent = new Intent().setClass(context, ChooseEncryptionPassword.class); + intent.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, quality); + intent.putExtra(PASSWORD_MIN_KEY, minLength); + intent.putExtra(PASSWORD_MAX_KEY, maxLength); + intent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, confirmCredentials); + intent.putExtra(EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, requirePasswordToDecrypt); + return intent; + } + + public static Intent createIntent(Context context, int quality, + int minLength, final int maxLength, boolean requirePasswordToDecrypt, String password) { + Intent intent = createIntent(context, quality, minLength, maxLength, + requirePasswordToDecrypt, false); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, password); + return intent; + } + + public static Intent createIntent(Context context, int quality, + int minLength, final int maxLength, boolean requirePasswordToDecrypt, long challenge) { + Intent intent = createIntent(context, quality, minLength, maxLength, + requirePasswordToDecrypt, false); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); + return intent; + } + + @Override + protected boolean isValidFragment(String fragmentName) { + if (ChooseEncryptionPasswordFragment.class.getName().equals(fragmentName)) return true; + return false; + } + + /* package */ Class<? extends Fragment> getFragmentClass() { + return ChooseEncryptionPasswordFragment.class; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + // TODO: Fix on phones + // Disable IME on our window since we provide our own keyboard + //getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, + //WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + super.onCreate(savedInstanceState); + CharSequence msg = getText(R.string.lockpassword_choose_your_password_header); + setTitle(msg); + } + + public static class ChooseEncryptionPasswordFragment extends InstrumentedFragment + implements OnClickListener, OnEditorActionListener, TextWatcher, + SaveAndFinishWorker.Listener { + private static final String KEY_FIRST_PIN = "first_pin"; + private static final String KEY_UI_STAGE = "ui_stage"; + private static final String KEY_CURRENT_PASSWORD = "current_password"; + private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker"; + + private String mCurrentPassword; + private String mChosenPassword; + private boolean mHasChallenge; + private long mChallenge; + private TextView mPasswordEntry; + private TextViewInputDisabler mPasswordEntryInputDisabler; + private int mPasswordMinLength = LockPatternUtils.MIN_LOCK_PASSWORD_SIZE; + private int mPasswordMaxLength = 16; + private int mPasswordMinLetters = 0; + private int mPasswordMinUpperCase = 0; + private int mPasswordMinLowerCase = 0; + private int mPasswordMinSymbols = 0; + private int mPasswordMinNumeric = 0; + private int mPasswordMinNonLetter = 0; + private LockPatternUtils mLockPatternUtils; + private SaveAndFinishWorker mSaveAndFinishWorker; + private int mRequestedQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; + private ChooseLockSettingsHelper mChooseLockSettingsHelper; + private Stage mUiStage = Stage.Introduction; + + private TextView mHeaderText; + private String mFirstPin; + private KeyboardView mKeyboardView; + private PasswordEntryKeyboardHelper mKeyboardHelper; + private boolean mIsAlphaMode; + private Button mCancelButton; + private Button mNextButton; + private static final int CONFIRM_EXISTING_REQUEST = 58; + static final int RESULT_FINISHED = RESULT_FIRST_USER; + private static final long ERROR_MESSAGE_TIMEOUT = 3000; + private static final int MSG_SHOW_ERROR = 1; + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_SHOW_ERROR) { + updateStage((Stage) msg.obj); + } + } + }; + + /** + * Keep track internally of where the user is in choosing a pattern. + */ + protected enum Stage { + + Introduction(R.string.lockpassword_choose_your_password_header, + R.string.lockpassword_choose_your_pin_header, + R.string.lockpassword_continue_label), + + NeedToConfirm(R.string.lockpassword_confirm_your_password_header, + R.string.lockpassword_confirm_your_pin_header, + R.string.lockpassword_ok_label), + + ConfirmWrong(R.string.lockpassword_confirm_passwords_dont_match, + R.string.lockpassword_confirm_pins_dont_match, + R.string.lockpassword_continue_label); + + Stage(int hintInAlpha, int hintInNumeric, int nextButtonText) { + this.alphaHint = hintInAlpha; + this.numericHint = hintInNumeric; + this.buttonText = nextButtonText; + } + + public final int alphaHint; + public final int numericHint; + public final int buttonText; + } + + // required constructor for fragments + public ChooseEncryptionPasswordFragment() { + + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mLockPatternUtils = new LockPatternUtils(getActivity()); + Intent intent = getActivity().getIntent(); + if (!(getActivity() instanceof ChooseEncryptionPassword)) { + throw new SecurityException("Fragment contained in wrong activity"); + } + mRequestedQuality = Math.max(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, + mRequestedQuality), mLockPatternUtils.getRequestedPasswordQuality( + UserHandle.myUserId())); + mPasswordMinLength = Math.max(Math.max( + LockPatternUtils.MIN_LOCK_PASSWORD_SIZE, + intent.getIntExtra(PASSWORD_MIN_KEY, mPasswordMinLength)), + mLockPatternUtils.getRequestedMinimumPasswordLength(UserHandle.myUserId())); + mPasswordMaxLength = intent.getIntExtra(PASSWORD_MAX_KEY, mPasswordMaxLength); + mPasswordMinLetters = Math.max(intent.getIntExtra(PASSWORD_MIN_LETTERS_KEY, + mPasswordMinLetters), mLockPatternUtils.getRequestedPasswordMinimumLetters( + UserHandle.myUserId())); + mPasswordMinUpperCase = Math.max(intent.getIntExtra(PASSWORD_MIN_UPPERCASE_KEY, + mPasswordMinUpperCase), mLockPatternUtils.getRequestedPasswordMinimumUpperCase( + UserHandle.myUserId())); + mPasswordMinLowerCase = Math.max(intent.getIntExtra(PASSWORD_MIN_LOWERCASE_KEY, + mPasswordMinLowerCase), mLockPatternUtils.getRequestedPasswordMinimumLowerCase( + UserHandle.myUserId())); + mPasswordMinNumeric = Math.max(intent.getIntExtra(PASSWORD_MIN_NUMERIC_KEY, + mPasswordMinNumeric), mLockPatternUtils.getRequestedPasswordMinimumNumeric( + UserHandle.myUserId())); + mPasswordMinSymbols = Math.max(intent.getIntExtra(PASSWORD_MIN_SYMBOLS_KEY, + mPasswordMinSymbols), mLockPatternUtils.getRequestedPasswordMinimumSymbols( + UserHandle.myUserId())); + mPasswordMinNonLetter = Math.max(intent.getIntExtra(PASSWORD_MIN_NONLETTER_KEY, + mPasswordMinNonLetter), mLockPatternUtils.getRequestedPasswordMinimumNonLetter( + UserHandle.myUserId())); + + mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity()); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.choose_lock_password, container, false); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + mCancelButton = (Button) view.findViewById(R.id.cancel_button); + mCancelButton.setOnClickListener(this); + mNextButton = (Button) view.findViewById(R.id.next_button); + mNextButton.setOnClickListener(this); + + mIsAlphaMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == mRequestedQuality + || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == mRequestedQuality + || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == mRequestedQuality; + mKeyboardView = (PasswordEntryKeyboardView) view.findViewById(R.id.keyboard); + mPasswordEntry = (TextView) view.findViewById(R.id.password_entry); + mPasswordEntry.setOnEditorActionListener(this); + mPasswordEntry.addTextChangedListener(this); + mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry); + + final Activity activity = getActivity(); + mKeyboardHelper = new PasswordEntryKeyboardHelper(activity, + mKeyboardView, mPasswordEntry); + mKeyboardHelper.setKeyboardMode(mIsAlphaMode ? + PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA + : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC); + + mHeaderText = (TextView) view.findViewById(R.id.headerText); + mKeyboardView.requestFocus(); + + int currentType = mPasswordEntry.getInputType(); + mPasswordEntry.setInputType(mIsAlphaMode ? currentType + : (InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD)); + + Intent intent = getActivity().getIntent(); + final boolean confirmCredentials = intent.getBooleanExtra( + ChooseLockGeneric.CONFIRM_CREDENTIALS, true); + mCurrentPassword = intent.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); + mHasChallenge = intent.getBooleanExtra( + ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); + mChallenge = intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0); + if (savedInstanceState == null) { + updateStage(Stage.Introduction); + if (confirmCredentials) { + mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST, + getString(R.string.unlock_set_unlock_launch_picker_title), true); + } + } else { + // restore from previous state + mFirstPin = savedInstanceState.getString(KEY_FIRST_PIN); + final String state = savedInstanceState.getString(KEY_UI_STAGE); + if (state != null) { + mUiStage = Stage.valueOf(state); + updateStage(mUiStage); + } + + if (mCurrentPassword == null) { + mCurrentPassword = savedInstanceState.getString(KEY_CURRENT_PASSWORD); + } + + // Re-attach to the exiting worker if there is one. + mSaveAndFinishWorker = (SaveAndFinishWorker) getFragmentManager().findFragmentByTag( + FRAGMENT_TAG_SAVE_AND_FINISH); + } + if (activity instanceof SettingsActivity) { + final SettingsActivity sa = (SettingsActivity) activity; + int id = mIsAlphaMode ? R.string.lockpassword_choose_your_password_header + : R.string.lockpassword_choose_your_pin_header; + CharSequence title = getText(id); + sa.setTitle(title); + } + } + + @Override + protected int getMetricsCategory() { + return MetricsLogger.CHOOSE_LOCK_PASSWORD; + } + + @Override + public void onResume() { + super.onResume(); + updateStage(mUiStage); + if (mSaveAndFinishWorker != null) { + mSaveAndFinishWorker.setListener(this); + } else { + mKeyboardView.requestFocus(); + } + } + + @Override + public void onPause() { + mHandler.removeMessages(MSG_SHOW_ERROR); + if (mSaveAndFinishWorker != null) { + mSaveAndFinishWorker.setListener(null); + } + + super.onPause(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString(KEY_UI_STAGE, mUiStage.name()); + outState.putString(KEY_FIRST_PIN, mFirstPin); + outState.putString(KEY_CURRENT_PASSWORD, mCurrentPassword); + } + + @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(); + } else { + mCurrentPassword = data.getStringExtra( + ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); + } + break; + } + } + + protected Intent getRedactionInterstitialIntent(Context context) { + return RedactionInterstitial.createStartIntent(context); + } + + protected void updateStage(Stage stage) { + final Stage previousStage = mUiStage; + mUiStage = stage; + updateUi(); + + // 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()); + } + } + + /** + * Validates PIN and returns a message to display if PIN fails test. + * @param password the raw password the user typed in + * @return error message to show to user or null if password is OK + */ + private String validatePassword(String password) { + if (password.length() < mPasswordMinLength) { + return getString(mIsAlphaMode ? + R.string.lockpassword_password_too_short + : R.string.lockpassword_pin_too_short, mPasswordMinLength); + } + if (password.length() > mPasswordMaxLength) { + return getString(mIsAlphaMode ? + R.string.lockpassword_password_too_long + : R.string.lockpassword_pin_too_long, mPasswordMaxLength + 1); + } + int letters = 0; + int numbers = 0; + int lowercase = 0; + int symbols = 0; + int uppercase = 0; + int nonletter = 0; + for (int i = 0; i < password.length(); i++) { + char c = password.charAt(i); + // allow non control Latin-1 characters only + if (c < 32 || c > 127) { + return getString(R.string.lockpassword_illegal_character); + } + if (c >= '0' && c <= '9') { + numbers++; + nonletter++; + } else if (c >= 'A' && c <= 'Z') { + letters++; + uppercase++; + } else if (c >= 'a' && c <= 'z') { + letters++; + lowercase++; + } else { + symbols++; + nonletter++; + } + } + if (DevicePolicyManager.PASSWORD_QUALITY_NUMERIC == mRequestedQuality + || DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX == mRequestedQuality) { + if (letters > 0 || symbols > 0) { + // This shouldn't be possible unless user finds some way to bring up + // soft keyboard + return getString(R.string.lockpassword_pin_contains_non_digits); + } + // Check for repeated characters or sequences (e.g. '1234', '0000', '2468') + final int sequence = LockPatternUtils.maxLengthSequence(password); + if (DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX == mRequestedQuality + && sequence > LockPatternUtils.MAX_ALLOWED_SEQUENCE) { + return getString(R.string.lockpassword_pin_no_sequential_digits); + } + } else if (DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == mRequestedQuality) { + if (letters < mPasswordMinLetters) { + return String.format(getResources().getQuantityString( + R.plurals.lockpassword_password_requires_letters, mPasswordMinLetters), + mPasswordMinLetters); + } else if (numbers < mPasswordMinNumeric) { + return String.format(getResources().getQuantityString( + R.plurals.lockpassword_password_requires_numeric, mPasswordMinNumeric), + mPasswordMinNumeric); + } else if (lowercase < mPasswordMinLowerCase) { + return String.format(getResources().getQuantityString( + R.plurals.lockpassword_password_requires_lowercase, mPasswordMinLowerCase), + mPasswordMinLowerCase); + } else if (uppercase < mPasswordMinUpperCase) { + return String.format(getResources().getQuantityString( + R.plurals.lockpassword_password_requires_uppercase, mPasswordMinUpperCase), + mPasswordMinUpperCase); + } else if (symbols < mPasswordMinSymbols) { + return String.format(getResources().getQuantityString( + R.plurals.lockpassword_password_requires_symbols, mPasswordMinSymbols), + mPasswordMinSymbols); + } else if (nonletter < mPasswordMinNonLetter) { + return String.format(getResources().getQuantityString( + R.plurals.lockpassword_password_requires_nonletter, mPasswordMinNonLetter), + mPasswordMinNonLetter); + } + } else { + final boolean alphabetic = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC + == mRequestedQuality; + final boolean alphanumeric = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC + == mRequestedQuality; + if ((alphabetic || alphanumeric) && letters == 0) { + return getString(R.string.lockpassword_password_requires_alpha); + } + if (alphanumeric && numbers == 0) { + return getString(R.string.lockpassword_password_requires_digit); + } + } + if(mLockPatternUtils.checkPasswordHistory(password, UserHandle.myUserId())) { + return getString(mIsAlphaMode ? R.string.lockpassword_password_recently_used + : R.string.lockpassword_pin_recently_used); + } + + return null; + } + + public void handleNext() { + if (mSaveAndFinishWorker != null) return; + mChosenPassword = mPasswordEntry.getText().toString(); + if (TextUtils.isEmpty(mChosenPassword)) { + return; + } + String errorMsg = null; + if (mUiStage == Stage.Introduction) { + errorMsg = validatePassword(mChosenPassword); + if (errorMsg == null) { + mFirstPin = mChosenPassword; + mPasswordEntry.setText(""); + updateStage(Stage.NeedToConfirm); + } + } else if (mUiStage == Stage.NeedToConfirm) { + if (mFirstPin.equals(mChosenPassword)) { + startSaveAndFinish(); + } else { + CharSequence tmp = mPasswordEntry.getText(); + if (tmp != null) { + Selection.setSelection((Spannable) tmp, 0, tmp.length()); + } + updateStage(Stage.ConfirmWrong); + } + } + if (errorMsg != null) { + showError(errorMsg, mUiStage); + } + } + + protected void setNextEnabled(boolean enabled) { + mNextButton.setEnabled(enabled); + } + + protected void setNextText(int text) { + mNextButton.setText(text); + } + + public void onClick(View v) { + switch (v.getId()) { + case R.id.next_button: + handleNext(); + break; + + case R.id.cancel_button: + getActivity().finish(); + break; + } + } + + private void showError(String msg, final Stage next) { + mHeaderText.setText(msg); + mHeaderText.announceForAccessibility(mHeaderText.getText()); + Message mesg = mHandler.obtainMessage(MSG_SHOW_ERROR, next); + mHandler.removeMessages(MSG_SHOW_ERROR); + mHandler.sendMessageDelayed(mesg, ERROR_MESSAGE_TIMEOUT); + } + + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + // Check if this was the result of hitting the enter or "done" key + if (actionId == EditorInfo.IME_NULL + || actionId == EditorInfo.IME_ACTION_DONE + || actionId == EditorInfo.IME_ACTION_NEXT) { + handleNext(); + return true; + } + return false; + } + + /** + * Update the hint based on current Stage and length of password entry + */ + private void updateUi() { + final boolean canInput = mSaveAndFinishWorker == null; + String password = mPasswordEntry.getText().toString(); + final int length = password.length(); + if (mUiStage == Stage.Introduction) { + if (length < mPasswordMinLength) { + String msg = getString(mIsAlphaMode ? R.string.lockpassword_password_too_short + : R.string.lockpassword_pin_too_short, mPasswordMinLength); + mHeaderText.setText(msg); + setNextEnabled(false); + } else { + String error = validatePassword(password); + if (error != null) { + mHeaderText.setText(error); + setNextEnabled(false); + } else { + mHeaderText.setText(R.string.lockpassword_press_continue); + setNextEnabled(true); + } + } + } else { + mHeaderText.setText(mIsAlphaMode ? mUiStage.alphaHint : mUiStage.numericHint); + setNextEnabled(canInput && length > 0); + } + setNextText(mUiStage.buttonText); + mPasswordEntryInputDisabler.setInputEnabled(canInput); + } + + public void afterTextChanged(Editable s) { + // Changing the text while error displayed resets to NeedToConfirm state + if (mUiStage == Stage.ConfirmWrong) { + mUiStage = Stage.NeedToConfirm; + } + updateUi(); + } + + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + private void startSaveAndFinish() { + if (mSaveAndFinishWorker != null) { + Log.w(TAG, "startSaveAndFinish with an existing SaveAndFinishWorker."); + return; + } + + mPasswordEntryInputDisabler.setInputEnabled(false); + setNextEnabled(false); + + mSaveAndFinishWorker = new SaveAndFinishWorker(); + getFragmentManager().beginTransaction().add(mSaveAndFinishWorker, + FRAGMENT_TAG_SAVE_AND_FINISH).commit(); + mSaveAndFinishWorker.setListener(this); + + final boolean required = getActivity().getIntent().getBooleanExtra( + EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true); + mSaveAndFinishWorker.start(mLockPatternUtils, required, mHasChallenge, mChallenge, + mChosenPassword, mCurrentPassword, mRequestedQuality); + } + + @Override + public void onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData) { + getActivity().setResult(RESULT_FINISHED, resultData); + getActivity().finish(); + + if (!wasSecureBefore) { + Intent intent = getRedactionInterstitialIntent(getActivity()); + if (intent != null) { + startActivity(intent); + } + } + } + } + + private static class SaveAndFinishWorker extends SaveChosenLockWorkerBase { + + private String mChosenPassword; + private String mCurrentPassword; + private int mRequestedQuality; + + public void start(LockPatternUtils utils, boolean required, + boolean hasChallenge, long challenge, + String chosenPassword, String currentPassword, int requestedQuality) { + prepare(utils, required, hasChallenge, challenge); + + mChosenPassword = chosenPassword; + mCurrentPassword = currentPassword; + mRequestedQuality = requestedQuality; + + start(); + } + + @Override + protected Intent saveAndVerifyInBackground() { + Intent result = null; + final int userId = UserHandle.myUserId(); + mUtils.setCredentialRequiredToDecrypt(true); + mUtils.setSeparateEncryptionPassword(mChosenPassword); + + if (mHasChallenge) { + byte[] token; + try { + token = mUtils.verifyPassword(mChosenPassword, mChallenge, userId); + } catch (RequestThrottledException e) { + token = null; + } + + if (token == null) { + Log.e(TAG, "critical: no token returned for known good password."); + } + + result = new Intent(); + result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token); + } + + return result; + } + } +} diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java index b5b89cb61..d6b1d920f 100644 --- a/src/com/android/settings/DevelopmentSettings.java +++ b/src/com/android/settings/DevelopmentSettings.java @@ -779,7 +779,7 @@ public class DevelopmentSettings extends SettingsPreferenceFragment private void updateAdvancedRebootOptions() { mAdvancedReboot.setChecked(CMSettings.Secure.getInt(getActivity().getContentResolver(), - CMSettings.Secure.ADVANCED_REBOOT, 0) != 0); + CMSettings.Secure.ADVANCED_REBOOT, 1) != 0); } private void resetDevelopmentShortcutOptions() { diff --git a/src/com/android/settings/ReplaceEncryptionPassword.java b/src/com/android/settings/ReplaceEncryptionPassword.java new file mode 100644 index 000000000..b6869d83a --- /dev/null +++ b/src/com/android/settings/ReplaceEncryptionPassword.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings; + +import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockPatternUtils.RequestThrottledException; + +import android.app.Activity; +import android.app.Fragment; +import android.content.Intent; +import android.content.res.Resources; +import android.os.Bundle; +import android.os.storage.StorageManager; +import android.os.UserHandle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class ReplaceEncryptionPassword extends SettingsActivity { + @Override + public Intent getIntent() { + Intent modIntent = new Intent(super.getIntent()); + modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName()); + return modIntent; + } + + @Override + protected boolean isValidFragment(String fragmentName) { + if (ReplaceEncryptionPasswordFragment.class.getName().equals(fragmentName)) return true; + return false; + } + + /* package */ Class<? extends Fragment> getFragmentClass() { + return ReplaceEncryptionPasswordFragment.class; + } + + public static class ReplaceEncryptionPasswordFragment extends Fragment { + private static final int KEYGUARD_REQUEST = 55; + private byte mPatternSize = LockPatternUtils.PATTERN_SIZE_DEFAULT; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (!(getActivity() instanceof ReplaceEncryptionPassword)) { + throw new SecurityException("Fragment contained in wrong activity"); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { + Resources res = getActivity().getResources(); + ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(getActivity(), this); + + helper.launchConfirmationActivity(KEYGUARD_REQUEST, + res.getText(R.string.unlock_set_unlock_password_title), + true); + + return null; + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + final int userId = UserHandle.myUserId(); + + if (requestCode != KEYGUARD_REQUEST) { + return; + } + + // If the user entered a valid keyguard trace, present the final + // confirmation prompt; otherwise, go back to the initial state. + if (resultCode == Activity.RESULT_OK && data != null) { + LockPatternUtils utils = new LockPatternUtils(getActivity()); + int type = data.getIntExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE, -1); + String password = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); + if (type == StorageManager.CRYPT_TYPE_PATTERN) { + mPatternSize = getActivity().getIntent().getByteExtra("pattern_size", + LockPatternUtils.PATTERN_SIZE_DEFAULT); + + utils.replaceSeparateEncryptionPasswordWithPattern( + utils.stringToPattern(password, + mPatternSize), userId); + } else { + utils.replaceSeparateEncryptionPassword(password); + } + } + + getActivity().finish(); + } + } +} diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index 7db4a4ef0..697767282 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -98,6 +98,7 @@ public class SecuritySettings extends SettingsPreferenceFragment private static final String KEY_VISIBLE_ERROR_PATTERN = "visible_error_pattern"; private static final String KEY_VISIBLE_DOTS = "visibledots"; private static final String KEY_SECURITY_CATEGORY = "security_category"; + private static final String KEY_ENCRYPTION_CATEGORY = "encryption_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"; @@ -127,6 +128,7 @@ public class SecuritySettings extends SettingsPreferenceFragment private static final String KEY_GENERAL_CATEGORY = "general_category"; private static final String KEY_LIVE_LOCK_SCREEN = "live_lock_screen"; private static final String KEY_LOCK_SCREEN_BLUR = CMSettings.Secure.LOCK_SCREEN_BLUR_ENABLED; + private static final String KEY_REPLACE_ENCRYPTION_PASSWORD = "crypt_keeper_replace_password"; // These switch preferences need special handling since they're not all stored in Settings. private static final String SWITCH_PREFERENCE_KEYS[] = { KEY_LOCK_AFTER_TIMEOUT, @@ -300,6 +302,15 @@ public class SecuritySettings extends SettingsPreferenceFragment if (LockPatternUtils.isDeviceEncryptionEnabled()) { // The device is currently encrypted. addPreferencesFromResource(R.xml.security_settings_encrypted); + if (!mLockPatternUtils.isSeparateEncryptionPasswordEnabled()) { + PreferenceGroup encryptionCategory = + (PreferenceGroup) root.findPreference(KEY_ENCRYPTION_CATEGORY); + if (encryptionCategory != null) { + Preference replaceEncryptionPassword = + root.findPreference(KEY_REPLACE_ENCRYPTION_PASSWORD); + encryptionCategory.removePreference(replaceEncryptionPassword); + } + } } else { // This device supports encryption but isn't encrypted. addPreferencesFromResource(R.xml.security_settings_unencrypted); diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 0834b4f42..a52af29a5 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -122,7 +122,6 @@ public class Settings extends SettingsActivity { public static class DisplayRotationActivity extends SettingsActivity { /* empty */ } public static class BlacklistSettingsActivity extends SettingsActivity { /* empty */ } public static class ProfilesSettingsActivity extends SettingsActivity { /* empty */ } - public static class AnonymousStatsActivity extends Settings { /* empty */ } public static class ContributorsCloudActivity extends SettingsActivity { /* empty */ } public static class CMSoundSettingsActivity extends SettingsActivity { /* empty */ } public static class LockScreenSettingsActivity extends SettingsActivity { /* empty */ } diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index b54d7719a..d5c53a445 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -1250,9 +1250,7 @@ public class SettingsActivity extends Activity } private void updateTilesList(List<DashboardCategory> target) { - final boolean showDev = mDevelopmentPreferences.getBoolean( - DevelopmentSettings.PREF_SHOW, - android.os.Build.TYPE.equals("eng")); + final boolean showDev = true; final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE); diff --git a/src/com/android/settings/cmstats/AnonymousStats.java b/src/com/android/settings/cmstats/AnonymousStats.java deleted file mode 100644 index 54e124da6..000000000 --- a/src/com/android/settings/cmstats/AnonymousStats.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2015 The CyanogenMod Project - * (C) 2017 The LineageOS 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.cmstats; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Bundle; - -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; - -import org.cyanogenmod.internal.logging.CMMetricsLogger; - -public class AnonymousStats extends SettingsPreferenceFragment { - - private static final String PREF_FILE_NAME = "CMStats"; - /* package */ static final String ANONYMOUS_OPT_IN = "pref_anonymous_opt_in"; - /* package */ static final String ANONYMOUS_LAST_CHECKED = "pref_anonymous_checked_in"; - - /* package */ static final String KEY_LAST_JOB_ID = "last_job_id"; - /* package */ static final int QUEUE_MAX_THRESHOLD = 1000; - - public static SharedPreferences getPreferences(Context context) { - return context.getSharedPreferences(PREF_FILE_NAME, 0); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.anonymous_stats); - } - - public static void updateLastSynced(Context context) { - getPreferences(context) - .edit() - .putLong(ANONYMOUS_LAST_CHECKED,System.currentTimeMillis()) - .commit(); - } - - private static int getLastJobId(Context context) { - return getPreferences(context).getInt(KEY_LAST_JOB_ID, 0); - } - - private static void setLastJobId(Context context, int id) { - getPreferences(context) - .edit() - .putInt(KEY_LAST_JOB_ID, id) - .commit(); - } - - public static int getNextJobId(Context context) { - int lastId = getLastJobId(context); - if (lastId >= QUEUE_MAX_THRESHOLD) { - lastId = 1; - } else { - lastId += 1; - } - setLastJobId(context, lastId); - return lastId; - } - - @Override - protected int getMetricsCategory() { - return CMMetricsLogger.ANONYMOUS_STATS; - } -} diff --git a/src/com/android/settings/cmstats/PreviewData.java b/src/com/android/settings/cmstats/PreviewData.java deleted file mode 100644 index 0adacad39..000000000 --- a/src/com/android/settings/cmstats/PreviewData.java +++ /dev/null @@ -1,55 +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.cmstats; - -import android.content.Context; -import android.os.Bundle; -import android.preference.Preference; -import android.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import org.cyanogenmod.internal.logging.CMMetricsLogger; - -public class PreviewData extends SettingsPreferenceFragment { - private static final String UNIQUE_ID = "preview_id"; - private static final String DEVICE = "preview_device"; - private static final String VERSION = "preview_version"; - private static final String COUNTRY = "preview_country"; - private static final String CARRIER = "preview_carrier"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.preview_data); - - final PreferenceScreen prefSet = getPreferenceScreen(); - final Context context = getActivity(); - - prefSet.findPreference(UNIQUE_ID).setSummary(Utilities.getUniqueID(context)); - prefSet.findPreference(DEVICE).setSummary(Utilities.getDevice()); - prefSet.findPreference(VERSION).setSummary(Utilities.getModVersion()); - prefSet.findPreference(COUNTRY).setSummary(Utilities.getCountryCode(context)); - prefSet.findPreference(CARRIER).setSummary(Utilities.getCarrier(context)); - } - - @Override - protected int getMetricsCategory() { - return CMMetricsLogger.PREVIEW_DATA; - } -} diff --git a/src/com/android/settings/cmstats/ReportingService.java b/src/com/android/settings/cmstats/ReportingService.java deleted file mode 100644 index f04786d95..000000000 --- a/src/com/android/settings/cmstats/ReportingService.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2015 The CyanogenMod Project - * (C) 2017 The LineageOS 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.cmstats; - -import android.app.IntentService; -import android.app.job.JobInfo; -import android.app.job.JobScheduler; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.os.PersistableBundle; -import android.os.UserHandle; -import android.util.Log; -import cyanogenmod.providers.CMSettings; - -import java.util.List; - -public class ReportingService extends IntentService { - /* package */ static final String TAG = "CMStats"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - public ReportingService() { - super(ReportingService.class.getSimpleName()); - } - - @Override - protected void onHandleIntent(Intent intent) { - JobScheduler js = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); - - String deviceId = Utilities.getUniqueID(getApplicationContext()); - String deviceName = Utilities.getDevice(); - String deviceVersion = Utilities.getModVersion(); - String deviceCountry = Utilities.getCountryCode(getApplicationContext()); - String deviceCarrier = Utilities.getCarrier(getApplicationContext()); - String deviceCarrierId = Utilities.getCarrierId(getApplicationContext()); - - final int cmOrgJobId = AnonymousStats.getNextJobId(getApplicationContext()); - - if (DEBUG) Log.d(TAG, "scheduling job id: " + cmOrgJobId); - - PersistableBundle cmBundle = new PersistableBundle(); - cmBundle.putString(StatsUploadJobService.KEY_DEVICE_NAME, deviceName); - cmBundle.putString(StatsUploadJobService.KEY_UNIQUE_ID, deviceId); - cmBundle.putString(StatsUploadJobService.KEY_VERSION, deviceVersion); - cmBundle.putString(StatsUploadJobService.KEY_COUNTRY, deviceCountry); - cmBundle.putString(StatsUploadJobService.KEY_CARRIER, deviceCarrier); - cmBundle.putString(StatsUploadJobService.KEY_CARRIER_ID, deviceCarrierId); - cmBundle.putLong(StatsUploadJobService.KEY_TIMESTAMP, System.currentTimeMillis()); - - // set job types - cmBundle.putInt(StatsUploadJobService.KEY_JOB_TYPE, - StatsUploadJobService.JOB_TYPE_CMORG); - - // schedule cmorg stats upload - js.schedule(new JobInfo.Builder(cmOrgJobId, new ComponentName(getPackageName(), - StatsUploadJobService.class.getName())) - .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) - .setMinimumLatency(1000) - .setExtras(cmBundle) - .setPersisted(true) - .build()); - - // reschedule - AnonymousStats.updateLastSynced(this); - ReportingServiceManager.setAlarm(this); - } -} diff --git a/src/com/android/settings/cmstats/ReportingServiceManager.java b/src/com/android/settings/cmstats/ReportingServiceManager.java deleted file mode 100644 index 286618ce0..000000000 --- a/src/com/android/settings/cmstats/ReportingServiceManager.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2012 The CyanogenMod Project - * (C) 2017 The LineageOS 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.cmstats; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.job.JobScheduler; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.UserHandle; -import android.util.Log; -import cyanogenmod.providers.CMSettings; - -public class ReportingServiceManager extends BroadcastReceiver { - private static final long MILLIS_PER_HOUR = 60L * 60L * 1000L; - private static final long MILLIS_PER_DAY = 24L * MILLIS_PER_HOUR; - private static final long UPDATE_INTERVAL = 1L * MILLIS_PER_DAY; - - private static final String TAG = ReportingServiceManager.class.getSimpleName(); - - public static final String ACTION_LAUNCH_SERVICE = - "com.android.settings.action.TRIGGER_REPORT_METRICS"; - public static final String EXTRA_FORCE = "force"; - - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { - setAlarm(context); - } else if (intent.getAction().equals(ACTION_LAUNCH_SERVICE)){ - launchService(context, intent.getBooleanExtra(EXTRA_FORCE, false)); - } - } - - public static void setAlarm(Context context) { - SharedPreferences prefs = AnonymousStats.getPreferences(context); - if (prefs.contains(AnonymousStats.ANONYMOUS_OPT_IN)) { - migrate(context, prefs); - } - if (!Utilities.isStatsCollectionEnabled(context)) { - return; - } - long lastSynced = prefs.getLong(AnonymousStats.ANONYMOUS_LAST_CHECKED, 0); - if (lastSynced == 0) { - launchService(context, true); // service will reschedule the next alarm - return; - } - long millisFromNow = (lastSynced + UPDATE_INTERVAL) - System.currentTimeMillis(); - - Intent intent = new Intent(ACTION_LAUNCH_SERVICE); - intent.setClass(context, ReportingServiceManager.class); - - AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + millisFromNow, - PendingIntent.getBroadcast(context, 0, intent, 0)); - Log.d(TAG, "Next sync attempt in : " - + (millisFromNow / MILLIS_PER_HOUR) + " hours"); - } - - public static void launchService(Context context, boolean force) { - SharedPreferences prefs = AnonymousStats.getPreferences(context); - - if (!Utilities.isStatsCollectionEnabled(context)) { - return; - } - - if (!force) { - long lastSynced = prefs.getLong(AnonymousStats.ANONYMOUS_LAST_CHECKED, 0); - if (lastSynced == 0) { - setAlarm(context); - return; - } - long timeElapsed = System.currentTimeMillis() - lastSynced; - if (timeElapsed < UPDATE_INTERVAL) { - long timeLeft = UPDATE_INTERVAL - timeElapsed; - Log.d(TAG, "Waiting for next sync : " - + timeLeft / MILLIS_PER_HOUR + " hours"); - return; - } - } - - Intent intent = new Intent(); - intent.setClass(context, ReportingService.class); - context.startServiceAsUser(intent, UserHandle.OWNER); - } - - private static void migrate(Context context, SharedPreferences prefs) { - Utilities.setStatsCollectionEnabled(context, - prefs.getBoolean(AnonymousStats.ANONYMOUS_OPT_IN, true)); - prefs.edit().remove(AnonymousStats.ANONYMOUS_OPT_IN).commit(); - } - -} diff --git a/src/com/android/settings/cmstats/StatsUploadJobService.java b/src/com/android/settings/cmstats/StatsUploadJobService.java deleted file mode 100644 index c84e1a19a..000000000 --- a/src/com/android/settings/cmstats/StatsUploadJobService.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2015 The CyanogenMod Project - * (C) 2017 The LineageOS 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.cmstats; - -import android.app.job.JobParameters; -import android.app.job.JobService; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.PersistableBundle; -import android.util.ArrayMap; -import android.util.Log; -import com.android.settings.R; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Collections; -import java.util.Map; - -public class StatsUploadJobService extends JobService { - - private static final String TAG = StatsUploadJobService.class.getSimpleName(); - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - public static final String KEY_JOB_TYPE = "job_type"; - public static final int JOB_TYPE_CMORG = 1; - - public static final String KEY_UNIQUE_ID = "uniqueId"; - public static final String KEY_DEVICE_NAME = "deviceName"; - public static final String KEY_VERSION = "version"; - public static final String KEY_COUNTRY = "country"; - public static final String KEY_CARRIER = "carrier"; - public static final String KEY_CARRIER_ID = "carrierId"; - public static final String KEY_TIMESTAMP = "timeStamp"; - - private final Map<JobParameters, StatsUploadTask> mCurrentJobs - = Collections.synchronizedMap(new ArrayMap<JobParameters, StatsUploadTask>()); - - @Override - public boolean onStartJob(JobParameters jobParameters) { - if (DEBUG) - Log.d(TAG, "onStartJob() called with " + "jobParameters = [" + jobParameters + "]"); - - if (!Utilities.isStatsCollectionEnabled(this)) { - return false; - } - - final StatsUploadTask uploadTask = new StatsUploadTask(jobParameters); - mCurrentJobs.put(jobParameters, uploadTask); - uploadTask.execute((Void) null); - return true; - } - - @Override - public boolean onStopJob(JobParameters jobParameters) { - if (DEBUG) - Log.d(TAG, "onStopJob() called with " + "jobParameters = [" + jobParameters + "]"); - - final StatsUploadTask cancelledJob; - cancelledJob = mCurrentJobs.remove(jobParameters); - - if (cancelledJob != null) { - // cancel the ongoing background task - cancelledJob.cancel(true); - return true; // reschedule - } - - return false; - } - - private class StatsUploadTask extends AsyncTask<Void, Void, Boolean> { - - private JobParameters mJobParams; - - public StatsUploadTask(JobParameters jobParams) { - this.mJobParams = jobParams; - } - - @Override - protected Boolean doInBackground(Void... params) { - - PersistableBundle extras = mJobParams.getExtras(); - - String deviceId = extras.getString(KEY_UNIQUE_ID); - String deviceName = extras.getString(KEY_DEVICE_NAME); - String deviceVersion = extras.getString(KEY_VERSION); - String deviceCountry = extras.getString(KEY_COUNTRY); - String deviceCarrier = extras.getString(KEY_CARRIER); - String deviceCarrierId = extras.getString(KEY_CARRIER_ID); - long timeStamp = extras.getLong(KEY_TIMESTAMP); - - boolean success = false; - int jobType = extras.getInt(KEY_JOB_TYPE, -1); - if (!isCancelled()) { - switch (jobType) { - case JOB_TYPE_CMORG: - try { - JSONObject json = buildStatsRequest(deviceId, deviceName, - deviceVersion, deviceCountry, deviceCarrier, deviceCarrierId); - success = uploadToCM(json); - } catch (IOException | JSONException e) { - Log.e(TAG, "Could not upload stats checkin to community server", e); - success = false; - } - break; - } - } - if (DEBUG) - Log.d(TAG, "job id " + mJobParams.getJobId() + ", has finished with success=" - + success); - return success; - } - - @Override - protected void onPostExecute(Boolean success) { - mCurrentJobs.remove(mJobParams); - jobFinished(mJobParams, !success); - } - } - - private JSONObject buildStatsRequest(String deviceId, String deviceName, String deviceVersion, - String deviceCountry, String deviceCarrier, - String deviceCarrierId) throws JSONException { - JSONObject request = new JSONObject(); - request.put("device_hash", deviceId); - request.put("device_name", deviceName); - request.put("device_version", deviceVersion); - request.put("device_country", deviceCountry); - request.put("device_carrier", deviceCarrier); - request.put("device_carrier_id", deviceCarrierId); - return request; - } - - private boolean uploadToCM(JSONObject json) throws IOException { - final Uri uri = Uri.parse(getString(R.string.stats_cm_url)); - URL url = new URL(uri.toString()); - HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); - try { - urlConnection.setInstanceFollowRedirects(true); - urlConnection.setDoOutput(true); - urlConnection.setDoInput(true); - urlConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); - - OutputStream os = urlConnection.getOutputStream(); - os.write(json.toString().getBytes("UTF-8")); - os.close(); - - final int responseCode = urlConnection.getResponseCode(); - if (DEBUG) Log.d(TAG, "cm server response code=" + responseCode); - final boolean success = responseCode == HttpURLConnection.HTTP_OK; - if (!success) { - Log.w(TAG, "failed sending, server returned: " + getResponse(urlConnection, - !success)); - } - return success; - } finally { - urlConnection.disconnect(); - } - - } - - private String getResponse(HttpURLConnection httpUrlConnection, boolean errorStream) - throws IOException { - InputStream responseStream = new BufferedInputStream(errorStream - ? httpUrlConnection.getErrorStream() - : httpUrlConnection.getInputStream()); - - BufferedReader responseStreamReader = new BufferedReader( - new InputStreamReader(responseStream)); - String line = ""; - StringBuilder stringBuilder = new StringBuilder(); - while ((line = responseStreamReader.readLine()) != null) { - stringBuilder.append(line).append("\n"); - } - responseStreamReader.close(); - responseStream.close(); - - return stringBuilder.toString(); - } - -} diff --git a/src/com/android/settings/cmstats/Utilities.java b/src/com/android/settings/cmstats/Utilities.java deleted file mode 100644 index f69e8ca93..000000000 --- a/src/com/android/settings/cmstats/Utilities.java +++ /dev/null @@ -1,102 +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.cmstats; - -import android.content.Context; -import android.os.Build; -import android.os.SystemProperties; -import android.provider.Settings; -import android.telephony.TelephonyManager; -import android.text.TextUtils; - -import cyanogenmod.providers.CMSettings; - -import java.math.BigInteger; -import java.net.NetworkInterface; -import java.security.MessageDigest; - -public class Utilities { - public static String getUniqueID(Context context) { - final String id = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); - return digest(context.getPackageName() + id); - } - - public static String getCarrier(Context context) { - TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - String carrier = tm.getNetworkOperatorName(); - if (TextUtils.isEmpty(carrier)) { - carrier = "Unknown"; - } - return carrier; - } - - public static String getCarrierId(Context context) { - TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - String carrierId = tm.getNetworkOperator(); - if (TextUtils.isEmpty(carrierId)) { - carrierId = "0"; - } - return carrierId; - } - - public static String getCountryCode(Context context) { - TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - String countryCode = tm.getNetworkCountryIso(); - if (TextUtils.isEmpty(countryCode)) { - countryCode = "Unknown"; - } - return countryCode; - } - - public static String getDevice() { - return SystemProperties.get("ro.cm.device", Build.PRODUCT); - } - - public static String getModVersion() { - return SystemProperties.get("ro.cm.version", Build.DISPLAY); - } - - public static String digest(String input) { - try { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - return new BigInteger(1, md.digest(input.getBytes())).toString(16).toUpperCase(); - } catch (Exception e) { - return null; - } - } - - /** - * Check to see if global stats are enabled. - * @param context - * @return Whether or not stats collection is enabled. - */ - public static boolean isStatsCollectionEnabled(Context context) { - return CMSettings.Secure.getInt(context.getContentResolver(), - CMSettings.Secure.STATS_COLLECTION, 1) != 0; - } - - /** - * Enabled or disable stats collection - * @param context - * @param enabled Boolean that sets collection being enabled. - */ - public static void setStatsCollectionEnabled(Context context, boolean enabled) { - int enable = (enabled) ? 1 : 0; - CMSettings.Secure.putInt(context.getContentResolver(), - CMSettings.Secure.STATS_COLLECTION, enable); - } -} |