Merge "Import translations. DO NOT MERGE ANYWHERE" into sc-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 46eaaaf..88d2f1a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1132,6 +1132,8 @@
<string name="puk2_blocked">PUK2 is permanently blocked.</string>
<!-- SIM PIN2 screen: error message -->
<string name="pin2_attempts">\nYou have <xliff:g id="number">%d</xliff:g> remaining attempts.</string>
+ <!-- SIM PIN2 screen: error message displayed in a dialog -->
+ <string name="puk2_locked">PUK2 locked. Contact service provider to unlock.</string>
<!-- SIM PIN screen: status message displayed in a popup (toast) -->
<string name="pin2_unblocked">PIN2 no longer blocked</string>
<!-- SIM PIN screen: error message shown in dialog when there is a network or sim error.
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index efd2f1b..2b91a24 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -321,13 +321,13 @@
@Override
public void onReceiveResult(int resultCode, Bundle resultData) {
unbindIfBound(mContext, conn, phoneId);
+ removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT,
+ getMessageToken(phoneId));
// If new service connection has been created, this is stale.
if (mServiceConnection[phoneId] != conn) {
loge("Received response for stale request.");
return;
}
- removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT,
- getMessageToken(phoneId));
if (resultCode == RESULT_ERROR || resultData == null) {
// On error, abort config fetching.
loge("Failed to get carrier config");
@@ -451,13 +451,13 @@
@Override
public void onReceiveResult(int resultCode, Bundle resultData) {
unbindIfBound(mContext, conn, phoneId);
+ removeMessages(EVENT_FETCH_CARRIER_TIMEOUT,
+ getMessageToken(phoneId));
// If new service connection has been created, this is stale.
if (mServiceConnection[phoneId] != conn) {
loge("Received response for stale request.");
return;
}
- removeMessages(EVENT_FETCH_CARRIER_TIMEOUT,
- getMessageToken(phoneId));
if (resultCode == RESULT_ERROR || resultData == null) {
// On error, abort config fetching.
loge("Failed to get carrier config from carrier app: "
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 83d71f1..127e08b 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -6560,8 +6560,9 @@
private int getCarrierPrivilegeStatusFromCarrierConfigRules(int privilegeFromSim, int uid,
Phone phone) {
- if (uid == Process.SYSTEM_UID || uid == Process.PHONE_UID) {
- // Skip the check if it's one of these special uids
+ if (uid == Process.PHONE_UID) {
+ // Skip the check if it's the phone UID (system UID removed in b/184713596)
+ // TODO (b/184954344): Check for system/phone UID at call site instead of here
return TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
}
diff --git a/src/com/android/phone/callcomposer/CallComposerPictureManager.java b/src/com/android/phone/callcomposer/CallComposerPictureManager.java
index 818994a..efb149e 100644
--- a/src/com/android/phone/callcomposer/CallComposerPictureManager.java
+++ b/src/com/android/phone/callcomposer/CallComposerPictureManager.java
@@ -96,7 +96,8 @@
InputStream input,
Executor executor,
OutcomeReceiver<Uri, CallLog.CallComposerLoggingException> callback) {
- CallLog.storeCallComposerPictureAsUser(context, user, input, executor, callback);
+ CallLog.storeCallComposerPicture(context.createContextAsUser(user, 0),
+ input, executor, callback);
}
}
diff --git a/src/com/android/phone/settings/fdn/BaseFdnContactScreen.java b/src/com/android/phone/settings/fdn/BaseFdnContactScreen.java
new file mode 100644
index 0000000..5beff34
--- /dev/null
+++ b/src/com/android/phone/settings/fdn/BaseFdnContactScreen.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2020 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.phone.settings.fdn;
+
+import static android.view.Window.PROGRESS_VISIBILITY_OFF;
+import static android.view.Window.PROGRESS_VISIBILITY_ON;
+
+import android.app.Activity;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.AsyncQueryHandler;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.AsyncResult;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.Window;
+import android.widget.Toast;
+
+import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.Phone;
+import com.android.phone.PhoneGlobals;
+import com.android.phone.R;
+import com.android.phone.SubscriptionInfoHelper;
+
+/**
+ * Base activity for FDN contact screen.
+ */
+public abstract class BaseFdnContactScreen extends Activity
+ implements Pin2LockedDialogFragment.Listener {
+ protected static final String LOG_TAG = PhoneGlobals.LOG_TAG;
+ protected static final boolean DBG = false;
+
+ protected static final int EVENT_PIN2_ENTRY_COMPLETE = 10;
+ protected static final int PIN2_REQUEST_CODE = 100;
+
+ protected static final String INTENT_EXTRA_NAME = "name";
+ protected static final String INTENT_EXTRA_NUMBER = "number";
+
+ protected String mName;
+ protected String mNumber;
+ protected String mPin2;
+
+ protected SubscriptionInfoHelper mSubscriptionInfoHelper;
+ protected BaseFdnContactScreen.QueryHandler mQueryHandler;
+
+ protected Handler mHandler = new Handler();
+ protected Phone mPhone;
+
+ protected abstract void pin2AuthenticationSucceed();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ resolveIntent();
+ getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ }
+
+ protected void authenticatePin2() {
+ Intent intent = new Intent();
+ intent.setClass(this, GetPin2Screen.class);
+ intent.setData(FdnList.getContentUri(mSubscriptionInfoHelper));
+ startActivityForResult(intent, PIN2_REQUEST_CODE);
+ }
+
+ protected void displayProgress(boolean flag) {
+ getWindow().setFeatureInt(
+ Window.FEATURE_INDETERMINATE_PROGRESS,
+ flag ? PROGRESS_VISIBILITY_ON : PROGRESS_VISIBILITY_OFF);
+ }
+
+ protected void handleResult(boolean success) {
+ }
+
+ protected void handleResult(boolean success, boolean invalidNumber) {
+ }
+
+ protected void log(String msg) {
+ Log.d(LOG_TAG, getClass().getSimpleName() + " : " + msg);
+ }
+
+ // Add method to check if Pin2 supplied is correct.
+ protected void processPin2(String pin) {
+ Message onComplete = mFDNHandler
+ .obtainMessage(EVENT_PIN2_ENTRY_COMPLETE);
+ mPhone.getIccCard().supplyPin2(pin, onComplete);
+ }
+
+ protected void resolveIntent() {
+ Intent intent = getIntent();
+
+ mSubscriptionInfoHelper = new SubscriptionInfoHelper(this, intent);
+ mPhone = mSubscriptionInfoHelper.getPhone();
+
+ mName = intent.getStringExtra(INTENT_EXTRA_NAME);
+ mNumber = intent.getStringExtra(INTENT_EXTRA_NUMBER);
+ }
+
+ /**
+ * Removed the status field, with preference to displaying a toast
+ * to match the rest of settings UI.
+ */
+ protected void showStatus(CharSequence statusMsg) {
+ if (statusMsg != null) {
+ Toast.makeText(this, statusMsg, Toast.LENGTH_LONG).show();
+ }
+ }
+
+ private Handler mFDNHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_PIN2_ENTRY_COMPLETE:
+ AsyncResult ar = (AsyncResult) msg.obj;
+ if (ar.exception != null) {
+ // see if PUK2 is requested and alert the user accordingly.
+ CommandException ce = (CommandException) ar.exception;
+ if (ce.getCommandError() == CommandException.Error.SIM_PUK2) {
+ // make sure we set the PUK2 state so that we can skip some
+ // redundant behaviour.
+ showPin2LockedDialog();
+ } else {
+ final int attemptsRemaining = msg.arg1;
+ if (attemptsRemaining > 0) {
+ Toast.makeText(
+ BaseFdnContactScreen.this,
+ getString(R.string.pin2_invalid)
+ + getString(R.string.pin2_attempts,
+ attemptsRemaining), Toast.LENGTH_LONG)
+ .show();
+ finish();
+ }
+ }
+ } else {
+ pin2AuthenticationSucceed();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ protected class QueryHandler extends AsyncQueryHandler {
+ protected QueryHandler(ContentResolver cr) {
+ super(cr);
+ }
+
+ @Override
+ protected void onInsertComplete(int token, Object cookie, Uri uri) {
+ if (DBG) log("onInsertComplete");
+ displayProgress(false);
+ handleResult(uri != null, false);
+ }
+
+ @Override
+ protected void onUpdateComplete(int token, Object cookie, int result) {
+ if (DBG) log("onUpdateComplete");
+ displayProgress(false);
+ handleResult(result > 0, false);
+ }
+
+ @Override
+ protected void onDeleteComplete(int token, Object cookie, int result) {
+ if (DBG) log("onDeleteComplete");
+ displayProgress(false);
+ handleResult(result > 0);
+ }
+ }
+
+ private void showPin2LockedDialog() {
+ final FragmentManager fragmentManager = getFragmentManager();
+ Pin2LockedDialogFragment dialogFragment = (Pin2LockedDialogFragment) fragmentManager
+ .findFragmentByTag(Pin2LockedDialogFragment.TAG_PIN2_LOCKED_DIALOG);
+ if (dialogFragment == null) {
+ dialogFragment = new Pin2LockedDialogFragment();
+ Bundle args = new Bundle();
+ args.putInt(Pin2LockedDialogFragment.KEY_DIALOG_ID,
+ Pin2LockedDialogFragment.DIALOG_ID_PUK2_REQUESTED_ON_PIN_ENTRY);
+ dialogFragment.setArguments(args);
+ dialogFragment.show(fragmentManager, Pin2LockedDialogFragment.TAG_PIN2_LOCKED_DIALOG);
+ } else {
+ FragmentTransaction transaction = fragmentManager.beginTransaction();
+ transaction.show(dialogFragment);
+ transaction.commitNow();
+ }
+ }
+
+ @Override
+ public void onRequestPuk2(int id) {
+ finish();
+ }
+}
diff --git a/src/com/android/phone/settings/fdn/DeleteFdnContactScreen.java b/src/com/android/phone/settings/fdn/DeleteFdnContactScreen.java
index 8b17cfb..7cd4c93 100644
--- a/src/com/android/phone/settings/fdn/DeleteFdnContactScreen.java
+++ b/src/com/android/phone/settings/fdn/DeleteFdnContactScreen.java
@@ -16,58 +16,24 @@
package com.android.phone.settings.fdn;
-import static android.view.Window.PROGRESS_VISIBILITY_OFF;
-import static android.view.Window.PROGRESS_VISIBILITY_ON;
-
-import android.app.Activity;
-import android.content.AsyncQueryHandler;
-import android.content.ContentResolver;
import android.content.Intent;
-import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
import android.text.TextUtils;
-import android.util.Log;
-import android.view.Window;
-import android.widget.Toast;
-import com.android.phone.PhoneGlobals;
import com.android.phone.R;
-import com.android.phone.SubscriptionInfoHelper;
/**
* Activity to let the user delete an FDN contact.
*/
-public class DeleteFdnContactScreen extends Activity {
- private static final String LOG_TAG = PhoneGlobals.LOG_TAG;
- private static final boolean DBG = false;
-
- private static final String INTENT_EXTRA_NAME = "name";
- private static final String INTENT_EXTRA_NUMBER = "number";
-
- private static final int PIN2_REQUEST_CODE = 100;
-
- private SubscriptionInfoHelper mSubscriptionInfoHelper;
-
- private String mName;
- private String mNumber;
- private String mPin2;
-
- protected QueryHandler mQueryHandler;
-
- private Handler mHandler = new Handler();
+public class DeleteFdnContactScreen extends BaseFdnContactScreen {
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
- resolveIntent();
-
// Starts PIN2 authentication only for the first time.
if (icicle == null) authenticatePin2();
-
- getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.delete_fdn_contact_screen);
}
@@ -80,9 +46,7 @@
Bundle extras = (intent != null) ? intent.getExtras() : null;
if (extras != null) {
mPin2 = extras.getString("pin2");
- showStatus(getResources().getText(
- R.string.deleting_fdn_contact));
- deleteContact();
+ processPin2(mPin2);
} else {
// if they cancelled, then we just cancel too.
if (DBG) log("onActivityResult: CANCELLED");
@@ -93,13 +57,9 @@
}
}
- private void resolveIntent() {
- Intent intent = getIntent();
-
- mSubscriptionInfoHelper = new SubscriptionInfoHelper(this, intent);
-
- mName = intent.getStringExtra(INTENT_EXTRA_NAME);
- mNumber = intent.getStringExtra(INTENT_EXTRA_NUMBER);
+ @Override
+ protected void resolveIntent() {
+ super.resolveIntent();
if (TextUtils.isEmpty(mNumber)) {
finish();
@@ -127,29 +87,8 @@
displayProgress(true);
}
- private void authenticatePin2() {
- Intent intent = new Intent();
- intent.setClass(this, GetPin2Screen.class);
- intent.setData(FdnList.getContentUri(mSubscriptionInfoHelper));
- startActivityForResult(intent, PIN2_REQUEST_CODE);
- }
-
- private void displayProgress(boolean flag) {
- getWindow().setFeatureInt(
- Window.FEATURE_INDETERMINATE_PROGRESS,
- flag ? PROGRESS_VISIBILITY_ON : PROGRESS_VISIBILITY_OFF);
- }
-
- // Replace the status field with a toast to make things appear similar
- // to the rest of the settings. Removed the useless status field.
- private void showStatus(CharSequence statusMsg) {
- if (statusMsg != null) {
- Toast.makeText(this, statusMsg, Toast.LENGTH_SHORT)
- .show();
- }
- }
-
- private void handleResult(boolean success) {
+ @Override
+ protected void handleResult(boolean success) {
if (success) {
if (DBG) log("handleResult: success!");
showStatus(getResources().getText(R.string.fdn_contact_deleted));
@@ -157,43 +96,12 @@
if (DBG) log("handleResult: failed!");
showStatus(getResources().getText(R.string.pin2_invalid));
}
-
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- finish();
- }
- }, 2000);
-
+ mHandler.postDelayed(() -> finish(), 2000);
}
- private class QueryHandler extends AsyncQueryHandler {
- public QueryHandler(ContentResolver cr) {
- super(cr);
- }
-
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor c) {
- }
-
- @Override
- protected void onInsertComplete(int token, Object cookie, Uri uri) {
- }
-
- @Override
- protected void onUpdateComplete(int token, Object cookie, int result) {
- }
-
- @Override
- protected void onDeleteComplete(int token, Object cookie, int result) {
- if (DBG) log("onDeleteComplete");
- displayProgress(false);
- handleResult(result > 0);
- }
-
- }
-
- private void log(String msg) {
- Log.d(LOG_TAG, "[DeleteFdnContact] " + msg);
+ @Override
+ protected void pin2AuthenticationSucceed() {
+ showStatus(getResources().getText(R.string.deleting_fdn_contact));
+ deleteContact();
}
}
diff --git a/src/com/android/phone/settings/fdn/EditFdnContactScreen.java b/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
index 140cc74..468d38f 100644
--- a/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
+++ b/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
@@ -16,21 +16,18 @@
package com.android.phone.settings.fdn;
-import static android.view.Window.PROGRESS_VISIBILITY_OFF;
-import static android.view.Window.PROGRESS_VISIBILITY_ON;
-import android.app.Activity;
-import android.content.AsyncQueryHandler;
-import android.content.ContentResolver;
+import static android.app.Activity.RESULT_OK;
+
import android.content.ContentValues;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
import android.os.PersistableBundle;
import android.provider.ContactsContract.CommonDataKinds;
+import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
import android.text.Editable;
import android.text.Selection;
@@ -42,50 +39,31 @@
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
-import android.widget.Toast;
import com.android.internal.telephony.PhoneFactory;
import com.android.phone.PhoneGlobals;
import com.android.phone.R;
-import com.android.phone.SubscriptionInfoHelper;
-import android.telephony.CarrierConfigManager;
/**
* Activity to let the user add or edit an FDN contact.
*/
-public class EditFdnContactScreen extends Activity {
- private static final String LOG_TAG = PhoneGlobals.LOG_TAG;
- private static final boolean DBG = false;
+public class EditFdnContactScreen extends BaseFdnContactScreen {
// Menu item codes
private static final int MENU_IMPORT = 1;
private static final int MENU_DELETE = 2;
- private static final String INTENT_EXTRA_NAME = "name";
- private static final String INTENT_EXTRA_NUMBER = "number";
-
- private static final int PIN2_REQUEST_CODE = 100;
-
- private SubscriptionInfoHelper mSubscriptionInfoHelper;
-
- private String mName;
- private String mNumber;
- private String mPin2;
private boolean mAddContact;
- private QueryHandler mQueryHandler;
private EditText mNameField;
private EditText mNumberField;
private LinearLayout mPinFieldContainer;
private Button mButton;
- private Handler mHandler = new Handler();
-
/**
* Constants used in importing from contacts
*/
@@ -108,13 +86,10 @@
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
- resolveIntent();
-
- getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.edit_fdn_contact_screen);
setupView();
setTitle(mAddContact ? R.string.add_fdn_contact : R.string.edit_fdn_contact);
- PersistableBundle b = null;
+ PersistableBundle b;
if (mSubscriptionInfoHelper.hasSubId()) {
b = PhoneGlobals.getInstance().getCarrierConfigForSubId(
mSubscriptionInfoHelper.getSubId());
@@ -145,11 +120,7 @@
Bundle extras = (intent != null) ? intent.getExtras() : null;
if (extras != null) {
mPin2 = extras.getString("pin2");
- if (mAddContact) {
- addContact();
- } else {
- updateContact();
- }
+ processPin2(mPin2);
} else if (resultCode != RESULT_OK) {
// if they cancelled, then we just cancel too.
if (DBG) log("onActivityResult: cancelled.");
@@ -231,20 +202,15 @@
return super.onOptionsItemSelected(item);
}
- private void resolveIntent() {
- Intent intent = getIntent();
-
- mSubscriptionInfoHelper = new SubscriptionInfoHelper(this, intent);
-
- mName = intent.getStringExtra(INTENT_EXTRA_NAME);
- mNumber = intent.getStringExtra(INTENT_EXTRA_NUMBER);
-
+ @Override
+ protected void resolveIntent() {
+ super.resolveIntent();
mAddContact = TextUtils.isEmpty(mNumber);
}
/**
* We have multiple layouts, one to indicate that the user needs to
- * open the keyboard to enter information (if the keybord is hidden).
+ * open the keyboard to enter information (if the keyboard is hidden).
* So, we need to make sure that the layout here matches that in the
* layout file.
*/
@@ -374,36 +340,18 @@
finish();
}
- private void authenticatePin2() {
- Intent intent = new Intent();
- intent.setClass(this, GetPin2Screen.class);
- intent.setData(FdnList.getContentUri(mSubscriptionInfoHelper));
- startActivityForResult(intent, PIN2_REQUEST_CODE);
- }
-
- private void displayProgress(boolean flag) {
+ @Override
+ protected void displayProgress(boolean flag) {
+ super.displayProgress(flag);
// indicate we are busy.
mDataBusy = flag;
- getWindow().setFeatureInt(
- Window.FEATURE_INDETERMINATE_PROGRESS,
- mDataBusy ? PROGRESS_VISIBILITY_ON : PROGRESS_VISIBILITY_OFF);
// make sure we don't allow calls to save when we're
// not ready for them.
mButton.setClickable(!mDataBusy);
}
- /**
- * Removed the status field, with preference to displaying a toast
- * to match the rest of settings UI.
- */
- private void showStatus(CharSequence statusMsg) {
- if (statusMsg != null) {
- Toast.makeText(this, statusMsg, Toast.LENGTH_LONG)
- .show();
- }
- }
-
- private void handleResult(boolean success, boolean invalidNumber) {
+ @Override
+ protected void handleResult(boolean success, boolean invalidNumber) {
if (success) {
if (DBG) log("handleResult: success!");
showStatus(getResources().getText(mAddContact ?
@@ -426,13 +374,7 @@
}
}
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- finish();
- }
- }, 2000);
-
+ mHandler.postDelayed(() -> finish(), 2000);
}
private final View.OnClickListener mClicked = new View.OnClickListener() {
@@ -486,35 +428,12 @@
}
};
- private class QueryHandler extends AsyncQueryHandler {
- public QueryHandler(ContentResolver cr) {
- super(cr);
+ @Override
+ protected void pin2AuthenticationSucceed() {
+ if (mAddContact) {
+ addContact();
+ } else {
+ updateContact();
}
-
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor c) {
- }
-
- @Override
- protected void onInsertComplete(int token, Object cookie, Uri uri) {
- if (DBG) log("onInsertComplete");
- displayProgress(false);
- handleResult(uri != null, false);
- }
-
- @Override
- protected void onUpdateComplete(int token, Object cookie, int result) {
- if (DBG) log("onUpdateComplete");
- displayProgress(false);
- handleResult(result > 0, false);
- }
-
- @Override
- protected void onDeleteComplete(int token, Object cookie, int result) {
- }
- }
-
- private void log(String msg) {
- Log.d(LOG_TAG, "[EditFdnContact] " + msg);
}
}
diff --git a/src/com/android/phone/settings/fdn/FdnSetting.java b/src/com/android/phone/settings/fdn/FdnSetting.java
index 8b5afa4..8f46c85 100644
--- a/src/com/android/phone/settings/fdn/FdnSetting.java
+++ b/src/com/android/phone/settings/fdn/FdnSetting.java
@@ -17,8 +17,8 @@
package com.android.phone.settings.fdn;
import android.app.ActionBar;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
@@ -27,7 +27,6 @@
import android.preference.PreferenceScreen;
import android.util.Log;
import android.view.MenuItem;
-import android.view.WindowManager;
import android.widget.Toast;
import com.android.internal.telephony.CommandException;
@@ -42,7 +41,7 @@
* Rewritten to look and behave closer to the other preferences.
*/
public class FdnSetting extends PreferenceActivity
- implements EditPinPreference.OnPinEnteredListener, DialogInterface.OnCancelListener {
+ implements EditPinPreference.OnPinEnteredListener, Pin2LockedDialogFragment.Listener {
private static final String LOG_TAG = PhoneGlobals.LOG_TAG;
private static final boolean DBG = false;
@@ -56,6 +55,7 @@
*/
private static final int EVENT_PIN2_ENTRY_COMPLETE = 100;
private static final int EVENT_PIN2_CHANGE_COMPLETE = 200;
+ private static final int EVENT_PIN2_CHANGE_COMPLETE_TOGGLE_FDN = 300;
// String keys for preference lookup
private static final String BUTTON_FDN_ENABLE_KEY = "button_fdn_enable_key";
@@ -82,8 +82,11 @@
private static final String PIN_CHANGE_STATE_KEY = "pin_change_state_key";
private static final String OLD_PIN_KEY = "old_pin_key";
private static final String NEW_PIN_KEY = "new_pin_key";
+ private static final String PUK_KEY = "puk_key";
private static final String DIALOG_MESSAGE_KEY = "dialog_message_key";
private static final String DIALOG_PIN_ENTRY_KEY = "dialog_pin_entry_key";
+ private static final String FDN_DIALOG_MESSAGE_KEY = "fdn_dialog_message_key";
+ private static final String FDN_DIALOG_PIN_ENTRY_KEY = "fdn_dialog_pin_entry_key";
// size limits for the pin.
private static final int MIN_PIN_LENGTH = 4;
@@ -94,10 +97,10 @@
*/
@Override
public void onPinEntered(EditPinPreference preference, boolean positiveResult) {
- if (preference == mButtonEnableFDN) {
+ if (preference == mButtonEnableFDN && (!mIsPuk2Locked || !positiveResult)) {
toggleFDNEnable(positiveResult);
- } else if (preference == mButtonChangePin2){
- updatePINChangeState(positiveResult);
+ } else {
+ updatePINChangeState(preference, positiveResult);
}
}
@@ -106,6 +109,12 @@
*/
private void toggleFDNEnable(boolean positiveResult) {
if (!positiveResult) {
+ // reset the state on cancel, either to expect PUK2 or PIN2
+ if (!mIsPuk2Locked) {
+ resetPinChangeState();
+ } else {
+ resetPinChangeStateForPUK2();
+ }
return;
}
@@ -129,10 +138,10 @@
/**
* Attempt to change the pin.
*/
- private void updatePINChangeState(boolean positiveResult) {
+ private void updatePINChangeState(EditPinPreference button, boolean positiveResult) {
if (DBG) log("updatePINChangeState positive=" + positiveResult
+ " mPinChangeState=" + mPinChangeState
- + " mSkipOldPin=" + mIsPuk2Locked);
+ + " mIsPuk2Locked=" + mIsPuk2Locked);
if (!positiveResult) {
// reset the state on cancel, either to expect PUK2 or PIN2
@@ -155,80 +164,95 @@
// appears with text to indicate what the issue is.
switch (mPinChangeState) {
case PIN_CHANGE_OLD:
- mOldPin = mButtonChangePin2.getText();
- mButtonChangePin2.setText("");
+ mOldPin = button.getText();
+ button.setText("");
// if the pin is not valid, display a message and reset the state.
if (validatePin (mOldPin, false)) {
mPinChangeState = PIN_CHANGE_NEW;
- displayPinChangeDialog();
+ displayPinChangeDialog(button);
} else {
- displayPinChangeDialog(R.string.invalidPin2, true);
+ displayPinChangeDialog(button, R.string.invalidPin2, true);
}
break;
case PIN_CHANGE_NEW:
- mNewPin = mButtonChangePin2.getText();
- mButtonChangePin2.setText("");
+ mNewPin = button.getText();
+ button.setText("");
// if the new pin is not valid, display a message and reset the state.
if (validatePin (mNewPin, false)) {
mPinChangeState = PIN_CHANGE_REENTER;
- displayPinChangeDialog();
+ displayPinChangeDialog(button);
} else {
- displayPinChangeDialog(R.string.invalidPin2, true);
+ displayPinChangeDialog(button, R.string.invalidPin2, true);
}
break;
case PIN_CHANGE_REENTER:
- // if the re-entered pin is not valid, display a message and reset the state.
- if (!mNewPin.equals(mButtonChangePin2.getText())) {
- mPinChangeState = PIN_CHANGE_NEW;
- mButtonChangePin2.setText("");
- displayPinChangeDialog(R.string.mismatchPin2, true);
+ if (validatePin(button.getText(), false)) {
+ // if the re-entered pin is not valid, display a message and reset the state.
+ if (!mNewPin.equals(button.getText())) {
+ mPinChangeState = PIN_CHANGE_NEW;
+ button.setText("");
+ displayPinChangeDialog(button, R.string.mismatchPin2, true);
+ } else {
+ // If the PIN is valid, then we submit the change PIN request or
+ // display the PUK2 dialog if we KNOW that we're PUK2 locked.
+ button.setText("");
+ Message onComplete = mFDNHandler.obtainMessage(
+ EVENT_PIN2_CHANGE_COMPLETE);
+ if (!mIsPuk2Locked) {
+ mPhone.getIccCard().changeIccFdnPassword(mOldPin,
+ mNewPin, onComplete);
+ } else {
+ mPhone.getIccCard().supplyPuk2(mPuk2, mNewPin,
+ onComplete);
+ }
+ }
} else {
- // If the PIN is valid, then we submit the change PIN request.
- mButtonChangePin2.setText("");
- Message onComplete = mFDNHandler.obtainMessage(
- EVENT_PIN2_CHANGE_COMPLETE);
- mPhone.getIccCard().changeIccFdnPassword(
- mOldPin, mNewPin, onComplete);
+ button.setText("");
+ displayPinChangeDialog(button, R.string.invalidPin2, true);
}
break;
- case PIN_CHANGE_PUK: {
- // Doh! too many incorrect requests, PUK requested.
- mPuk2 = mButtonChangePin2.getText();
- mButtonChangePin2.setText("");
- // if the puk is not valid, display
- // a message and reset the state.
- if (validatePin (mPuk2, true)) {
- mPinChangeState = PIN_CHANGE_NEW_PIN_FOR_PUK;
- displayPinChangeDialog();
- } else {
- displayPinChangeDialog(R.string.invalidPuk2, true);
- }
+ case PIN_CHANGE_PUK:
+ // Doh! too many incorrect requests, PUK requested.
+ mPuk2 = button.getText();
+ button.setText("");
+ // if the puk is not valid, display
+ // a message and reset the state.
+ if (validatePin(mPuk2, true)) {
+ mPinChangeState = PIN_CHANGE_NEW_PIN_FOR_PUK;
+ displayPinChangeDialog(button);
+ } else {
+ displayPinChangeDialog(button, R.string.invalidPuk2, true);
}
break;
case PIN_CHANGE_NEW_PIN_FOR_PUK:
- mNewPin = mButtonChangePin2.getText();
- mButtonChangePin2.setText("");
+ mNewPin = button.getText();
+ button.setText("");
// if the new pin is not valid, display
// a message and reset the state.
if (validatePin (mNewPin, false)) {
mPinChangeState = PIN_CHANGE_REENTER_PIN_FOR_PUK;
- displayPinChangeDialog();
+ displayPinChangeDialog(button);
} else {
- displayPinChangeDialog(R.string.invalidPin2, true);
+ displayPinChangeDialog(button, R.string.invalidPin2, true);
}
break;
case PIN_CHANGE_REENTER_PIN_FOR_PUK:
// if the re-entered pin is not valid, display
// a message and reset the state.
- if (!mNewPin.equals(mButtonChangePin2.getText())) {
+ if (!mNewPin.equals(button.getText())) {
mPinChangeState = PIN_CHANGE_NEW_PIN_FOR_PUK;
- mButtonChangePin2.setText("");
- displayPinChangeDialog(R.string.mismatchPin2, true);
+ button.setText("");
+ displayPinChangeDialog(button, R.string.mismatchPin2, true);
} else {
// Both puk2 and new pin2 are ready to submit
- mButtonChangePin2.setText("");
- Message onComplete = mFDNHandler.obtainMessage(
- EVENT_PIN2_CHANGE_COMPLETE);
+ Message onComplete = null;
+ if (button == mButtonChangePin2) {
+ button.setText("");
+ onComplete = mFDNHandler.obtainMessage(EVENT_PIN2_CHANGE_COMPLETE);
+ } else {
+ onComplete = mFDNHandler.obtainMessage(
+ EVENT_PIN2_CHANGE_COMPLETE_TOGGLE_FDN);
+ }
mPhone.getIccCard().supplyPuk2(mPuk2, mNewPin, onComplete);
}
break;
@@ -246,6 +270,7 @@
// when we are enabling FDN, either we are unsuccessful and display
// a toast, or just update the UI.
case EVENT_PIN2_ENTRY_COMPLETE: {
+ if (DBG) log("Handle EVENT_PIN2_ENTRY_COMPLETE");
AsyncResult ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
if (ar.exception instanceof CommandException) {
@@ -255,11 +280,8 @@
((CommandException) ar.exception).getCommandError();
switch (e) {
case SIM_PUK2:
- // make sure we set the PUK2 state so that we can skip
- // some redundant behaviour.
- displayMessage(R.string.fdn_enable_puk2_requested,
- attemptsRemaining);
- resetPinChangeStateForPUK2();
+ showPin2OrPuk2LockedDialog(Pin2LockedDialogFragment
+ .DIALOG_ID_PUK2_REQUESTED_ON_PIN_ENTRY);
break;
case PASSWORD_INCORRECT:
displayMessage(R.string.pin2_invalid, attemptsRemaining);
@@ -279,7 +301,8 @@
// when changing the pin we need to pay attention to whether or not
// the error requests a PUK (usually after too many incorrect tries)
// Set the state accordingly.
- case EVENT_PIN2_CHANGE_COMPLETE: {
+ case EVENT_PIN2_CHANGE_COMPLETE:
+ case EVENT_PIN2_CHANGE_COMPLETE_TOGGLE_FDN: {
if (DBG)
log("Handle EVENT_PIN2_CHANGE_COMPLETE");
AsyncResult ar = (AsyncResult) msg.obj;
@@ -291,34 +314,24 @@
CommandException ce = (CommandException) ar.exception;
if (ce.getCommandError() == CommandException.Error.SIM_PUK2) {
// throw an alert dialog on the screen, displaying the
- // request for a PUK2. set the cancel listener to
- // FdnSetting.onCancel().
- AlertDialog a = new AlertDialog.Builder(FdnSetting.this)
- .setMessage(R.string.puk2_requested)
- .setCancelable(true)
- .setOnCancelListener(FdnSetting.this)
- .setNeutralButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- resetPinChangeStateForPUK2();
- displayPinChangeDialog(0,true);
- }
- })
- .create();
- a.getWindow().addFlags(
- WindowManager.LayoutParams.FLAG_DIM_BEHIND);
- a.show();
+ // request for a PUK2.
+ showPin2OrPuk2LockedDialog(Pin2LockedDialogFragment
+ .DIALOG_ID_PUK2_REQUESTED_ON_PIN_CHANGED);
} else {
- // set the correct error message depending upon the state.
- // Reset the state depending upon or knowledge of the PUK state.
- if (!mIsPuk2Locked) {
- displayMessage(R.string.badPin2, attemptsRemaining);
- resetPinChangeState();
+ if (mIsPuk2Locked && attemptsRemaining == 0) {
+ showPin2OrPuk2LockedDialog(Pin2LockedDialogFragment
+ .DIALOG_ID_PUK2_LOCKED_OUT);
} else {
- displayMessage(R.string.badPuk2, attemptsRemaining);
- resetPinChangeStateForPUK2();
+ // set the correct error message depending upon the state.
+ // Reset the state depending upon or knowledge of the PUK
+ // state.
+ if (!mIsPuk2Locked) {
+ displayMessage(R.string.badPin2, attemptsRemaining);
+ resetPinChangeState();
+ } else {
+ displayMessage(R.string.badPuk2, attemptsRemaining);
+ resetPinChangeStateForPUK2();
+ }
}
}
} else {
@@ -332,28 +345,25 @@
}
// reset to normal behaviour on successful change.
+ if (msg.what == EVENT_PIN2_CHANGE_COMPLETE_TOGGLE_FDN) {
+ log("Handle EVENT_PIN2_CHANGE_COMPLETE_TOGGLE_FDN");
+ // activate/deactivate FDN
+ toggleFDNEnable(true);
+ }
resetPinChangeState();
}
}
+ mButtonChangePin2.setText("");
+ mButtonEnableFDN.setText("");
break;
}
}
};
/**
- * Cancel listener for the PUK2 request alert dialog.
- */
- @Override
- public void onCancel(DialogInterface dialog) {
- // set the state of the preference and then display the dialog.
- resetPinChangeStateForPUK2();
- displayPinChangeDialog(0, true);
- }
-
- /**
* Display a toast for message, like the rest of the settings.
*/
- private final void displayMessage(int strId, int attemptsRemaining) {
+ private void displayMessage(int strId, int attemptsRemaining) {
String s = getString(strId);
if ((strId == R.string.badPin2) || (strId == R.string.badPuk2) ||
(strId == R.string.pin2_invalid)) {
@@ -367,22 +377,27 @@
Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
}
- private final void displayMessage(int strId) {
+ private void displayMessage(int strId) {
displayMessage(strId, -1);
}
/**
* The next two functions are for updating the message field on the dialog.
*/
- private final void displayPinChangeDialog() {
- displayPinChangeDialog(0, true);
+ private void displayPinChangeDialog(EditPinPreference button) {
+ displayPinChangeDialog(button, 0, true);
}
- private final void displayPinChangeDialog(int strId, boolean shouldDisplay) {
+ private void displayPinChangeDialog(EditPinPreference button,
+ int strId, boolean shouldDisplay) {
int msgId;
switch (mPinChangeState) {
case PIN_CHANGE_OLD:
- msgId = R.string.oldPin2Label;
+ if (button == mButtonEnableFDN) {
+ msgId = R.string.enter_pin2_text;
+ } else {
+ msgId = R.string.oldPin2Label;
+ }
break;
case PIN_CHANGE_NEW:
case PIN_CHANGE_NEW_PIN_FOR_PUK:
@@ -400,14 +415,14 @@
// append the note / additional message, if needed.
if (strId != 0) {
- mButtonChangePin2.setDialogMessage(getText(msgId) + "\n" + getText(strId));
+ button.setDialogMessage(getText(msgId) + "\n" + getText(strId));
} else {
- mButtonChangePin2.setDialogMessage(msgId);
+ button.setDialogMessage(msgId);
}
// only display if requested.
if (shouldDisplay) {
- mButtonChangePin2.showPinDialog();
+ button.showPinDialog();
}
}
@@ -417,7 +432,8 @@
private final void resetPinChangeState() {
if (DBG) log("resetPinChangeState");
mPinChangeState = PIN_CHANGE_OLD;
- displayPinChangeDialog(0, false);
+ displayPinChangeDialog(mButtonEnableFDN, 0, false);
+ displayPinChangeDialog(mButtonChangePin2, 0, false);
mOldPin = mNewPin = "";
mIsPuk2Locked = false;
}
@@ -428,7 +444,8 @@
private final void resetPinChangeStateForPUK2() {
if (DBG) log("resetPinChangeStateForPUK2");
mPinChangeState = PIN_CHANGE_PUK;
- displayPinChangeDialog(0, false);
+ displayPinChangeDialog(mButtonEnableFDN, 0, false);
+ displayPinChangeDialog(mButtonChangePin2, 0, false);
mOldPin = mNewPin = mPuk2 = "";
mIsPuk2Locked = true;
}
@@ -472,7 +489,10 @@
* Reflect the updated change PIN2 state in the UI.
*/
private void updateChangePIN2() {
- if (mPhone.getIccCard().getIccPin2Blocked()) {
+ if (mPhone.getIccCard().getIccPuk2Blocked()) {
+ showPin2OrPuk2LockedDialog(Pin2LockedDialogFragment.DIALOG_ID_PUK2_LOCKED_OUT);
+ resetPinChangeStateForPUK2();
+ } else if (mPhone.getIccCard().getIccPin2Blocked()) {
// If the pin2 is blocked, the state of the change pin2 dialog
// should be set for puk2 use (that is, the user should be prompted
// to enter puk2 code instead of old pin2).
@@ -514,8 +534,14 @@
mPinChangeState = icicle.getInt(PIN_CHANGE_STATE_KEY);
mOldPin = icicle.getString(OLD_PIN_KEY);
mNewPin = icicle.getString(NEW_PIN_KEY);
- mButtonChangePin2.setDialogMessage(icicle.getString(DIALOG_MESSAGE_KEY));
- mButtonChangePin2.setText(icicle.getString(DIALOG_PIN_ENTRY_KEY));
+ mPuk2 = icicle.getString(PUK_KEY);
+ mButtonChangePin2.setDialogMessage(
+ icicle.getString(DIALOG_MESSAGE_KEY));
+ mButtonChangePin2.setText(
+ icicle.getString(DIALOG_PIN_ENTRY_KEY));
+ mButtonEnableFDN.setDialogMessage(
+ icicle.getString(FDN_DIALOG_MESSAGE_KEY));
+ mButtonEnableFDN.setText(icicle.getString(FDN_DIALOG_PIN_ENTRY_KEY));
}
ActionBar actionBar = getActionBar();
@@ -545,8 +571,19 @@
out.putInt(PIN_CHANGE_STATE_KEY, mPinChangeState);
out.putString(OLD_PIN_KEY, mOldPin);
out.putString(NEW_PIN_KEY, mNewPin);
- out.putString(DIALOG_MESSAGE_KEY, mButtonChangePin2.getDialogMessage().toString());
- out.putString(DIALOG_PIN_ENTRY_KEY, mButtonChangePin2.getText());
+ out.putString(PUK_KEY, mPuk2);
+ if (mButtonChangePin2.isEnabled()) {
+ out.putString(DIALOG_MESSAGE_KEY, mButtonChangePin2.getDialogMessage().toString());
+ out.putString(DIALOG_PIN_ENTRY_KEY, mButtonChangePin2.getText());
+ }
+ if (mButtonEnableFDN.isEnabled()) {
+ CharSequence dialogMsg = mButtonEnableFDN.getDialogMessage();
+ if (dialogMsg != null) {
+ out.putString(FDN_DIALOG_MESSAGE_KEY,
+ mButtonEnableFDN.getDialogMessage().toString());
+ }
+ out.putString(FDN_DIALOG_PIN_ENTRY_KEY, mButtonEnableFDN.getText());
+ }
}
@Override
@@ -562,5 +599,31 @@
private void log(String msg) {
Log.d(LOG_TAG, "FdnSetting: " + msg);
}
+
+ @Override
+ public void onRequestPuk2(int id) {
+ resetPinChangeStateForPUK2();
+ final EditPinPreference button =
+ (id == Pin2LockedDialogFragment.DIALOG_ID_PUK2_REQUESTED_ON_PIN_CHANGED)
+ ? mButtonChangePin2 : mButtonEnableFDN;
+ displayPinChangeDialog(button, 0, true);
+ }
+
+ private void showPin2OrPuk2LockedDialog(int id) {
+ final FragmentManager fragmentManager = getFragmentManager();
+ Pin2LockedDialogFragment dialogFragment = (Pin2LockedDialogFragment) fragmentManager
+ .findFragmentByTag(Pin2LockedDialogFragment.TAG_PIN2_LOCKED_DIALOG);
+ if (dialogFragment == null) {
+ dialogFragment = new Pin2LockedDialogFragment();
+ Bundle args = new Bundle();
+ args.putInt(Pin2LockedDialogFragment.KEY_DIALOG_ID, id);
+ dialogFragment.setArguments(args);
+ dialogFragment.show(fragmentManager, Pin2LockedDialogFragment.TAG_PIN2_LOCKED_DIALOG);
+ } else {
+ FragmentTransaction transaction = fragmentManager.beginTransaction();
+ transaction.show(dialogFragment);
+ transaction.commitNow();
+ }
+ }
}
diff --git a/src/com/android/phone/settings/fdn/Pin2LockedDialogFragment.java b/src/com/android/phone/settings/fdn/Pin2LockedDialogFragment.java
new file mode 100644
index 0000000..ff16a7f
--- /dev/null
+++ b/src/com/android/phone/settings/fdn/Pin2LockedDialogFragment.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2020 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.phone.settings.fdn;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+import com.android.phone.R;
+
+/**
+ * Dialog Fragment that displays dialogs indicating that PIN2/PUK2 has been locked out.
+ *
+ * 1. When user fails PIN2 authentication and PIN2 is locked, show the dialog indicating that PIN2
+ * is locked and PUK2 must be entered.
+ * 2. When user fails PUK2 authentication and PUK2 is locked, show the dialog indicating that PUK2
+ * is locked and user must contact service provider to unlock PUK2.
+ */
+public class Pin2LockedDialogFragment extends DialogFragment {
+
+ static final String TAG_PIN2_LOCKED_DIALOG = "tag_pin2_locked_dialog";
+ static final String KEY_DIALOG_ID = "key_dialog_id";
+
+ // AlertDialog IDs
+ static final int DIALOG_ID_PUK2_LOCKED_OUT = 10;
+ static final int DIALOG_ID_PUK2_REQUESTED_ON_PIN_ENTRY = 11;
+ static final int DIALOG_ID_PUK2_REQUESTED_ON_PIN_CHANGED = 12;
+
+ private Listener mListener;
+ private int mId;
+
+ interface Listener {
+ void onRequestPuk2(int id);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ super.onCreateDialog(savedInstanceState);
+ Activity activity = getActivity();
+ if (!(activity instanceof Listener)) {
+ return null;
+ }
+ mListener = (Listener) activity;
+ mId = getArguments().getInt(KEY_DIALOG_ID);
+
+ if (mId == DIALOG_ID_PUK2_LOCKED_OUT) {
+ AlertDialog alert = new AlertDialog.Builder(activity)
+ .setMessage(R.string.puk2_locked)
+ .setCancelable(true)
+ .create();
+ alert.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+ alert.setButton(DialogInterface.BUTTON_NEUTRAL, getText(R.string.ok),
+ (dialog, which) -> {
+ });
+ return alert;
+ }
+
+ if (mId == DIALOG_ID_PUK2_REQUESTED_ON_PIN_CHANGED
+ || mId == DIALOG_ID_PUK2_REQUESTED_ON_PIN_ENTRY) {
+ AlertDialog alert = new AlertDialog.Builder(activity)
+ .setMessage(R.string.puk2_requested)
+ .setCancelable(true)
+ .create();
+ alert.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+ alert.setButton(DialogInterface.BUTTON_NEUTRAL, getText(R.string.ok),
+ (dialog, which) -> {
+ mListener.onRequestPuk2(mId);
+ dialog.dismiss();
+ });
+ return alert;
+ }
+ return null;
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ if (mId == DIALOG_ID_PUK2_REQUESTED_ON_PIN_CHANGED
+ || mId == DIALOG_ID_PUK2_REQUESTED_ON_PIN_ENTRY) {
+ mListener.onRequestPuk2(mId);
+ }
+ dialog.dismiss();
+ }
+}
+
diff --git a/testapps/TestRcsApp/TestApp/Android.bp b/testapps/TestRcsApp/TestApp/Android.bp
index 4496a8e..cda7d17 100644
--- a/testapps/TestRcsApp/TestApp/Android.bp
+++ b/testapps/TestRcsApp/TestApp/Android.bp
@@ -21,6 +21,8 @@
"libphonenumber-platform"
],
+ libs: ["org.apache.http.legacy"],
+
certificate: "platform",
privileged: true,
product_specific: true,
diff --git a/testapps/TestRcsApp/TestApp/AndroidManifest.xml b/testapps/TestRcsApp/TestApp/AndroidManifest.xml
index 460a1ce..7538df7 100644
--- a/testapps/TestRcsApp/TestApp/AndroidManifest.xml
+++ b/testapps/TestRcsApp/TestApp/AndroidManifest.xml
@@ -19,8 +19,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.sample.rcsclient"
- android:versionCode="12"
- android:versionName="1.0.11">
+ android:versionCode="13"
+ android:versionName="1.0.12">
<uses-sdk
android:minSdkVersion="30"
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java
index 3bc1c24..b9078f8 100644
--- a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java
@@ -156,6 +156,7 @@
Log.i(TAG, "FileTransferController null");
return;
}
+ mUploadResult.setText("");
Futures.addCallback(
fileTransferController.uploadFile(UUID.randomUUID().toString(),
mFile),
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/FileUploadController.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/FileUploadController.java
index d8e38e0..0d45828 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/FileUploadController.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/FileUploadController.java
@@ -34,10 +34,11 @@
import com.google.common.util.concurrent.MoreExecutors;
import org.apache.http.Header;
-import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AUTH;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.AuthPolicy;
@@ -96,7 +97,7 @@
ListenableFuture<HttpResponse> initialResponseFuture = sendEmptyPost(httpClient);
BasicHttpContext httpContext = new BasicHttpContext();
- ListenableFuture<Void> prepareAuthFuture =
+ ListenableFuture<AuthScheme> prepareAuthFuture =
Futures.transform(
initialResponseFuture,
initialResponse -> {
@@ -117,17 +118,16 @@
// Override nonce and realm in the HTTP context.
RFC2617Scheme authScheme = createAuthScheme(initialResponse);
httpContext.setAttribute(ATTRIBUTE_PREEMPTIVE_AUTH, authScheme);
-
- return null;
+ return authScheme;
},
executor);
// Executing the post with credentials.
return Futures.transformAsync(
prepareAuthFuture,
- unused ->
+ authScheme ->
executeAuthenticatedPost(
- httpClient, httpContext, transactionId, file),
+ httpClient, httpContext, authScheme, transactionId, file),
executor);
}
@@ -141,27 +141,12 @@
String scheme = authHeader.getValue();
if (scheme.contains(AuthPolicy.DIGEST)) {
- HeaderElement[] elements = authHeader.getElements();
-
- if (elements == null || elements.length == 0) {
- throw new IllegalArgumentException(
- "Unable to find header elements. Cannot perform Digest authentication.");
- }
-
DigestScheme digestScheme = new DigestScheme();
- for (HeaderElement element : elements) {
- // TODO(b/180601658): Add checks for the realm, which should start with
- // 3GPP-bootstrapping@.
- if (element.getName().contains(PARAM_REALM)) {
- digestScheme.overrideParamter(PARAM_REALM, element.getValue());
- Log.i(TAG, "Realm: " + element.getValue());
- }
- if (element.getName().contains(PARAM_NONCE)) {
- digestScheme.overrideParamter(PARAM_NONCE, element.getValue());
- Log.i(TAG, "Nonce: " + element.getValue());
- }
+ try {
+ digestScheme.processChallenge(authHeader);
+ } catch (MalformedChallengeException e) {
+ throw new IllegalArgumentException(e);
}
-
return digestScheme;
} else {
throw new IllegalArgumentException("Unable to create authentication scheme " + scheme);
@@ -195,13 +180,14 @@
private ListenableFuture<String> executeAuthenticatedPost(
DefaultHttpClient httpClient,
HttpContext context,
+ AuthScheme authScheme,
String transactionId,
File file)
throws IOException {
Part[] parts = {
new StringPart(TRANSFER_ID_PART_NAME, transactionId),
- new FilePart(file.getName(), file)
+ new FilePart(FILE_PART_NAME, file)
};
MultipartEntity entity = new MultipartEntity(parts);
@@ -211,7 +197,8 @@
Log.i(TAG, "Created file upload POST:" + contentServerUri);
ListenableFuture<HttpResponse> responseFuture =
- requestExecutor.executeAuthenticatedRequest(httpClient, context, postRequest);
+ requestExecutor.executeAuthenticatedRequest(httpClient, context, postRequest,
+ authScheme);
Futures.addCallback(
responseFuture,
@@ -227,7 +214,7 @@
@Override
public void onFailure(Throwable t) {
- Log.i(TAG, "onFailure");
+ Log.e(TAG, "onFailure", t);
throw new IllegalArgumentException(t);
}
},
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaAuthenticationProvider.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaAuthenticationProvider.java
index 0bfa4cb..008fb76 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaAuthenticationProvider.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaAuthenticationProvider.java
@@ -64,11 +64,12 @@
Log.i(TAG, "organization:" + organization + ", protocol:" + protocol + ", cipherSuite:"
+ cipherSuite + ", contentServerUrl:" + contentServerUrl);
- builder.setOrg(UaSecurityProtocolIdentifier.ORG_3GPP)
- .setProtocol(
- UaSecurityProtocolIdentifier.UA_SECURITY_PROTOCOL_3GPP_TLS_DEFAULT);
+ builder.setOrg(organization)
+ .setProtocol(protocol);
if (cipherSuite == TlsParams.TLS_NULL_WITH_NULL_NULL) {
builder.setTlsCipherSuite(TlsParams.TLS_RSA_WITH_AES_128_CBC_SHA);
+ } else {
+ builder.setTlsCipherSuite(cipherSuite);
}
} catch (IllegalArgumentException e) {
Log.e(TAG, e.getMessage());
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaRequestExecutor.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaRequestExecutor.java
index 856fec1..83d5a8a 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaRequestExecutor.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaRequestExecutor.java
@@ -24,9 +24,12 @@
import com.google.common.util.concurrent.MoreExecutors;
import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.AuthState;
import org.apache.http.auth.Credentials;
import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HttpContext;
@@ -48,7 +51,8 @@
@Override
@SuppressWarnings("CheckReturnValue")
public ListenableFuture<HttpResponse> executeAuthenticatedRequest(
- DefaultHttpClient httpClient, HttpContext context, HttpRequestBase request) {
+ DefaultHttpClient httpClient, HttpContext context, HttpRequestBase request,
+ AuthScheme authScheme) {
// Set authentication for the client.
ListenableFuture<Credentials> credentialsFuture =
@@ -61,8 +65,13 @@
Log.i(TAG,
"Obtained credentialsFuture, making the POST with credentials"
+ ".");
- httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY,
- credentials);
+ httpClient.addRequestInterceptor((req, ctx) -> {
+ AuthState authState = (AuthState) context.getAttribute(
+ ClientContext.TARGET_AUTH_STATE);
+ authState.setAuthScope(AuthScope.ANY);
+ authState.setAuthScheme(authScheme);
+ authState.setCredentials(credentials);
+ }, /* index= */ 0);
// Make the first request.
return executor.submit(() -> httpClient.execute(request, context));
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/HttpRequestExecutor.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/HttpRequestExecutor.java
index 59a3aa9..0026790 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/HttpRequestExecutor.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/HttpRequestExecutor.java
@@ -19,6 +19,7 @@
import com.google.common.util.concurrent.ListenableFuture;
import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScheme;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HttpContext;
@@ -29,6 +30,7 @@
public interface HttpRequestExecutor {
ListenableFuture<HttpResponse> executeAuthenticatedRequest(
- DefaultHttpClient httpClient, HttpContext context, HttpRequestBase request)
+ DefaultHttpClient httpClient, HttpContext context, HttpRequestBase request,
+ AuthScheme authScheme)
throws IOException;
}
diff --git a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
index c7d0c8f..57e01f0 100644
--- a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
+++ b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
@@ -85,28 +85,56 @@
*/
public class RcsProvisioningMonitorTest {
private static final String TAG = "RcsProvisioningMonitorTest";
- private static final String CONFIG_DEFAULT = "<RCSConfig>\n"
- + "\t<rcsVolteSingleRegistration>1</rcsVolteSingleRegistration>\n"
- + "\t<SERVICES>\n"
- + "\t\t<SupportedRCSProfileVersions>UP_2.0</SupportedRCSProfileVersions>\n"
- + "\t\t<ChatAuth>1</ChatAuth>\n"
- + "\t\t<GroupChatAuth>1</GroupChatAuth>\n"
- + "\t\t<ftAuth>1</ftAuth>\n"
- + "\t\t<standaloneMsgAuth>1</standaloneMsgAuth>\n"
- + "\t\t<geolocPushAuth>1</geolocPushAuth>\n"
- + "\t\t<Ext>\n"
- + "\t\t\t<DataOff>\n"
- + "\t\t\t\t<rcsMessagingDataOff>1</rcsMessagingDataOff>\n"
- + "\t\t\t\t<fileTransferDataOff>1</fileTransferDataOff>\n"
- + "\t\t\t\t<mmsDataOff>1</mmsDataOff>\n"
- + "\t\t\t\t<syncDataOff>1</syncDataOff>\n"
- + "\t\t\t</DataOff>\n"
- + "\t\t</Ext>\n"
- + "\t</SERVICES>\n"
- + "</RCSConfig>";
- private static final String CONFIG_SINGLE_REGISTRATION_DISABLED = "<RCSConfig>\n"
- + "\t<rcsVolteSingleRegistration>0</rcsVolteSingleRegistration>\n"
- + "</RCSConfig>";
+ private static final String CONFIG_DEFAULT = "<?xml version=\"1.0\"?>\n"
+ + "<wap-provisioningdoc version=\"1.1\">\n"
+ + "\t<characteristic type=\"APPLICATION\">\n"
+ + "\t\t<parm name=\"AppID\" value=\"urn:oma:mo:ext-3gpp-ims:1.0\"/>\n"
+ + "\t\t<characteristic type=\"3GPP_IMS\">\n"
+ + "\t\t\t<parm name=\"AppID\" value=\"ap2001\"/>\n"
+ + "\t\t\t<parm name=\"Name\" value=\"RCS IMS Settings\"/>\n"
+ + "\t\t\t<characteristic type=\"Ext\">\n"
+ + "\t\t\t\t<characteristic type=\"GSMA\">\n"
+ + "\t\t\t\t\t<parm name=\"AppRef\" value=\"IMS-Setting\"/>\n"
+ + "\t\t\t\t\t<parm name=\"rcsVolteSingleRegistration\" value=\"1\"/>\n"
+ + "\t\t\t\t</characteristic>\n"
+ + "\t\t\t</characteristic>\n"
+ + "\t\t</characteristic>\n"
+ + "\t\t<characteristic type=\"SERVICES\">\n"
+ + "\t\t\t<parm name=\"SupportedRCSProfileVersions\" value=\"UP2.3\"/>\n"
+ + "\t\t\t<parm name=\"ChatAuth\" value=\"1\"/>\n"
+ + "\t\t\t<parm name=\"GroupChatAuth\" value=\"1\"/>\n"
+ + "\t\t\t<parm name=\"ftAuth\" value=\"1\"/>\n"
+ + "\t\t\t<parm name=\"standaloneMsgAuth\" value=\"1\"/>\n"
+ + "\t\t\t<parm name=\"geolocPushAuth\" value=\"1\"/>\n"
+ + "\t\t\t<characteristic type=\"Ext\">\n"
+ + "\t\t\t\t<characteristic type=\"DataOff\">\n"
+ + "\t\t\t\t\t<parm name=\"rcsMessagingDataOff\" value=\"1\"/>\n"
+ + "\t\t\t\t\t<parm name=\"fileTransferDataOff\" value=\"1\"/>\n"
+ + "\t\t\t\t\t<parm name=\"mmsDataOff\" value=\"1\"/>\n"
+ + "\t\t\t\t\t<parm name=\"syncDataOff\" value=\"1\"/>\n"
+ + "\t\t\t\t\t<characteristic type=\"Ext\"/>\n"
+ + "\t\t\t\t</characteristic>\n"
+ + "\t\t\t</characteristic>\n"
+ + "\t\t</characteristic>\n"
+ + "\t</characteristic>\n"
+ + "</wap-provisioningdoc>\n";
+
+ private static final String CONFIG_SINGLE_REGISTRATION_DISABLED = "<?xml version=\"1.0\"?>\n"
+ + "<wap-provisioningdoc version=\"1.1\">\n"
+ + "\t<characteristic type=\"APPLICATION\">\n"
+ + "\t\t<parm name=\"AppID\" value=\"urn:oma:mo:ext-3gpp-ims:1.0\"/>\n"
+ + "\t\t<characteristic type=\"3GPP_IMS\">\n"
+ + "\t\t\t<parm name=\"AppID\" value=\"ap2001\"/>\n"
+ + "\t\t\t<parm name=\"Name\" value=\"RCS IMS Settings\"/>\n"
+ + "\t\t\t<characteristic type=\"Ext\">\n"
+ + "\t\t\t\t<characteristic type=\"GSMA\">\n"
+ + "\t\t\t\t\t<parm name=\"AppRef\" value=\"IMS-Setting\"/>\n"
+ + "\t\t\t\t\t<parm name=\"rcsVolteSingleRegistration\" value=\"0\"/>\n"
+ + "\t\t\t\t</characteristic>\n"
+ + "\t\t\t</characteristic>\n"
+ + "\t\t</characteristic>\n"
+ + "\t</characteristic>\n"
+ + "</wap-provisioningdoc>\n";
private static final int FAKE_SUB_ID_BASE = 0x0FFFFFF0;
private static final String DEFAULT_MESSAGING_APP1 = "DMA1";
private static final String DEFAULT_MESSAGING_APP2 = "DMA2";