Merge "Fix issue where "No recent apps" showed initially before loading thumbnails" into jb-dev
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 150880c..39e83e0 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -405,6 +405,55 @@
}
/**
+ * Change whether or not an app (identified by its uid) is allowed to retrieve an authToken
+ * for an account.
+ * <p>
+ * This is only meant to be used by system activities and is not in the SDK.
+ * @param account The account whose permissions are being modified
+ * @param authTokenType The type of token whose permissions are being modified
+ * @param uid The uid that identifies the app which is being granted or revoked permission.
+ * @param value true is permission is being granted, false for revoked
+ * @hide
+ */
+ public void updateAppPermission(Account account, String authTokenType, int uid, boolean value) {
+ try {
+ mService.updateAppPermission(account, authTokenType, uid, value);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Get the user-friendly label associated with an authenticator's auth token.
+ * @param accountType the type of the authenticator. must not be null.
+ * @param authTokenType the token type. must not be null.
+ * @param callback callback to invoke when the result is available. may be null.
+ * @param handler the handler on which to invoke the callback, or null for the main thread
+ * @return a future containing the label string
+ * @hide
+ */
+ public AccountManagerFuture<String> getAuthTokenLabel(
+ final String accountType, final String authTokenType,
+ AccountManagerCallback<String> callback, Handler handler) {
+ if (accountType == null) throw new IllegalArgumentException("accountType is null");
+ if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+ return new Future2Task<String>(handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.getAuthTokenLabel(mResponse, accountType, authTokenType);
+ }
+
+ @Override
+ public String bundleToResult(Bundle bundle) throws AuthenticatorException {
+ if (!bundle.containsKey(KEY_AUTH_TOKEN_LABEL)) {
+ throw new AuthenticatorException("no result in response");
+ }
+ return bundle.getString(KEY_AUTH_TOKEN_LABEL);
+ }
+ }.start();
+ }
+
+ /**
* Finds out whether a particular account has all the specified features.
* Account features are authenticator-specific string tokens identifying
* boolean account properties. For example, features are used to tell
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 2b643c2..ad4b58f 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -985,21 +985,25 @@
}
}
- void getAuthTokenLabel(final IAccountManagerResponse response,
- final Account account,
- final String authTokenType, int uid) {
- if (account == null) throw new IllegalArgumentException("account is null");
+ public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
+ final String authTokenType)
+ throws RemoteException {
+ if (accountType == null) throw new IllegalArgumentException("accountType is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
- checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
- UserAccounts accounts = getUserAccounts(UserId.getUserId(uid));
+ final int callingUid = getCallingUid();
+ clearCallingIdentity();
+ if (callingUid != android.os.Process.SYSTEM_UID) {
+ throw new SecurityException("can only call from system");
+ }
+ UserAccounts accounts = getUserAccounts(UserId.getUserId(callingUid));
long identityToken = clearCallingIdentity();
try {
- new Session(accounts, response, account.type, false,
+ new Session(accounts, response, accountType, false,
false /* stripAuthTokenFromResult */) {
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAuthTokenLabel"
- + ", " + account
+ + ", " + accountType
+ ", authTokenType " + authTokenType;
}
@@ -2230,6 +2234,21 @@
Manifest.permission.USE_CREDENTIALS);
}
+ public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
+ throws RemoteException {
+ final int callingUid = getCallingUid();
+
+ if (callingUid != android.os.Process.SYSTEM_UID) {
+ throw new SecurityException();
+ }
+
+ if (value) {
+ grantAppPermission(account, authTokenType, uid);
+ } else {
+ revokeAppPermission(account, authTokenType, uid);
+ }
+ }
+
/**
* Allow callers with the given uid permission to get credentials for account/authTokenType.
* <p>
@@ -2237,7 +2256,7 @@
* which is in the system. This means we don't need to protect it with permissions.
* @hide
*/
- public void grantAppPermission(Account account, String authTokenType, int uid) {
+ private void grantAppPermission(Account account, String authTokenType, int uid) {
if (account == null || authTokenType == null) {
Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
return;
@@ -2271,7 +2290,7 @@
* which is in the system. This means we don't need to protect it with permissions.
* @hide
*/
- public void revokeAppPermission(Account account, String authTokenType, int uid) {
+ private void revokeAppPermission(Account account, String authTokenType, int uid) {
if (account == null || authTokenType == null) {
Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
return;
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 291e75e..8543848 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -16,24 +16,19 @@
package android.accounts;
import android.app.Activity;
-import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
-import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
+
import com.android.internal.R;
import java.io.IOException;
@@ -106,10 +101,16 @@
private static final String KEY_INSTANCE_STATE_PENDING_REQUEST = "pendingRequest";
private static final String KEY_INSTANCE_STATE_EXISTING_ACCOUNTS = "existingAccounts";
+ private static final String KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME = "selectedAccountName";
+ private static final String KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT = "selectedAddAccount";
- private ArrayList<AccountInfo> mAccountInfos;
+ private static final int SELECTED_ITEM_NONE = -1;
+
+ private ArrayList<Account> mAccounts;
private int mPendingRequest = REQUEST_NULL;
private Parcelable[] mExistingAccounts = null;
+ private int mSelectedItemIndex;
+ private Button mOkButton;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -119,30 +120,38 @@
+ savedInstanceState + ")");
}
- if (savedInstanceState != null) {
- mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
- mExistingAccounts =
- savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);
- } else {
- mPendingRequest = REQUEST_NULL;
- mExistingAccounts = null;
- }
-
// save some items we use frequently
final AccountManager accountManager = AccountManager.get(this);
final Intent intent = getIntent();
- // override the description text if supplied
- final String descriptionOverride =
- intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
- if (!TextUtils.isEmpty(descriptionOverride)) {
- ((TextView)findViewById(R.id.description)).setText(descriptionOverride);
+ String selectedAccountName = null;
+ boolean selectedAddNewAccount = false;
+
+ if (savedInstanceState != null) {
+ mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
+ mExistingAccounts =
+ savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);
+
+ // Makes sure that any user selection is preserved across orientation changes.
+ selectedAccountName = savedInstanceState.getString(
+ KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);
+
+ selectedAddNewAccount = savedInstanceState.getBoolean(
+ KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
+ } else {
+ mPendingRequest = REQUEST_NULL;
+ mExistingAccounts = null;
+ // If the selected account as specified in the intent matches one in the list we will
+ // show is as pre-selected.
+ Account selectedAccount = (Account) intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
+ if (selectedAccount != null) {
+ selectedAccountName = selectedAccount.name;
+ }
}
- // If the selected account matches one in the list we will place a
- // checkmark next to it.
- final Account selectedAccount =
- (Account)intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "selected account name is " + selectedAccountName);
+ }
// build an efficiently queryable map of account types to authenticator descriptions
final HashMap<String, AuthenticatorDescription> typeToAuthDescription =
@@ -192,7 +201,8 @@
// accounts that don't match the allowable types, if provided, or that don't match the
// allowable accounts, if provided.
final Account[] accounts = accountManager.getAccounts();
- mAccountInfos = new ArrayList<AccountInfo>(accounts.length);
+ mAccounts = new ArrayList<Account>(accounts.length);
+ mSelectedItemIndex = SELECTED_ITEM_NONE;
for (Account account : accounts) {
if (setOfAllowableAccounts != null
&& !setOfAllowableAccounts.contains(account)) {
@@ -202,15 +212,16 @@
&& !setOfRelevantAccountTypes.contains(account.type)) {
continue;
}
- mAccountInfos.add(new AccountInfo(account,
- getDrawableForType(typeToAuthDescription, account.type),
- account.equals(selectedAccount)));
+ if (account.name.equals(selectedAccountName)) {
+ mSelectedItemIndex = mAccounts.size();
+ }
+ mAccounts.add(account);
}
if (mPendingRequest == REQUEST_NULL) {
- // If there are no relevant accounts and only one relevant account typoe go directly to
+ // If there are no relevant accounts and only one relevant account type go directly to
// add account. Otherwise let the user choose.
- if (mAccountInfos.isEmpty()) {
+ if (mAccounts.isEmpty()) {
if (setOfRelevantAccountTypes.size() == 1) {
runAddAccountForAuthenticator(setOfRelevantAccountTypes.iterator().next());
} else {
@@ -221,36 +232,71 @@
// if there is only one allowable account return it
if (!intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false)
- && mAccountInfos.size() == 1) {
- Account account = mAccountInfos.get(0).account;
+ && mAccounts.size() == 1) {
+ Account account = mAccounts.get(0);
setResultAndFinish(account.name, account.type);
return;
}
}
+ // Cannot set content view until we know that mPendingRequest is not null, otherwise
+ // would cause screen flicker.
setContentView(R.layout.choose_type_and_account);
- // there is more than one allowable account. initialize the list adapter to allow
- // the user to select an account.
+ // Override the description text if supplied
+ final String descriptionOverride =
+ intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
+ TextView descriptionView = (TextView) findViewById(R.id.description);
+ if (!TextUtils.isEmpty(descriptionOverride)) {
+ descriptionView.setText(descriptionOverride);
+ } else {
+ descriptionView.setVisibility(View.GONE);
+ }
+
+ // List of options includes all accounts found together with "Add new account" as the
+ // last item in the list.
+ String[] listItems = new String[mAccounts.size() + 1];
+ for (int i = 0; i < mAccounts.size(); i++) {
+ listItems[i] = mAccounts.get(i).name;
+ }
+ listItems[mAccounts.size()] = getResources().getString(
+ R.string.add_account_button_label);
+
ListView list = (ListView) findViewById(android.R.id.list);
- list.setAdapter(new AccountArrayAdapter(this,
- android.R.layout.simple_list_item_1, mAccountInfos));
+ list.setAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_single_choice, listItems));
list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ list.setItemsCanFocus(false);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
- onListItemClick((ListView)parent, v, position, id);
+ mSelectedItemIndex = position;
+ mOkButton.setEnabled(true);
}
});
- // set the listener for the addAccount button
- Button addAccountButton = (Button) findViewById(R.id.addAccount);
- addAccountButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(final View v) {
- startChooseAccountTypeActivity();
+ // If "Add account" option was previously selected by user, preserve it across
+ // orientation changes.
+ if (selectedAddNewAccount) {
+ mSelectedItemIndex = mAccounts.size();
+ }
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "mSelectedItemIndex is " + mSelectedItemIndex);
+ }
+
+ ViewGroup buttonBar = (ViewGroup) findViewById(R.id.button_bar);
+ if (buttonBar != null) {
+ mOkButton = (Button) buttonBar.findViewById(android.R.id.button2);
+ if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
+ // If caller specified a selectedAccount, then display that as selected and enable
+ // the "OK" button by default.
+ list.setSelection(mSelectedItemIndex);
+ mOkButton.setEnabled(true);
+ } else {
+ // Otherwise "OK" button is disabled since nothing is pre-selected.
+ mOkButton.setEnabled(false);
}
- });
+ }
}
@Override
@@ -268,6 +314,28 @@
if (mPendingRequest == REQUEST_ADD_ACCOUNT) {
outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);
}
+ if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
+ if (mSelectedItemIndex == mAccounts.size()) {
+ outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true);
+ } else {
+ outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
+ outState.putString(KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME,
+ mAccounts.get(mSelectedItemIndex).name);
+ }
+ }
+ }
+
+ public void onCancelButtonClicked(View view) {
+ onBackPressed();
+ }
+
+ public void onOkButtonClicked(View view) {
+ if (mSelectedItemIndex == mAccounts.size()) {
+ // Selected "Add New Account" option
+ startChooseAccountTypeActivity();
+ } else if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
+ onAccountSelected(mAccounts.get(mSelectedItemIndex));
+ }
}
// Called when the choose account type activity (for adding an account) returns.
@@ -287,9 +355,9 @@
mPendingRequest = REQUEST_NULL;
if (resultCode == RESULT_CANCELED) {
- // if cancelling out of addAccount and the original state caused us to skip this,
+ // if canceling out of addAccount and the original state caused us to skip this,
// finish this activity
- if (mAccountInfos.isEmpty()) {
+ if (mAccounts.isEmpty()) {
setResult(Activity.RESULT_CANCELED);
finish();
}
@@ -360,6 +428,7 @@
options, null /* activity */, this /* callback */, null /* Handler */);
}
+ @Override
public void run(final AccountManagerFuture<Bundle> accountManagerFuture) {
try {
final Bundle accountManagerResult = accountManagerFuture.getResult();
@@ -385,34 +454,9 @@
finish();
}
- private Drawable getDrawableForType(
- final HashMap<String, AuthenticatorDescription> typeToAuthDescription,
- String accountType) {
- Drawable icon = null;
- if (typeToAuthDescription.containsKey(accountType)) {
- try {
- AuthenticatorDescription desc = typeToAuthDescription.get(accountType);
- Context authContext = createPackageContext(desc.packageName, 0);
- icon = authContext.getResources().getDrawable(desc.iconId);
- } catch (PackageManager.NameNotFoundException e) {
- // Nothing we can do much here, just log
- if (Log.isLoggable(TAG, Log.WARN)) {
- Log.w(TAG, "No icon name for account type " + accountType);
- }
- } catch (Resources.NotFoundException e) {
- // Nothing we can do much here, just log
- if (Log.isLoggable(TAG, Log.WARN)) {
- Log.w(TAG, "No icon resource for account type " + accountType);
- }
- }
- }
- return icon;
- }
-
- protected void onListItemClick(ListView l, View v, int position, long id) {
- AccountInfo accountInfo = mAccountInfos.get(position);
- Log.d(TAG, "selected account " + accountInfo.account);
- setResultAndFinish(accountInfo.account.name, accountInfo.account.type);
+ private void onAccountSelected(Account account) {
+ Log.d(TAG, "selected account " + account);
+ setResultAndFinish(account.name, account.type);
}
private void setResultAndFinish(final String accountName, final String accountType) {
@@ -444,58 +488,4 @@
startActivityForResult(intent, REQUEST_CHOOSE_TYPE);
mPendingRequest = REQUEST_CHOOSE_TYPE;
}
-
- private static class AccountInfo {
- final Account account;
- final Drawable drawable;
- private final boolean checked;
-
- AccountInfo(Account account, Drawable drawable, boolean checked) {
- this.account = account;
- this.drawable = drawable;
- this.checked = checked;
- }
- }
-
- private static class ViewHolder {
- ImageView icon;
- TextView text;
- ImageView checkmark;
- }
-
- private static class AccountArrayAdapter extends ArrayAdapter<AccountInfo> {
- private LayoutInflater mLayoutInflater;
- private ArrayList<AccountInfo> mInfos;
-
- public AccountArrayAdapter(Context context, int textViewResourceId,
- ArrayList<AccountInfo> infos) {
- super(context, textViewResourceId, infos);
- mInfos = infos;
- mLayoutInflater = (LayoutInflater) context.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- ViewHolder holder;
-
- if (convertView == null) {
- convertView = mLayoutInflater.inflate(R.layout.choose_selected_account_row, null);
- holder = new ViewHolder();
- holder.text = (TextView) convertView.findViewById(R.id.account_row_text);
- holder.icon = (ImageView) convertView.findViewById(R.id.account_row_icon);
- holder.checkmark = (ImageView) convertView.findViewById(R.id.account_row_checkmark);
- convertView.setTag(holder);
- } else {
- holder = (ViewHolder) convertView.getTag();
- }
-
- holder.text.setText(mInfos.get(position).account.name);
- holder.icon.setImageDrawable(mInfos.get(position).drawable);
- final int displayCheckmark =
- mInfos.get(position).checked ? View.VISIBLE : View.INVISIBLE;
- holder.checkmark.setVisibility(displayCheckmark);
- return convertView;
- }
- }
}
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index 4419c8c..8b01c6a 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -16,22 +16,22 @@
package android.accounts;
import android.app.Activity;
+import android.content.pm.RegisteredServicesCache;
+import android.content.res.Resources;
import android.os.Bundle;
-import android.os.RemoteException;
import android.widget.TextView;
import android.widget.LinearLayout;
-import android.widget.ImageView;
import android.view.View;
import android.view.LayoutInflater;
-import android.view.Window;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.pm.RegisteredServicesCache;
import android.text.TextUtils;
-import android.graphics.drawable.Drawable;
import com.android.internal.R;
+import java.io.IOException;
+import java.net.Authenticator;
+
/**
* @hide
*/
@@ -48,7 +48,6 @@
private int mUid;
private Bundle mResultBundle = null;
protected LayoutInflater mInflater;
- private final AccountManagerService accountManagerService = AccountManagerService.getSingleton();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -81,7 +80,7 @@
String accountTypeLabel;
try {
- accountTypeLabel = accountManagerService.getAccountLabel(mAccount.type);
+ accountTypeLabel = getAccountLabel(mAccount);
} catch (IllegalArgumentException e) {
// label or resource was missing. abort the activity.
setResult(Activity.RESULT_CANCELED);
@@ -92,28 +91,27 @@
final TextView authTokenTypeView = (TextView) findViewById(R.id.authtoken_type);
authTokenTypeView.setVisibility(View.GONE);
- /** Handles the responses from the AccountManager */
- IAccountManagerResponse response = new IAccountManagerResponse.Stub() {
- public void onResult(Bundle bundle) {
- final String authTokenLabel =
- bundle.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
- if (!TextUtils.isEmpty(authTokenLabel)) {
- runOnUiThread(new Runnable() {
- public void run() {
- if (!isFinishing()) {
- authTokenTypeView.setText(authTokenLabel);
- authTokenTypeView.setVisibility(View.VISIBLE);
+ final AccountManagerCallback<String> callback = new AccountManagerCallback<String>() {
+ public void run(AccountManagerFuture<String> future) {
+ try {
+ final String authTokenLabel = future.getResult();
+ if (!TextUtils.isEmpty(authTokenLabel)) {
+ runOnUiThread(new Runnable() {
+ public void run() {
+ if (!isFinishing()) {
+ authTokenTypeView.setText(authTokenLabel);
+ authTokenTypeView.setVisibility(View.VISIBLE);
+ }
}
- }
- });
+ });
+ }
+ } catch (OperationCanceledException e) {
+ } catch (IOException e) {
+ } catch (AuthenticatorException e) {
}
}
-
- public void onError(int code, String message) {
- }
};
-
- accountManagerService.getAuthTokenLabel(response, mAccount, mAuthTokenType, mUid);
+ AccountManager.get(this).getAuthTokenLabel(mAccount.type, mAuthTokenType, callback, null);
findViewById(R.id.allow_button).setOnClickListener(this);
findViewById(R.id.deny_button).setOnClickListener(this);
@@ -134,6 +132,24 @@
((TextView) findViewById(R.id.account_type)).setText(accountTypeLabel);
}
+ private String getAccountLabel(Account account) {
+ final AuthenticatorDescription[] authenticatorTypes =
+ AccountManager.get(this).getAuthenticatorTypes();
+ for (int i = 0, N = authenticatorTypes.length; i < N; i++) {
+ final AuthenticatorDescription desc = authenticatorTypes[i];
+ if (desc.type.equals(account.type)) {
+ try {
+ return createPackageContext(desc.packageName, 0).getString(desc.labelId);
+ } catch (PackageManager.NameNotFoundException e) {
+ return account.type;
+ } catch (Resources.NotFoundException e) {
+ return account.type;
+ }
+ }
+ }
+ return account.type;
+ }
+
private View newPackageView(String packageLabel) {
View view = mInflater.inflate(R.layout.permissions_package_list_item, null);
((TextView) view.findViewById(R.id.package_label)).setText(packageLabel);
@@ -143,7 +159,7 @@
public void onClick(View v) {
switch (v.getId()) {
case R.id.allow_button:
- accountManagerService.grantAppPermission(mAccount, mAuthTokenType, mUid);
+ AccountManager.get(this).updateAppPermission(mAccount, mAuthTokenType, mUid, true);
Intent result = new Intent();
result.putExtra("retry", true);
setResult(RESULT_OK, result);
@@ -151,7 +167,7 @@
break;
case R.id.deny_button:
- accountManagerService.revokeAppPermission(mAccount, mAuthTokenType, mUid);
+ AccountManager.get(this).updateAppPermission(mAccount, mAuthTokenType, mUid, false);
setResult(RESULT_CANCELED);
break;
}
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 36a5653..6007321 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -41,6 +41,7 @@
void setPassword(in Account account, String password);
void clearPassword(in Account account);
void setUserData(in Account account, String key, String value);
+ void updateAppPermission(in Account account, String authTokenType, int uid, boolean value);
void getAuthToken(in IAccountManagerResponse response, in Account account,
String authTokenType, boolean notifyOnAuthFailure, boolean expectActivityLaunch,
@@ -54,4 +55,6 @@
boolean expectActivityLaunch);
void confirmCredentials(in IAccountManagerResponse response, in Account account,
in Bundle options, boolean expectActivityLaunch);
+ void getAuthTokenLabel(in IAccountManagerResponse response, String accountType,
+ String authTokenType);
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 4506546..2ed93f4 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -580,7 +580,8 @@
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
String name = data.readString();
- ContentProviderHolder cph = getContentProvider(app, name);
+ boolean stable = data.readInt() != 0;
+ ContentProviderHolder cph = getContentProvider(app, name, stable);
reply.writeNoException();
if (cph != null) {
reply.writeInt(1);
@@ -617,12 +618,30 @@
return true;
}
+ case REF_CONTENT_PROVIDER_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder b = data.readStrongBinder();
+ int stable = data.readInt();
+ int unstable = data.readInt();
+ boolean res = refContentProvider(b, stable, unstable);
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
+
+ case UNSTABLE_PROVIDER_DIED_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder b = data.readStrongBinder();
+ unstableProviderDied(b);
+ reply.writeNoException();
+ return true;
+ }
+
case REMOVE_CONTENT_PROVIDER_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
- IApplicationThread app = ApplicationThreadNative.asInterface(b);
- String name = data.readString();
- removeContentProvider(app, name);
+ boolean stable = data.readInt() != 0;
+ removeContentProvider(b, stable);
reply.writeNoException();
return true;
}
@@ -2314,13 +2333,13 @@
reply.recycle();
}
public ContentProviderHolder getContentProvider(IApplicationThread caller,
- String name) throws RemoteException
- {
+ String name, boolean stable) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(name);
+ data.writeInt(stable ? 1 : 0);
mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
@@ -2352,7 +2371,7 @@
return cph;
}
public void publishContentProviders(IApplicationThread caller,
- List<ContentProviderHolder> providers) throws RemoteException
+ List<ContentProviderHolder> providers) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -2364,14 +2383,38 @@
data.recycle();
reply.recycle();
}
-
- public void removeContentProvider(IApplicationThread caller,
- String name) throws RemoteException {
+ public boolean refContentProvider(IBinder connection, int stable, int unstable)
+ throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(caller != null ? caller.asBinder() : null);
- data.writeString(name);
+ data.writeStrongBinder(connection);
+ data.writeInt(stable);
+ data.writeInt(unstable);
+ mRemote.transact(REF_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean res = reply.readInt() != 0;
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+ public void unstableProviderDied(IBinder connection) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(connection);
+ mRemote.transact(UNSTABLE_PROVIDER_DIED_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ public void removeContentProvider(IBinder connection, boolean stable) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(connection);
+ data.writeInt(stable ? 1 : 0);
mRemote.transact(REMOVE_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 33e639e..7242029 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -140,6 +140,7 @@
private static final boolean DEBUG_CONFIGURATION = false;
private static final boolean DEBUG_SERVICE = false;
private static final boolean DEBUG_MEMORY_TRIM = false;
+ private static final boolean DEBUG_PROVIDER = false;
private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";");
private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
@@ -210,6 +211,8 @@
= new HashMap<IBinder, ProviderRefCount>();
final HashMap<IBinder, ProviderClientRecord> mLocalProviders
= new HashMap<IBinder, ProviderClientRecord>();
+ final HashMap<ComponentName, ProviderClientRecord> mLocalProvidersByName
+ = new HashMap<ComponentName, ProviderClientRecord>();
final HashMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
= new HashMap<Activity, ArrayList<OnActivityPausedListener>>();
@@ -284,20 +287,19 @@
}
}
- final class ProviderClientRecord implements IBinder.DeathRecipient {
- final String mName;
+ final class ProviderClientRecord {
+ final String[] mNames;
final IContentProvider mProvider;
final ContentProvider mLocalProvider;
+ final IActivityManager.ContentProviderHolder mHolder;
- ProviderClientRecord(String name, IContentProvider provider,
- ContentProvider localProvider) {
- mName = name;
+ ProviderClientRecord(String[] names, IContentProvider provider,
+ ContentProvider localProvider,
+ IActivityManager.ContentProviderHolder holder) {
+ mNames = names;
mProvider = provider;
mLocalProvider = localProvider;
- }
-
- public void binderDied() {
- removeDeadProvider(mName, mProvider);
+ mHolder = holder;
}
}
@@ -1061,6 +1063,11 @@
pw.flush();
}
+ @Override
+ public void unstableProviderDied(IBinder provider) {
+ queueOrSendMessage(H.UNSTABLE_PROVIDER_DIED, provider);
+ }
+
private void printRow(PrintWriter pw, String format, Object...objs) {
pw.println(String.format(format, objs));
}
@@ -1125,6 +1132,7 @@
public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
public static final int TRIM_MEMORY = 140;
public static final int DUMP_PROVIDER = 141;
+ public static final int UNSTABLE_PROVIDER_DIED = 142;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
@@ -1170,6 +1178,7 @@
case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
case TRIM_MEMORY: return "TRIM_MEMORY";
case DUMP_PROVIDER: return "DUMP_PROVIDER";
+ case UNSTABLE_PROVIDER_DIED: return "UNSTABLE_PROVIDER_DIED";
}
}
return Integer.toString(code);
@@ -1337,7 +1346,7 @@
break;
case REMOVE_PROVIDER:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "providerRemove");
- completeRemoveProvider((IContentProvider)msg.obj);
+ completeRemoveProvider((ProviderRefCount)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case ENABLE_JIT:
@@ -1377,6 +1386,9 @@
handleTrimMemory(msg.arg1);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
+ case UNSTABLE_PROVIDER_DIED:
+ handleUnstableProviderDied((IBinder)msg.obj, false);
+ break;
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
@@ -2867,10 +2879,24 @@
}
private static final class ProviderRefCount {
- public int count;
+ public final IActivityManager.ContentProviderHolder holder;
+ public final ProviderClientRecord client;
+ public int stableCount;
+ public int unstableCount;
- ProviderRefCount(int pCount) {
- count = pCount;
+ // When this is set, the stable and unstable ref counts are 0 and
+ // we have a pending operation scheduled to remove the ref count
+ // from the activity manager. On the activity manager we are still
+ // holding an unstable ref, though it is not reflected in the counts
+ // here.
+ public boolean removePending;
+
+ ProviderRefCount(IActivityManager.ContentProviderHolder inHolder,
+ ProviderClientRecord inClient, int sCount, int uCount) {
+ holder = inHolder;
+ client = inClient;
+ stableCount = sCount;
+ unstableCount = uCount;
}
}
@@ -4080,15 +4106,6 @@
Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
}
- try {
- mInstrumentation.onCreate(data.instrumentationArgs);
- }
- catch (Exception e) {
- throw new RuntimeException(
- "Exception thrown in onCreate() of "
- + data.instrumentationName + ": " + e.toString(), e);
- }
-
} else {
mInstrumentation = new Instrumentation();
}
@@ -4119,6 +4136,17 @@
}
}
+ // Do this after providers, since instrumentation tests generally start their
+ // test thread at this point, and we don't want that racing.
+ try {
+ mInstrumentation.onCreate(data.instrumentationArgs);
+ }
+ catch (Exception e) {
+ throw new RuntimeException(
+ "Exception thrown in onCreate() of "
+ + data.instrumentationName + ": " + e.toString(), e);
+ }
+
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
@@ -4159,12 +4187,9 @@
buf.append(": ");
buf.append(cpi.name);
Log.i(TAG, buf.toString());
- IContentProvider cp = installProvider(context, null, cpi,
- false /*noisy*/, true /*noReleaseNeeded*/);
- if (cp != null) {
- IActivityManager.ContentProviderHolder cph =
- new IActivityManager.ContentProviderHolder(cpi);
- cph.provider = cp;
+ IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
+ false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
+ if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
@@ -4177,8 +4202,8 @@
}
}
- public final IContentProvider acquireProvider(Context c, String name) {
- IContentProvider provider = acquireExistingProvider(c, name);
+ public final IContentProvider acquireProvider(Context c, String name, boolean stable) {
+ IContentProvider provider = acquireExistingProvider(c, name, stable);
if (provider != null) {
return provider;
}
@@ -4192,7 +4217,7 @@
IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().getContentProvider(
- getApplicationThread(), name);
+ getApplicationThread(), name, stable);
} catch (RemoteException ex) {
}
if (holder == null) {
@@ -4202,23 +4227,79 @@
// Install provider will increment the reference count for us, and break
// any ties in the race.
- provider = installProvider(c, holder.provider, holder.info,
- true /*noisy*/, holder.noReleaseNeeded);
- if (holder.provider != null && provider != holder.provider) {
- if (localLOGV) {
- Slog.v(TAG, "acquireProvider: lost the race, releasing extraneous "
- + "reference to the content provider");
- }
- try {
- ActivityManagerNative.getDefault().removeContentProvider(
- getApplicationThread(), name);
- } catch (RemoteException ex) {
- }
- }
- return provider;
+ holder = installProvider(c, holder, holder.info,
+ true /*noisy*/, holder.noReleaseNeeded, stable);
+ return holder.provider;
}
- public final IContentProvider acquireExistingProvider(Context c, String name) {
+ private final void incProviderRefLocked(ProviderRefCount prc, boolean stable) {
+ if (stable) {
+ prc.stableCount += 1;
+ if (prc.stableCount == 1) {
+ // We are acquiring a new stable reference on the provider.
+ int unstableDelta;
+ if (prc.removePending) {
+ // We have a pending remove operation, which is holding the
+ // last unstable reference. At this point we are converting
+ // that unstable reference to our new stable reference.
+ unstableDelta = -1;
+ // Cancel the removal of the provider.
+ if (DEBUG_PROVIDER) {
+ Slog.v(TAG, "incProviderRef: stable "
+ + "snatched provider from the jaws of death");
+ }
+ prc.removePending = false;
+ mH.removeMessages(H.REMOVE_PROVIDER, prc);
+ } else {
+ unstableDelta = 0;
+ }
+ try {
+ if (DEBUG_PROVIDER) {
+ Slog.v(TAG, "incProviderRef Now stable - "
+ + prc.holder.info.name + ": unstableDelta="
+ + unstableDelta);
+ }
+ ActivityManagerNative.getDefault().refContentProvider(
+ prc.holder.connection, 1, unstableDelta);
+ } catch (RemoteException e) {
+ //do nothing content provider object is dead any way
+ }
+ }
+ } else {
+ prc.unstableCount += 1;
+ if (prc.unstableCount == 1) {
+ // We are acquiring a new unstable reference on the provider.
+ if (prc.removePending) {
+ // Oh look, we actually have a remove pending for the
+ // provider, which is still holding the last unstable
+ // reference. We just need to cancel that to take new
+ // ownership of the reference.
+ if (DEBUG_PROVIDER) {
+ Slog.v(TAG, "incProviderRef: unstable "
+ + "snatched provider from the jaws of death");
+ }
+ prc.removePending = false;
+ mH.removeMessages(H.REMOVE_PROVIDER, prc);
+ } else {
+ // First unstable ref, increment our count in the
+ // activity manager.
+ try {
+ if (DEBUG_PROVIDER) {
+ Slog.v(TAG, "incProviderRef: Now unstable - "
+ + prc.holder.info.name);
+ }
+ ActivityManagerNative.getDefault().refContentProvider(
+ prc.holder.connection, 0, 1);
+ } catch (RemoteException e) {
+ //do nothing content provider object is dead any way
+ }
+ }
+ }
+ }
+ }
+
+ public final IContentProvider acquireExistingProvider(Context c, String name,
+ boolean stable) {
synchronized (mProviderMap) {
ProviderClientRecord pr = mProviderMap.get(name);
if (pr == null) {
@@ -4232,23 +4313,14 @@
// provider is not reference counted and never needs to be released.
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
- prc.count += 1;
- if (prc.count == 1) {
- if (localLOGV) {
- Slog.v(TAG, "acquireExistingProvider: "
- + "snatched provider from the jaws of death");
- }
- // Because the provider previously had a reference count of zero,
- // it was scheduled to be removed. Cancel that.
- mH.removeMessages(H.REMOVE_PROVIDER, provider);
- }
+ incProviderRefLocked(prc, stable);
}
return provider;
}
}
- public final boolean releaseProvider(IContentProvider provider) {
- if(provider == null) {
+ public final boolean releaseProvider(IContentProvider provider, boolean stable) {
+ if (provider == null) {
return false;
}
@@ -4260,55 +4332,98 @@
return false;
}
- if (prc.count == 0) {
- if (localLOGV) Slog.v(TAG, "releaseProvider: ref count already 0, how?");
- return false;
+ boolean lastRef = false;
+ if (stable) {
+ if (prc.stableCount == 0) {
+ if (DEBUG_PROVIDER) Slog.v(TAG,
+ "releaseProvider: stable ref count already 0, how?");
+ return false;
+ }
+ prc.stableCount -= 1;
+ if (prc.stableCount == 0) {
+ // What we do at this point depends on whether there are
+ // any unstable refs left: if there are, we just tell the
+ // activity manager to decrement its stable count; if there
+ // aren't, we need to enqueue this provider to be removed,
+ // and convert to holding a single unstable ref while
+ // doing so.
+ lastRef = prc.unstableCount == 0;
+ try {
+ if (DEBUG_PROVIDER) {
+ Slog.v(TAG, "releaseProvider: No longer stable w/lastRef="
+ + lastRef + " - " + prc.holder.info.name);
+ }
+ ActivityManagerNative.getDefault().refContentProvider(
+ prc.holder.connection, -1, lastRef ? 1 : 0);
+ } catch (RemoteException e) {
+ //do nothing content provider object is dead any way
+ }
+ }
+ } else {
+ if (prc.unstableCount == 0) {
+ if (DEBUG_PROVIDER) Slog.v(TAG,
+ "releaseProvider: unstable ref count already 0, how?");
+ return false;
+ }
+ prc.unstableCount -= 1;
+ if (prc.unstableCount == 0) {
+ // If this is the last reference, we need to enqueue
+ // this provider to be removed instead of telling the
+ // activity manager to remove it at this point.
+ lastRef = prc.stableCount == 0;
+ if (!lastRef) {
+ try {
+ if (DEBUG_PROVIDER) {
+ Slog.v(TAG, "releaseProvider: No longer unstable - "
+ + prc.holder.info.name);
+ }
+ ActivityManagerNative.getDefault().refContentProvider(
+ prc.holder.connection, 0, -1);
+ } catch (RemoteException e) {
+ //do nothing content provider object is dead any way
+ }
+ }
+ }
}
- prc.count -= 1;
- if (prc.count == 0) {
- // Schedule the actual remove asynchronously, since we don't know the context
- // this will be called in.
- // TODO: it would be nice to post a delayed message, so
- // if we come back and need the same provider quickly
- // we will still have it available.
- Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, provider);
- mH.sendMessage(msg);
+ if (lastRef) {
+ if (!prc.removePending) {
+ // Schedule the actual remove asynchronously, since we don't know the context
+ // this will be called in.
+ // TODO: it would be nice to post a delayed message, so
+ // if we come back and need the same provider quickly
+ // we will still have it available.
+ if (DEBUG_PROVIDER) {
+ Slog.v(TAG, "releaseProvider: Enqueueing pending removal - "
+ + prc.holder.info.name);
+ }
+ prc.removePending = true;
+ Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, prc);
+ mH.sendMessage(msg);
+ } else {
+ Slog.w(TAG, "Duplicate remove pending of provider " + prc.holder.info.name);
+ }
}
return true;
}
}
- public final IContentProvider acquireUnstableProvider(Context c, String name) {
- return acquireProvider(c, name);
- }
-
- public final boolean releaseUnstableProvider(IContentProvider provider) {
- return releaseProvider(provider);
- }
-
- final void completeRemoveProvider(IContentProvider provider) {
- IBinder jBinder = provider.asBinder();
- String remoteProviderName = null;
- synchronized(mProviderMap) {
- ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
- if (prc == null) {
- // Either no release is needed (so we shouldn't be here) or the
- // provider was already released.
- if (localLOGV) Slog.v(TAG, "completeRemoveProvider: release not needed");
- return;
- }
-
- if (prc.count != 0) {
+ final void completeRemoveProvider(ProviderRefCount prc) {
+ synchronized (mProviderMap) {
+ if (!prc.removePending) {
// There was a race! Some other client managed to acquire
// the provider before the removal was completed.
// Abort the removal. We will do it later.
- if (localLOGV) Slog.v(TAG, "completeRemoveProvider: lost the race, "
+ if (DEBUG_PROVIDER) Slog.v(TAG, "completeRemoveProvider: lost the race, "
+ "provider still in use");
return;
}
- mProviderRefCountMap.remove(jBinder);
+ final IBinder jBinder = prc.holder.provider.asBinder();
+ ProviderRefCount existingPrc = mProviderRefCountMap.get(jBinder);
+ if (existingPrc == prc) {
+ mProviderRefCountMap.remove(jBinder);
+ }
Iterator<ProviderClientRecord> iter = mProviderMap.values().iterator();
while (iter.hasNext()) {
@@ -4316,41 +4431,70 @@
IBinder myBinder = pr.mProvider.asBinder();
if (myBinder == jBinder) {
iter.remove();
- if (pr.mLocalProvider == null) {
- myBinder.unlinkToDeath(pr, 0);
- if (remoteProviderName == null) {
- remoteProviderName = pr.mName;
+ }
+ }
+ }
+
+ try {
+ if (DEBUG_PROVIDER) {
+ Slog.v(TAG, "removeProvider: Invoking ActivityManagerNative."
+ + "removeContentProvider(" + prc.holder.info.name + ")");
+ }
+ ActivityManagerNative.getDefault().removeContentProvider(
+ prc.holder.connection, false);
+ } catch (RemoteException e) {
+ //do nothing content provider object is dead any way
+ }
+ }
+
+ final void handleUnstableProviderDied(IBinder provider, boolean fromClient) {
+ synchronized(mProviderMap) {
+ ProviderRefCount prc = mProviderRefCountMap.get(provider);
+ if (prc != null) {
+ if (DEBUG_PROVIDER) Slog.v(TAG, "Cleaning up dead provider "
+ + provider + " " + prc.holder.info.name);
+ mProviderRefCountMap.remove(provider);
+ if (prc.client != null && prc.client.mNames != null) {
+ for (String name : prc.client.mNames) {
+ ProviderClientRecord pr = mProviderMap.get(name);
+ if (pr != null && pr.mProvider.asBinder() == provider) {
+ Slog.i(TAG, "Removing dead content provider: " + name);
+ mProviderMap.remove(name);
}
}
}
+ if (fromClient) {
+ // We found out about this due to execution in our client
+ // code. Tell the activity manager about it now, to ensure
+ // that the next time we go to do anything with the provider
+ // it knows it is dead (so we don't race with its death
+ // notification).
+ try {
+ ActivityManagerNative.getDefault().unstableProviderDied(
+ prc.holder.connection);
+ } catch (RemoteException e) {
+ //do nothing content provider object is dead any way
+ }
+ }
}
}
-
- if (remoteProviderName != null) {
- try {
- if (localLOGV) {
- Slog.v(TAG, "removeProvider: Invoking ActivityManagerNative."
- + "removeContentProvider(" + remoteProviderName + ")");
- }
- ActivityManagerNative.getDefault().removeContentProvider(
- getApplicationThread(), remoteProviderName);
- } catch (RemoteException e) {
- //do nothing content provider object is dead any way
- }
- }
}
- final void removeDeadProvider(String name, IContentProvider provider) {
- synchronized(mProviderMap) {
- ProviderClientRecord pr = mProviderMap.get(name);
- if (pr != null && pr.mProvider.asBinder() == provider.asBinder()) {
- Slog.i(TAG, "Removing dead content provider: " + name);
- ProviderClientRecord removed = mProviderMap.remove(name);
- if (removed != null) {
- removed.mProvider.asBinder().unlinkToDeath(removed, 0);
- }
+ private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
+ ContentProvider localProvider,IActivityManager.ContentProviderHolder holder) {
+ String names[] = PATTERN_SEMICOLON.split(holder.info.authority);
+ ProviderClientRecord pcr = new ProviderClientRecord(names, provider,
+ localProvider, holder);
+ for (int i = 0; i < names.length; i++) {
+ ProviderClientRecord existing = mProviderMap.get(names[i]);
+ if (existing != null) {
+ Slog.w(TAG, "Content provider " + pcr.mHolder.info.name
+ + " already published as " + names[i]);
+ } else {
+ mProviderMap.put(names[i], pcr);
}
}
+ return pcr;
}
/**
@@ -4367,12 +4511,13 @@
* and returns the existing provider. This can happen due to concurrent
* attempts to acquire the same provider.
*/
- private IContentProvider installProvider(Context context,
- IContentProvider provider, ProviderInfo info,
- boolean noisy, boolean noReleaseNeeded) {
+ private IActivityManager.ContentProviderHolder installProvider(Context context,
+ IActivityManager.ContentProviderHolder holder, ProviderInfo info,
+ boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
- if (provider == null) {
- if (noisy) {
+ IContentProvider provider;
+ if (holder == null || holder.provider == null) {
+ if (DEBUG_PROVIDER || noisy) {
Slog.d(TAG, "Loading provider " + info.authority + ": "
+ info.name);
}
@@ -4409,7 +4554,7 @@
info.applicationInfo.sourceDir);
return null;
}
- if (false) Slog.v(
+ if (DEBUG_PROVIDER) Slog.v(
TAG, "Instantiating local provider " + info.name);
// XXX Need to create the correct context for this provider.
localProvider.attachInfo(c, info);
@@ -4421,76 +4566,72 @@
}
return null;
}
- } else if (localLOGV) {
- Slog.v(TAG, "Installing external provider " + info.authority + ": "
+ } else {
+ provider = holder.provider;
+ if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
+ info.name);
}
- synchronized (mProviderMap) {
- // There is a possibility that this thread raced with another thread to
- // add the provider. If we find another thread got there first then we
- // just get out of the way and return the original provider.
- IBinder jBinder = provider.asBinder();
- String names[] = PATTERN_SEMICOLON.split(info.authority);
- for (int i = 0; i < names.length; i++) {
- ProviderClientRecord pr = mProviderMap.get(names[i]);
- if (pr != null) {
- if (localLOGV) {
- Slog.v(TAG, "installProvider: lost the race, "
- + "using existing named provider");
- }
- provider = pr.mProvider;
- } else {
- pr = new ProviderClientRecord(names[i], provider, localProvider);
- if (localProvider == null) {
- try {
- jBinder.linkToDeath(pr, 0);
- } catch (RemoteException e) {
- // Provider already dead. Bail out of here without making
- // any changes to the provider map or other data structures.
- return null;
- }
- }
- mProviderMap.put(names[i], pr);
- }
- }
+ IActivityManager.ContentProviderHolder retHolder;
+ synchronized (mProviderMap) {
+ if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
+ + " / " + info.name);
+ IBinder jBinder = provider.asBinder();
if (localProvider != null) {
- ProviderClientRecord pr = mLocalProviders.get(jBinder);
+ ComponentName cname = new ComponentName(info.packageName, info.name);
+ ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
- if (localLOGV) {
+ if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, "
+ "using existing local provider");
}
provider = pr.mProvider;
} else {
- pr = new ProviderClientRecord(null, provider, localProvider);
+ holder = new IActivityManager.ContentProviderHolder(info);
+ holder.provider = provider;
+ holder.noReleaseNeeded = true;
+ pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
mLocalProviders.put(jBinder, pr);
+ mLocalProvidersByName.put(cname, pr);
}
- }
-
- if (!noReleaseNeeded) {
+ retHolder = pr.mHolder;
+ } else {
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
- if (localLOGV) {
- Slog.v(TAG, "installProvider: lost the race, incrementing ref count");
+ if (DEBUG_PROVIDER) {
+ Slog.v(TAG, "installProvider: lost the race, updating ref count");
}
- prc.count += 1;
- if (prc.count == 1) {
- if (localLOGV) {
- Slog.v(TAG, "installProvider: "
- + "snatched provider from the jaws of death");
+ // We need to transfer our new reference to the existing
+ // ref count, releasing the old one... but only if
+ // release is needed (that is, it is not running in the
+ // system process).
+ if (!noReleaseNeeded) {
+ incProviderRefLocked(prc, stable);
+ try {
+ ActivityManagerNative.getDefault().removeContentProvider(
+ holder.connection, stable);
+ } catch (RemoteException e) {
+ //do nothing content provider object is dead any way
}
- // Because the provider previously had a reference count of zero,
- // it was scheduled to be removed. Cancel that.
- mH.removeMessages(H.REMOVE_PROVIDER, provider);
}
} else {
- mProviderRefCountMap.put(jBinder, new ProviderRefCount(1));
+ ProviderClientRecord client = installProviderAuthoritiesLocked(
+ provider, localProvider, holder);
+ if (noReleaseNeeded) {
+ prc = new ProviderRefCount(holder, client, 1000, 1000);
+ } else {
+ prc = stable
+ ? new ProviderRefCount(holder, client, 1, 0)
+ : new ProviderRefCount(holder, client, 0, 1);
+ }
+ mProviderRefCountMap.put(jBinder, prc);
}
+ retHolder = prc.holder;
}
}
- return provider;
+
+ return retHolder;
}
private void attach(boolean system) {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 437362b..3e726e0 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -575,6 +575,15 @@
reply.writeNoException();
return true;
}
+
+ case UNSTABLE_PROVIDER_DIED_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ IBinder provider = data.readStrongBinder();
+ unstableProviderDied(provider);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -1163,4 +1172,12 @@
mRemote.transact(DUMP_DB_INFO_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
data.recycle();
}
+
+ public void unstableProviderDied(IBinder provider) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeStrongBinder(provider);
+ mRemote.transact(UNSTABLE_PROVIDER_DIED_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 299e408..4c35a8c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1679,27 +1679,32 @@
@Override
protected IContentProvider acquireProvider(Context context, String name) {
- return mMainThread.acquireProvider(context, name);
+ return mMainThread.acquireProvider(context, name, true);
}
@Override
protected IContentProvider acquireExistingProvider(Context context, String name) {
- return mMainThread.acquireExistingProvider(context, name);
+ return mMainThread.acquireExistingProvider(context, name, true);
}
@Override
public boolean releaseProvider(IContentProvider provider) {
- return mMainThread.releaseProvider(provider);
+ return mMainThread.releaseProvider(provider, true);
}
@Override
protected IContentProvider acquireUnstableProvider(Context c, String name) {
- return mMainThread.acquireUnstableProvider(c, name);
+ return mMainThread.acquireProvider(c, name, false);
}
@Override
public boolean releaseUnstableProvider(IContentProvider icp) {
- return mMainThread.releaseUnstableProvider(icp);
+ return mMainThread.releaseProvider(icp, false);
+ }
+
+ @Override
+ public void unstableProviderDied(IContentProvider icp) {
+ mMainThread.handleUnstableProviderDied(icp.asBinder(), true);
}
private final ActivityThread mMainThread;
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index cf304df..609a047 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -116,14 +116,16 @@
public void reportThumbnail(IBinder token,
Bitmap thumbnail, CharSequence description) throws RemoteException;
public ContentProviderHolder getContentProvider(IApplicationThread caller,
- String name) throws RemoteException;
+ String name, boolean stable) throws RemoteException;
public ContentProviderHolder getContentProviderExternal(String name, IBinder token)
throws RemoteException;
- public void removeContentProvider(IApplicationThread caller,
- String name) throws RemoteException;
+ public void removeContentProvider(IBinder connection, boolean stable) throws RemoteException;
public void removeContentProviderExternal(String name, IBinder token) throws RemoteException;
public void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) throws RemoteException;
+ public boolean refContentProvider(IBinder connection, int stableDelta, int unstableDelta)
+ throws RemoteException;
+ public void unstableProviderDied(IBinder connection) throws RemoteException;
public PendingIntent getRunningServiceControlPanel(ComponentName service)
throws RemoteException;
public ComponentName startService(IApplicationThread caller, Intent service,
@@ -363,6 +365,7 @@
public static class ContentProviderHolder implements Parcelable {
public final ProviderInfo info;
public IContentProvider provider;
+ public IBinder connection;
public boolean noReleaseNeeded;
public ContentProviderHolder(ProviderInfo _info) {
@@ -380,6 +383,7 @@
} else {
dest.writeStrongBinder(null);
}
+ dest.writeStrongBinder(connection);
dest.writeInt(noReleaseNeeded ? 1:0);
}
@@ -398,6 +402,7 @@
info = ProviderInfo.CREATOR.createFromParcel(source);
provider = ContentProviderNative.asInterface(
source.readStrongBinder());
+ connection = source.readStrongBinder();
noReleaseNeeded = source.readInt() != 0;
}
}
@@ -476,7 +481,7 @@
int REPORT_THUMBNAIL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+27;
int GET_CONTENT_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+28;
int PUBLISH_CONTENT_PROVIDERS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29;
-
+ int REF_CONTENT_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
int FINISH_SUB_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31;
int GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32;
int START_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33;
@@ -597,4 +602,5 @@
int SET_LOCK_SCREEN_SHOWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+147;
int FINISH_ACTIVITY_AFFINITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+148;
int GET_LAUNCHED_FROM_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+149;
+ int UNSTABLE_PROVIDER_DIED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+150;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 70029d2..f60cfd6 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -128,6 +128,7 @@
String[] args) throws RemoteException;
void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
void dumpDbInfo(FileDescriptor fd, String[] args) throws RemoteException;
+ void unstableProviderDied(IBinder provider) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -176,4 +177,5 @@
int DUMP_GFX_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+43;
int DUMP_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+44;
int DUMP_DB_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+45;
+ int UNSTABLE_PROVIDER_DIED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+46;
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 75c6e11..cad4b01 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -987,7 +987,12 @@
/**
* Perform calling of the application's {@link Application#onCreate}
* method. The default implementation simply calls through to that method.
- *
+ *
+ * <p>Note: This method will be called immediately after {@link #onCreate(Bundle)}.
+ * Often instrumentation tests start their test thread in onCreate(); you
+ * need to be careful of races between these. (Well between it and
+ * everything else, but let's start here.)
+ *
* @param app The application being created.
*/
public void callApplicationOnCreate(Application app) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3ced82b..036008b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1379,7 +1379,7 @@
}
}
- private RemoteViews applyStandardTemplate(int resId) {
+ private RemoteViews applyStandardTemplate(int resId, boolean fitIn1U) {
RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
boolean showLine3 = false;
boolean showLine2 = false;
@@ -1432,7 +1432,6 @@
contentView.setTextViewText(R.id.text, mSubText);
if (mContentText != null) {
contentView.setTextViewText(R.id.text2, mContentText);
- // need to shrink all the type to make sure everything fits
contentView.setViewVisibility(R.id.text2, View.VISIBLE);
showLine2 = true;
} else {
@@ -1450,10 +1449,13 @@
}
}
if (showLine2) {
- final Resources res = mContext.getResources();
- final float subTextSize = res.getDimensionPixelSize(
- R.dimen.notification_subtext_size);
- contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize);
+ if (fitIn1U) {
+ // need to shrink all the type to make sure everything fits
+ final Resources res = mContext.getResources();
+ final float subTextSize = res.getDimensionPixelSize(
+ R.dimen.notification_subtext_size);
+ contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize);
+ }
// vertical centering
contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
}
@@ -1470,16 +1472,18 @@
}
}
contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
+ contentView.setViewVisibility(R.id.overflow_divider, showLine3 ? View.VISIBLE : View.GONE);
return contentView;
}
private RemoteViews applyStandardTemplateWithActions(int layoutId) {
- RemoteViews big = applyStandardTemplate(layoutId);
+ RemoteViews big = applyStandardTemplate(layoutId, false);
int N = mActions.size();
if (N > 0) {
// Log.d("Notification", "has actions: " + mContentText);
big.setViewVisibility(R.id.actions, View.VISIBLE);
+ big.setViewVisibility(R.id.action_divider, View.VISIBLE);
if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
big.removeAllViews(R.id.actions);
for (int i=0; i<N; i++) {
@@ -1495,7 +1499,7 @@
if (mContentView != null) {
return mContentView;
} else {
- return applyStandardTemplate(R.layout.notification_template_base); // no more special large_icon flavor
+ return applyStandardTemplate(R.layout.notification_template_base, true); // no more special large_icon flavor
}
}
@@ -1506,7 +1510,7 @@
if (mContentView == null) {
return applyStandardTemplate(mLargeIcon == null
? R.layout.status_bar_latest_event_ticker
- : R.layout.status_bar_latest_event_ticker_large_icon);
+ : R.layout.status_bar_latest_event_ticker_large_icon, true);
} else {
return null;
}
@@ -1655,12 +1659,9 @@
contentView.setViewVisibility(R.id.line1, View.VISIBLE);
}
+ // The last line defaults to the content text or subtext, but can be replaced by mSummaryText
if (mSummaryText != null && !mSummaryText.equals("")) {
- contentView.setViewVisibility(R.id.overflow_title, View.VISIBLE);
- contentView.setTextViewText(R.id.overflow_title, mSummaryText);
- contentView.setViewVisibility(R.id.line3, View.GONE);
- } else {
- contentView.setViewVisibility(R.id.overflow_title, View.GONE);
+ contentView.setTextViewText(R.id.text, mSummaryText);
contentView.setViewVisibility(R.id.line3, View.VISIBLE);
}
@@ -1801,6 +1802,8 @@
}
private RemoteViews makeBigContentView() {
+ // Remove the content text so line3 disappears entirely
+ mBuilder.mContentText = null;
RemoteViews contentView = getStandardView(R.layout.notification_template_big_text);
contentView.setTextViewText(R.id.big_text, mBigText);
contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 6eebed2..be8108c 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -145,8 +145,10 @@
try {
IRestoreSession binder = sService.beginRestoreSession(mContext.getPackageName(),
null);
- session = new RestoreSession(mContext, binder);
- result = session.restorePackage(mContext.getPackageName(), observer);
+ if (binder != null) {
+ session = new RestoreSession(mContext, binder);
+ result = session.restorePackage(mContext.getPackageName(), observer);
+ }
} catch (RemoteException e) {
Log.w(TAG, "restoreSelf() unable to contact service");
} finally {
@@ -170,7 +172,9 @@
try {
// All packages, current transport
IRestoreSession binder = sService.beginRestoreSession(null, null);
- session = new RestoreSession(mContext, binder);
+ if (binder != null) {
+ session = new RestoreSession(mContext, binder);
+ }
} catch (RemoteException e) {
Log.w(TAG, "beginRestoreSession() couldn't connect");
}
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 423f1f6..5c315ce 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -20,6 +20,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
+import android.os.DeadObjectException;
import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.os.ParcelFileDescriptor;
@@ -33,11 +34,19 @@
* calling {@link ContentResolver#acquireContentProviderClient}. This object must be released
* using {@link #release} in order to indicate to the system that the {@link ContentProvider} is
* no longer needed and can be killed to free up resources.
+ *
+ * <p>Note that you should generally create a new ContentProviderClient instance
+ * for each thread that will be performing operations. Unlike
+ * {@link ContentResolver}, the methods here such as {@link #query} and
+ * {@link #openFile} are not thread safe -- you must not call
+ * {@link #release()} on the ContentProviderClient those calls are made from
+ * until you are finished with the data they have returned.
*/
public class ContentProviderClient {
private final IContentProvider mContentProvider;
private final ContentResolver mContentResolver;
private final boolean mStable;
+ private boolean mReleased;
/**
* @hide
@@ -52,7 +61,14 @@
/** See {@link ContentProvider#query ContentProvider.query} */
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder) throws RemoteException {
- return query(url, projection, selection, selectionArgs, sortOrder, null);
+ try {
+ return query(url, projection, selection, selectionArgs, sortOrder, null);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
}
/** See {@link ContentProvider#query ContentProvider.query} */
@@ -64,41 +80,90 @@
remoteCancellationSignal = mContentProvider.createCancellationSignal();
cancellationSignal.setRemote(remoteCancellationSignal);
}
- return mContentProvider.query(url, projection, selection, selectionArgs, sortOrder,
- remoteCancellationSignal);
+ try {
+ return mContentProvider.query(url, projection, selection, selectionArgs, sortOrder,
+ remoteCancellationSignal);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
}
/** See {@link ContentProvider#getType ContentProvider.getType} */
public String getType(Uri url) throws RemoteException {
- return mContentProvider.getType(url);
+ try {
+ return mContentProvider.getType(url);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
}
/** See {@link ContentProvider#getStreamTypes ContentProvider.getStreamTypes} */
public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException {
- return mContentProvider.getStreamTypes(url, mimeTypeFilter);
+ try {
+ return mContentProvider.getStreamTypes(url, mimeTypeFilter);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
}
/** See {@link ContentProvider#insert ContentProvider.insert} */
public Uri insert(Uri url, ContentValues initialValues)
throws RemoteException {
- return mContentProvider.insert(url, initialValues);
+ try {
+ return mContentProvider.insert(url, initialValues);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
}
/** See {@link ContentProvider#bulkInsert ContentProvider.bulkInsert} */
public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException {
- return mContentProvider.bulkInsert(url, initialValues);
+ try {
+ return mContentProvider.bulkInsert(url, initialValues);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
}
/** See {@link ContentProvider#delete ContentProvider.delete} */
public int delete(Uri url, String selection, String[] selectionArgs)
throws RemoteException {
- return mContentProvider.delete(url, selection, selectionArgs);
+ try {
+ return mContentProvider.delete(url, selection, selectionArgs);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
}
/** See {@link ContentProvider#update ContentProvider.update} */
public int update(Uri url, ContentValues values, String selection,
String[] selectionArgs) throws RemoteException {
- return mContentProvider.update(url, values, selection, selectionArgs);
+ try {
+ return mContentProvider.update(url, values, selection, selectionArgs);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
}
/**
@@ -110,7 +175,14 @@
*/
public ParcelFileDescriptor openFile(Uri url, String mode)
throws RemoteException, FileNotFoundException {
- return mContentProvider.openFile(url, mode);
+ try {
+ return mContentProvider.openFile(url, mode);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
}
/**
@@ -122,20 +194,41 @@
*/
public AssetFileDescriptor openAssetFile(Uri url, String mode)
throws RemoteException, FileNotFoundException {
- return mContentProvider.openAssetFile(url, mode);
+ try {
+ return mContentProvider.openAssetFile(url, mode);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
}
/** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
String mimeType, Bundle opts)
throws RemoteException, FileNotFoundException {
- return mContentProvider.openTypedAssetFile(uri, mimeType, opts);
+ try {
+ return mContentProvider.openTypedAssetFile(uri, mimeType, opts);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
}
/** See {@link ContentProvider#applyBatch ContentProvider.applyBatch} */
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException {
- return mContentProvider.applyBatch(operations);
+ try {
+ return mContentProvider.applyBatch(operations);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
}
/**
@@ -144,10 +237,16 @@
* @return true if this was release, false if it was already released
*/
public boolean release() {
- if (mStable) {
- return mContentResolver.releaseProvider(mContentProvider);
- } else {
- return mContentResolver.releaseUnstableProvider(mContentProvider);
+ synchronized (this) {
+ if (mReleased) {
+ throw new IllegalStateException("Already released");
+ }
+ mReleased = true;
+ if (mStable) {
+ return mContentResolver.releaseProvider(mContentProvider);
+ } else {
+ return mContentResolver.releaseUnstableProvider(mContentProvider);
+ }
}
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f509fd8..34b5a30 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -20,27 +20,24 @@
import android.accounts.Account;
import android.app.ActivityManagerNative;
-import android.app.ActivityThread;
import android.app.AppGlobals;
-import android.content.ContentProvider.Transport;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.CrossProcessCursorWrapper;
import android.database.Cursor;
-import android.database.CursorWrapper;
import android.database.IContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
+import android.os.DeadObjectException;
import android.os.IBinder;
import android.os.ICancellationSignal;
import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.StrictMode;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.EventLog;
@@ -202,6 +199,8 @@
protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
/** @hide */
public abstract boolean releaseUnstableProvider(IContentProvider icp);
+ /** @hide */
+ public abstract void unstableProviderDied(IContentProvider icp);
/**
* Return the MIME type of the given content URL.
@@ -211,6 +210,7 @@
* @return A MIME type for the content, or null if the URL is invalid or the type is unknown
*/
public final String getType(Uri url) {
+ // XXX would like to have an acquireExistingUnstableProvider for this.
IContentProvider provider = acquireExistingProvider(url);
if (provider != null) {
try {
@@ -351,23 +351,37 @@
public final Cursor query(final Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
CancellationSignal cancellationSignal) {
- IContentProvider provider = acquireProvider(uri);
- if (provider == null) {
+ IContentProvider unstableProvider = acquireUnstableProvider(uri);
+ if (unstableProvider == null) {
return null;
}
+ IContentProvider stableProvider = null;
try {
long startTime = SystemClock.uptimeMillis();
ICancellationSignal remoteCancellationSignal = null;
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
- remoteCancellationSignal = provider.createCancellationSignal();
+ remoteCancellationSignal = unstableProvider.createCancellationSignal();
cancellationSignal.setRemote(remoteCancellationSignal);
}
- Cursor qCursor = provider.query(uri, projection,
- selection, selectionArgs, sortOrder, remoteCancellationSignal);
+ Cursor qCursor;
+ try {
+ qCursor = unstableProvider.query(uri, projection,
+ selection, selectionArgs, sortOrder, remoteCancellationSignal);
+ } catch (DeadObjectException e) {
+ // The remote process has died... but we only hold an unstable
+ // reference though, so we might recover!!! Let's try!!!!
+ // This is exciting!!1!!1!!!!1
+ unstableProviderDied(unstableProvider);
+ stableProvider = acquireProvider(uri);
+ if (stableProvider == null) {
+ return null;
+ }
+ qCursor = stableProvider.query(uri, projection,
+ selection, selectionArgs, sortOrder, remoteCancellationSignal);
+ }
if (qCursor == null) {
- releaseProvider(provider);
return null;
}
// force query execution
@@ -375,16 +389,21 @@
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
// Wrap the cursor object into CursorWrapperInner object
- return new CursorWrapperInner(qCursor, provider);
+ CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
+ stableProvider != null ? stableProvider : acquireProvider(uri));
+ stableProvider = null;
+ return wrapper;
} catch (RemoteException e) {
- releaseProvider(provider);
-
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
return null;
- } catch (RuntimeException e) {
- releaseProvider(provider);
- throw e;
+ } finally {
+ if (unstableProvider != null) {
+ releaseUnstableProvider(unstableProvider);
+ }
+ if (stableProvider != null) {
+ releaseProvider(stableProvider);
+ }
}
}
@@ -592,49 +611,63 @@
if ("r".equals(mode)) {
return openTypedAssetFileDescriptor(uri, "*/*", null);
} else {
- int n = 0;
- while (true) {
- n++;
- IContentProvider provider = acquireUnstableProvider(uri);
- if (provider == null) {
- throw new FileNotFoundException("No content provider: " + uri);
- }
+ IContentProvider unstableProvider = acquireUnstableProvider(uri);
+ if (unstableProvider == null) {
+ throw new FileNotFoundException("No content provider: " + uri);
+ }
+ IContentProvider stableProvider = null;
+ AssetFileDescriptor fd = null;
+
+ try {
try {
- AssetFileDescriptor fd = provider.openAssetFile(uri, mode);
+ fd = unstableProvider.openAssetFile(uri, mode);
if (fd == null) {
// The provider will be released by the finally{} clause
return null;
}
- ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
- fd.getParcelFileDescriptor(), provider);
-
- // Success! Don't release the provider when exiting, let
- // ParcelFileDescriptorInner do that when it is closed.
- provider = null;
-
- return new AssetFileDescriptor(pfd, fd.getStartOffset(),
- fd.getDeclaredLength());
- } catch (RemoteException e) {
- // The provider died for some reason. Since we are
- // acquiring it unstable, its process could have gotten
- // killed and need to be restarted. We'll retry a couple
- // times and if still can't succeed then fail.
- if (n <= 2) {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e1) {
- }
- continue;
+ } catch (DeadObjectException e) {
+ // The remote process has died... but we only hold an unstable
+ // reference though, so we might recover!!! Let's try!!!!
+ // This is exciting!!1!!1!!!!1
+ unstableProviderDied(unstableProvider);
+ stableProvider = acquireProvider(uri);
+ if (stableProvider == null) {
+ throw new FileNotFoundException("No content provider: " + uri);
}
- // Whatever, whatever, we'll go away.
- throw new FileNotFoundException("Dead content provider: " + uri);
- } catch (FileNotFoundException e) {
- throw e;
- } finally {
- if (provider != null) {
- releaseUnstableProvider(provider);
+ fd = stableProvider.openAssetFile(uri, mode);
+ if (fd == null) {
+ // The provider will be released by the finally{} clause
+ return null;
}
}
+
+ if (stableProvider == null) {
+ stableProvider = acquireProvider(uri);
+ }
+ releaseUnstableProvider(unstableProvider);
+ ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
+ fd.getParcelFileDescriptor(), stableProvider);
+
+ // Success! Don't release the provider when exiting, let
+ // ParcelFileDescriptorInner do that when it is closed.
+ stableProvider = null;
+
+ return new AssetFileDescriptor(pfd, fd.getStartOffset(),
+ fd.getDeclaredLength());
+
+ } catch (RemoteException e) {
+ // Whatever, whatever, we'll go away.
+ throw new FileNotFoundException(
+ "Failed opening content provider: " + uri);
+ } catch (FileNotFoundException e) {
+ throw e;
+ } finally {
+ if (stableProvider != null) {
+ releaseProvider(stableProvider);
+ }
+ if (unstableProvider != null) {
+ releaseUnstableProvider(unstableProvider);
+ }
}
}
}
@@ -670,49 +703,63 @@
*/
public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
String mimeType, Bundle opts) throws FileNotFoundException {
- int n = 0;
- while (true) {
- n++;
- IContentProvider provider = acquireUnstableProvider(uri);
- if (provider == null) {
- throw new FileNotFoundException("No content provider: " + uri);
- }
+ IContentProvider unstableProvider = acquireUnstableProvider(uri);
+ if (unstableProvider == null) {
+ throw new FileNotFoundException("No content provider: " + uri);
+ }
+ IContentProvider stableProvider = null;
+ AssetFileDescriptor fd = null;
+
+ try {
try {
- AssetFileDescriptor fd = provider.openTypedAssetFile(uri, mimeType, opts);
+ fd = unstableProvider.openTypedAssetFile(uri, mimeType, opts);
if (fd == null) {
// The provider will be released by the finally{} clause
return null;
}
- ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
- fd.getParcelFileDescriptor(), provider);
-
- // Success! Don't release the provider when exiting, let
- // ParcelFileDescriptorInner do that when it is closed.
- provider = null;
-
- return new AssetFileDescriptor(pfd, fd.getStartOffset(),
- fd.getDeclaredLength());
- } catch (RemoteException e) {
- // The provider died for some reason. Since we are
- // acquiring it unstable, its process could have gotten
- // killed and need to be restarted. We'll retry a couple
- // times and if still can't succeed then fail.
- if (n <= 2) {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e1) {
- }
- continue;
+ } catch (DeadObjectException e) {
+ // The remote process has died... but we only hold an unstable
+ // reference though, so we might recover!!! Let's try!!!!
+ // This is exciting!!1!!1!!!!1
+ unstableProviderDied(unstableProvider);
+ stableProvider = acquireProvider(uri);
+ if (stableProvider == null) {
+ throw new FileNotFoundException("No content provider: " + uri);
}
- // Whatever, whatever, we'll go away.
- throw new FileNotFoundException("Dead content provider: " + uri);
- } catch (FileNotFoundException e) {
- throw e;
- } finally {
- if (provider != null) {
- releaseUnstableProvider(provider);
+ fd = stableProvider.openTypedAssetFile(uri, mimeType, opts);
+ if (fd == null) {
+ // The provider will be released by the finally{} clause
+ return null;
}
}
+
+ if (stableProvider == null) {
+ stableProvider = acquireProvider(uri);
+ }
+ releaseUnstableProvider(unstableProvider);
+ ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
+ fd.getParcelFileDescriptor(), stableProvider);
+
+ // Success! Don't release the provider when exiting, let
+ // ParcelFileDescriptorInner do that when it is closed.
+ stableProvider = null;
+
+ return new AssetFileDescriptor(pfd, fd.getStartOffset(),
+ fd.getDeclaredLength());
+
+ } catch (RemoteException e) {
+ // Whatever, whatever, we'll go away.
+ throw new FileNotFoundException(
+ "Failed opening content provider: " + uri);
+ } catch (FileNotFoundException e) {
+ throw e;
+ } finally {
+ if (stableProvider != null) {
+ releaseProvider(stableProvider);
+ }
+ if (unstableProvider != null) {
+ releaseUnstableProvider(unstableProvider);
+ }
}
}
@@ -1061,7 +1108,7 @@
if (name == null) {
return null;
}
- return acquireProvider(mContext, name);
+ return acquireUnstableProvider(mContext, name);
}
/**
@@ -1113,10 +1160,15 @@
* use it as needed and it won't disappear, even if your process is in the
* background. If using this method, you need to take care to deal with any
* failures when communicating with the provider, and be sure to close it
- * so that it can be re-opened later.
+ * so that it can be re-opened later. In particular, catching a
+ * {@link android.os.DeadObjectException} from the calls there will let you
+ * know that the content provider has gone away; at that point the current
+ * ContentProviderClient object is invalid, and you should release it. You
+ * can acquire a new one if you would like to try to restart the provider
+ * and perform new operations on it.
*/
public final ContentProviderClient acquireUnstableContentProviderClient(Uri uri) {
- IContentProvider provider = acquireProvider(uri);
+ IContentProvider provider = acquireUnstableProvider(uri);
if (provider != null) {
return new ContentProviderClient(this, provider, false);
}
@@ -1133,10 +1185,15 @@
* use it as needed and it won't disappear, even if your process is in the
* background. If using this method, you need to take care to deal with any
* failures when communicating with the provider, and be sure to close it
- * so that it can be re-opened later.
+ * so that it can be re-opened later. In particular, catching a
+ * {@link android.os.DeadObjectException} from the calls there will let you
+ * know that the content provider has gone away; at that point the current
+ * ContentProviderClient object is invalid, and you should release it. You
+ * can acquire a new one if you would like to try to restart the provider
+ * and perform new operations on it.
*/
public final ContentProviderClient acquireUnstableContentProviderClient(String name) {
- IContentProvider provider = acquireProvider(name);
+ IContentProvider provider = acquireUnstableProvider(name);
if (provider != null) {
return new ContentProviderClient(this, provider, false);
}
@@ -1780,7 +1837,6 @@
private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
private final IContentProvider mContentProvider;
- public static final String TAG="ParcelFileDescriptorInner";
private boolean mReleaseProviderFlag = false;
ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
@@ -1792,7 +1848,7 @@
public void close() throws IOException {
if(!mReleaseProviderFlag) {
super.close();
- ContentResolver.this.releaseUnstableProvider(mContentProvider);
+ ContentResolver.this.releaseProvider(mContentProvider);
mReleaseProviderFlag = true;
}
}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 89068e7..035a7c6 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1059,6 +1059,7 @@
}
native_takePicture(msgType);
+ mFaceDetectionRunning = false;
}
/**
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 33dea6c..46153e7 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1892,6 +1892,13 @@
* {@link KeyEvent#FLAG_KEEP_TOUCH_MODE KeyEvent.FLAG_KEEP_TOUCH_MODE}, so
* that they don't impact the current touch mode of the UI.
*
+ * <p>Note that it's discouraged to send such key events in normal operation;
+ * this is mainly for use with {@link android.text.InputType#TYPE_NULL} type
+ * text fields, or for non-rich input methods. A reasonably capable software
+ * input method should use the
+ * {@link android.view.inputmethod.InputConnection#commitText} family of methods
+ * to send text to an application, rather than sending key events.</p>
+ *
* @param keyEventCode The raw key code to send, as defined by
* {@link KeyEvent}.
*/
@@ -1949,7 +1956,11 @@
* {@link InputConnection#commitText InputConnection.commitText()} with
* the character; some, however, may be handled different. In particular,
* the enter character ('\n') will either be delivered as an action code
- * or a raw key event, as appropriate.
+ * or a raw key event, as appropriate. Consider this as a convenience
+ * method for IMEs that do not have a full implementation of actions; a
+ * fully complying IME will decide of the right action for each event and
+ * will likely never call this method except maybe to handle events coming
+ * from an actual hardware keyboard.
*
* @param charCode The UTF-16 character code to send.
*/
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 7e29dc7..4fede32 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -28,6 +28,10 @@
* Provides a basic foundation for entering and editing text.
* Subclasses should override {@link #onKeyDown} and {@link #onKeyUp} to insert
* characters as keys are pressed.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public abstract class BaseKeyListener extends MetaKeyKeyListener
implements KeyListener {
diff --git a/core/java/android/text/method/DateKeyListener.java b/core/java/android/text/method/DateKeyListener.java
index 7c11434..e6f63d1 100644
--- a/core/java/android/text/method/DateKeyListener.java
+++ b/core/java/android/text/method/DateKeyListener.java
@@ -21,6 +21,10 @@
/**
* For entering dates in a text field.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class DateKeyListener extends NumberKeyListener
{
diff --git a/core/java/android/text/method/DateTimeKeyListener.java b/core/java/android/text/method/DateTimeKeyListener.java
index f8ebc40..523e986 100644
--- a/core/java/android/text/method/DateTimeKeyListener.java
+++ b/core/java/android/text/method/DateTimeKeyListener.java
@@ -21,6 +21,10 @@
/**
* For entering dates and times in the same text field.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class DateTimeKeyListener extends NumberKeyListener
{
diff --git a/core/java/android/text/method/DialerKeyListener.java b/core/java/android/text/method/DialerKeyListener.java
index 07127b7..ce51fae 100644
--- a/core/java/android/text/method/DialerKeyListener.java
+++ b/core/java/android/text/method/DialerKeyListener.java
@@ -23,6 +23,10 @@
/**
* For dialing-only text entry
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class DialerKeyListener extends NumberKeyListener
{
diff --git a/core/java/android/text/method/DigitsKeyListener.java b/core/java/android/text/method/DigitsKeyListener.java
index f0f072c..3d9daed 100644
--- a/core/java/android/text/method/DigitsKeyListener.java
+++ b/core/java/android/text/method/DigitsKeyListener.java
@@ -24,6 +24,10 @@
/**
* For digits-only text entry
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class DigitsKeyListener extends NumberKeyListener
{
diff --git a/core/java/android/text/method/KeyListener.java b/core/java/android/text/method/KeyListener.java
index 318149a..bb79ecd 100644
--- a/core/java/android/text/method/KeyListener.java
+++ b/core/java/android/text/method/KeyListener.java
@@ -27,6 +27,12 @@
* {@link android.view.inputmethod.InputMethod}; it should only be used
* for cases where an application has its own on-screen keypad and also wants
* to process hard keyboard events to match it.
+ * <p></p>
+ * Key presses on soft input methods are not required to trigger the methods
+ * in this listener, and are in fact discouraged to do so. The default
+ * android keyboard will not trigger these for any key to any application
+ * targetting Jelly Bean or later, and will only deliver it for some
+ * key presses to applications targetting Ice Cream Sandwich or earlier.
*/
public interface KeyListener {
/**
diff --git a/core/java/android/text/method/MultiTapKeyListener.java b/core/java/android/text/method/MultiTapKeyListener.java
index 2a739fa..95ac0a1 100644
--- a/core/java/android/text/method/MultiTapKeyListener.java
+++ b/core/java/android/text/method/MultiTapKeyListener.java
@@ -28,6 +28,10 @@
* This is the standard key listener for alphabetic input on 12-key
* keyboards. You should generally not need to instantiate this yourself;
* TextKeyListener will do it for you.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class MultiTapKeyListener extends BaseKeyListener
implements SpanWatcher {
diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java
index 1e72309..5d4c732 100644
--- a/core/java/android/text/method/NumberKeyListener.java
+++ b/core/java/android/text/method/NumberKeyListener.java
@@ -27,6 +27,10 @@
/**
* For numeric text entry
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public abstract class NumberKeyListener extends BaseKeyListener
implements InputFilter
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 4c82b81..c5261f3 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -27,6 +27,10 @@
* This is the standard key listener for alphabetic input on qwerty
* keyboards. You should generally not need to instantiate this yourself;
* TextKeyListener will do it for you.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class QwertyKeyListener extends BaseKeyListener {
private static QwertyKeyListener[] sInstance =
diff --git a/core/java/android/text/method/TextKeyListener.java b/core/java/android/text/method/TextKeyListener.java
index 8312fe1..994f3d7 100644
--- a/core/java/android/text/method/TextKeyListener.java
+++ b/core/java/android/text/method/TextKeyListener.java
@@ -33,6 +33,10 @@
/**
* This is the key listener for typing normal text. It delegates to
* other key listeners appropriate to the current keyboard and language.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class TextKeyListener extends BaseKeyListener implements SpanWatcher {
private static TextKeyListener[] sInstance =
diff --git a/core/java/android/text/method/TimeKeyListener.java b/core/java/android/text/method/TimeKeyListener.java
index 3fbfd8c..c5bfd5c 100644
--- a/core/java/android/text/method/TimeKeyListener.java
+++ b/core/java/android/text/method/TimeKeyListener.java
@@ -21,6 +21,10 @@
/**
* For entering times in a text field.
+ * <p></p>
+ * As for all implementations of {@link KeyListener}, this class is only concerned
+ * with hardware keyboards. Software input methods have no obligation to trigger
+ * the methods in this class.
*/
public class TimeKeyListener extends NumberKeyListener
{
diff --git a/core/java/android/view/AccessibilityIterators.java b/core/java/android/view/AccessibilityIterators.java
index cd54f24..2a7dc18 100644
--- a/core/java/android/view/AccessibilityIterators.java
+++ b/core/java/android/view/AccessibilityIterators.java
@@ -47,7 +47,6 @@
* @hide
*/
public static abstract class AbstractTextSegmentIterator implements TextSegmentIterator {
- protected static final int DONE = -1;
protected String mText;
@@ -104,20 +103,20 @@
if (offset >= textLegth) {
return null;
}
- int start = -1;
- if (offset < 0) {
- offset = 0;
- if (mImpl.isBoundary(offset)) {
- start = offset;
+ int start = offset;
+ if (start < 0) {
+ start = 0;
+ }
+ while (!mImpl.isBoundary(start)) {
+ start = mImpl.following(start);
+ if (start == BreakIterator.DONE) {
+ return null;
}
}
- if (start < 0) {
- start = mImpl.following(offset);
- }
- if (start < 0) {
+ final int end = mImpl.following(start);
+ if (end == BreakIterator.DONE) {
return null;
}
- final int end = mImpl.following(start);
return getRange(start, end);
}
@@ -130,20 +129,20 @@
if (offset <= 0) {
return null;
}
- int end = -1;
- if (offset > mText.length()) {
- offset = mText.length();
- if (mImpl.isBoundary(offset)) {
- end = offset;
+ int end = offset;
+ if (end > textLegth) {
+ end = textLegth;
+ }
+ while (!mImpl.isBoundary(end)) {
+ end = mImpl.preceding(end);
+ if (end == BreakIterator.DONE) {
+ return null;
}
}
- if (end < 0) {
- end = mImpl.preceding(offset);
- }
- if (end < 0) {
+ final int start = mImpl.preceding(end);
+ if (start == BreakIterator.DONE) {
return null;
}
- final int start = mImpl.preceding(end);
return getRange(start, end);
}
@@ -195,25 +194,20 @@
if (offset >= mText.length()) {
return null;
}
- int start = -1;
- if (offset < 0) {
- offset = 0;
- if (mImpl.isBoundary(offset) && isLetterOrDigit(offset)) {
- start = offset;
- }
- }
+ int start = offset;
if (start < 0) {
- while ((offset = mImpl.following(offset)) != DONE) {
- if (isLetterOrDigit(offset)) {
- start = offset;
- break;
- }
- }
+ start = 0;
}
- if (start < 0) {
- return null;
+ while (!isLetterOrDigit(start) && !isStartBoundary(start)) {
+ start = mImpl.following(start);
+ if (start == BreakIterator.DONE) {
+ return null;
+ }
}
final int end = mImpl.following(start);
+ if (end == BreakIterator.DONE || !isEndBoundary(end)) {
+ return null;
+ }
return getRange(start, end);
}
@@ -226,28 +220,33 @@
if (offset <= 0) {
return null;
}
- int end = -1;
- if (offset > mText.length()) {
- offset = mText.length();
- if (mImpl.isBoundary(offset) && offset > 0 && isLetterOrDigit(offset - 1)) {
- end = offset;
- }
+ int end = offset;
+ if (end > textLegth) {
+ end = textLegth;
}
- if (end < 0) {
- while ((offset = mImpl.preceding(offset)) != DONE) {
- if (offset > 0 && isLetterOrDigit(offset - 1)) {
- end = offset;
- break;
- }
+ while (end > 0 && !isLetterOrDigit(end - 1) && !isEndBoundary(end)) {
+ end = mImpl.preceding(end);
+ if (end == BreakIterator.DONE) {
+ return null;
}
}
- if (end < 0) {
- return null;
- }
final int start = mImpl.preceding(end);
+ if (start == BreakIterator.DONE || !isStartBoundary(start)) {
+ return null;
+ }
return getRange(start, end);
}
+ private boolean isStartBoundary(int index) {
+ return isLetterOrDigit(index)
+ && (index == 0 || !isLetterOrDigit(index - 1));
+ }
+
+ private boolean isEndBoundary(int index) {
+ return (index > 0 && isLetterOrDigit(index - 1))
+ && (index == mText.length() || !isLetterOrDigit(index));
+ }
+
private boolean isLetterOrDigit(int index) {
if (index >= 0 && index < mText.length()) {
final int codePoint = mText.codePointAt(index);
@@ -276,31 +275,19 @@
if (offset >= textLength) {
return null;
}
- int start = -1;
- if (offset < 0) {
- start = 0;
- } else {
- for (int i = offset + 1; i < textLength; i++) {
- if (mText.charAt(i) == '\n') {
- start = i;
- break;
- }
- }
- }
+ int start = offset;
if (start < 0) {
- return null;
+ start = 0;
}
- while (start < textLength && mText.charAt(start) == '\n') {
+ while (start < textLength && mText.charAt(start) == '\n'
+ && !isStartBoundary(start)) {
start++;
}
- int end = start;
- for (int i = end + 1; i < textLength; i++) {
- end = i;
- if (mText.charAt(i) == '\n') {
- break;
- }
+ if (start >= textLength) {
+ return null;
}
- while (end < textLength && mText.charAt(end) == '\n') {
+ int end = start + 1;
+ while (end < textLength && !isEndBoundary(end)) {
end++;
}
return getRange(start, end);
@@ -315,38 +302,31 @@
if (offset <= 0) {
return null;
}
- int end = -1;
- if (offset > mText.length()) {
- end = mText.length();
- } else {
- if (offset > 0 && mText.charAt(offset - 1) == '\n') {
- offset--;
- }
- for (int i = offset - 1; i >= 0; i--) {
- if (i > 0 && mText.charAt(i - 1) == '\n') {
- end = i;
- break;
- }
- }
+ int end = offset;
+ if (end > textLength) {
+ end = textLength;
+ }
+ while(end > 0 && mText.charAt(end - 1) == '\n' && !isEndBoundary(end)) {
+ end--;
}
if (end <= 0) {
return null;
}
- int start = end;
- while (start > 0 && mText.charAt(start - 1) == '\n') {
+ int start = end - 1;
+ while (start > 0 && !isStartBoundary(start)) {
start--;
}
- if (start == 0 && mText.charAt(start) == '\n') {
- return null;
- }
- for (int i = start - 1; i >= 0; i--) {
- start = i;
- if (start > 0 && mText.charAt(i - 1) == '\n') {
- break;
- }
- }
- start = Math.max(0, start);
return getRange(start, end);
}
+
+ private boolean isStartBoundary(int index) {
+ return (mText.charAt(index) != '\n'
+ && (index == 0 || mText.charAt(index - 1) == '\n'));
+ }
+
+ private boolean isEndBoundary(int index) {
+ return (index > 0 && mText.charAt(index - 1) != '\n'
+ && (index == mText.length() || mText.charAt(index) == '\n'));
+ }
}
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index ace7aa8..1080229 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -52,6 +52,19 @@
* to characters. Be aware that there may be multiple key input devices active
* at the same time and each will have its own key character map.
* </p><p>
+ * As soft input methods can use multiple and inventive ways of inputting text,
+ * there is no guarantee that any key press on a soft keyboard will generate a key
+ * event: this is left to the IME's discretion, and in fact sending such events is
+ * discouraged. You should never rely on receiving KeyEvents for any key on a soft
+ * input method. In particular, the default software keyboard will never send any
+ * key event to any application targetting Jelly Bean or later, and will only send
+ * events for some presses of the delete and return keys to applications targetting
+ * Ice Cream Sandwich or earlier. Be aware that other software input methods may
+ * never send key events regardless of the version. Consider using editor actions
+ * like {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE} if you need
+ * specific interaction with the software keyboard, as it gives more visibility to
+ * the user as to how your application will react to key presses.
+ * </p><p>
* When interacting with an IME, the framework may deliver key events
* with the special action {@link #ACTION_MULTIPLE} that either specifies
* that single repeated key code or a sequence of characters to insert.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8cb5c85..9613149 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -204,12 +204,12 @@
* <tr>
* <td rowspan="4">Event processing</td>
* <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td>
- * <td>Called when a new key event occurs.
+ * <td>Called when a new hardware key event occurs.
* </td>
* </tr>
* <tr>
* <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td>
- * <td>Called when a key up event occurs.
+ * <td>Called when a hardware key up event occurs.
* </td>
* </tr>
* <tr>
@@ -1596,7 +1596,7 @@
/**
* @hide
*/
- private int mAccessibilityCursorPosition = -1;
+ private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED;
/**
* The view's tag.
@@ -2086,7 +2086,8 @@
// Accessiblity constants for mPrivateFlags2
/**
- * Shift for accessibility related bits in {@link #mPrivateFlags2}.
+ * Shift for the bits in {@link #mPrivateFlags2} related to the
+ * "importantForAccessibility" attribute.
*/
static final int IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20;
@@ -2142,6 +2143,72 @@
*/
static final int VIEW_QUICK_REJECTED = 0x20000000;
+ // Accessiblity constants for mPrivateFlags2
+
+ /**
+ * Shift for the bits in {@link #mPrivateFlags2} related to the
+ * "accessibilityFocusable" attribute.
+ */
+ static final int ACCESSIBILITY_FOCUSABLE_SHIFT = 30;
+
+ /**
+ * The system determines whether the view can take accessibility focus - default (recommended).
+ * <p>
+ * Such a view is consideted by the focus search if it is:
+ * <ul>
+ * <li>
+ * Important for accessibility and actionable (clickable, long clickable, focusable)
+ * </li>
+ * <li>
+ * Important for accessibility, not actionable (clickable, long clickable, focusable),
+ * and does not have an actionable predecessor.
+ * </li>
+ * </ul>
+ * An accessibility srvice can request putting accessibility focus on such a view.
+ * </p>
+ *
+ * @hide
+ */
+ public static final int ACCESSIBILITY_FOCUSABLE_AUTO = 0x00000000;
+
+ /**
+ * The view can take accessibility focus.
+ * <p>
+ * A view that can take accessibility focus is always considered during focus
+ * search and an accessibility service can request putting accessibility focus
+ * on it.
+ * </p>
+ *
+ * @hide
+ */
+ public static final int ACCESSIBILITY_FOCUSABLE_YES = 0x00000001;
+
+ /**
+ * The view can not take accessibility focus.
+ * <p>
+ * A view that can not take accessibility focus is never considered during focus
+ * search and an accessibility service can not request putting accessibility focus
+ * on it.
+ * </p>
+ *
+ * @hide
+ */
+ public static final int ACCESSIBILITY_FOCUSABLE_NO = 0x00000002;
+
+ /**
+ * The default whether the view is accessiblity focusable.
+ */
+ static final int ACCESSIBILITY_FOCUSABLE_DEFAULT = ACCESSIBILITY_FOCUSABLE_AUTO;
+
+ /**
+ * Mask for obtainig the bits which specifies how to determine
+ * whether a view is accessibility focusable.
+ */
+ static final int ACCESSIBILITY_FOCUSABLE_MASK = (ACCESSIBILITY_FOCUSABLE_AUTO
+ | ACCESSIBILITY_FOCUSABLE_YES | ACCESSIBILITY_FOCUSABLE_NO)
+ << ACCESSIBILITY_FOCUSABLE_SHIFT;
+
+
/* End of masks for mPrivateFlags2 */
static final int DRAG_MASK = DRAG_CAN_ACCEPT | DRAG_HOVERED;
@@ -2468,6 +2535,11 @@
public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004;
/**
+ * The undefined cursor position.
+ */
+ private static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1;
+
+ /**
* Indicates that the screen has changed state and is now off.
*
* @see #onScreenStateChanged(int)
@@ -3132,7 +3204,8 @@
mPrivateFlags2 = (LAYOUT_DIRECTION_DEFAULT << LAYOUT_DIRECTION_MASK_SHIFT) |
(TEXT_DIRECTION_DEFAULT << TEXT_DIRECTION_MASK_SHIFT) |
(TEXT_ALIGNMENT_DEFAULT << TEXT_ALIGNMENT_MASK_SHIFT) |
- (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << IMPORTANT_FOR_ACCESSIBILITY_SHIFT);
+ (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << IMPORTANT_FOR_ACCESSIBILITY_SHIFT) |
+ (ACCESSIBILITY_FOCUSABLE_DEFAULT << ACCESSIBILITY_FOCUSABLE_SHIFT);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
mUserPaddingStart = -1;
@@ -4082,7 +4155,9 @@
}
/**
- * Register a callback to be invoked when a key is pressed in this view.
+ * Register a callback to be invoked when a hardware key is pressed in this view.
+ * Key presses in software input methods will generally not trigger the methods of
+ * this listener.
* @param l the key listener to attach to this view
*/
public void setOnKeyListener(OnKeyListener l) {
@@ -4788,7 +4863,10 @@
}
if (!isAccessibilityFocused()) {
- info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
+ final int mode = getAccessibilityFocusable();
+ if (mode == ACCESSIBILITY_FOCUSABLE_YES || mode == ACCESSIBILITY_FOCUSABLE_AUTO) {
+ info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
+ }
} else {
info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
}
@@ -6069,7 +6147,7 @@
return;
}
if ((focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) {
- if (canTakeAccessibilityFocusFromHover() || getAccessibilityNodeProvider() != null) {
+ if (isAccessibilityFocusable()) {
views.add(this);
return;
}
@@ -6202,7 +6280,7 @@
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
notifyAccessibilityStateChanged();
// Clear the text navigation state.
- setAccessibilityCursorPosition(-1);
+ setAccessibilityCursorPosition(ACCESSIBILITY_CURSOR_POSITION_UNDEFINED);
}
// Clear the global reference of accessibility focus if this
// view or any of its descendants had accessibility focus.
@@ -6252,6 +6330,7 @@
void clearAccessibilityFocusNoCallbacks() {
if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) {
mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED;
+ setAccessibilityCursorPosition(ACCESSIBILITY_CURSOR_POSITION_UNDEFINED);
invalidate();
}
}
@@ -6403,12 +6482,9 @@
* @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
*/
@ViewDebug.ExportedProperty(category = "accessibility", mapping = {
- @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO,
- to = "IMPORTANT_FOR_ACCESSIBILITY_AUTO"),
- @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES,
- to = "IMPORTANT_FOR_ACCESSIBILITY_YES"),
- @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO,
- to = "IMPORTANT_FOR_ACCESSIBILITY_NO")
+ @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"),
+ @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"),
+ @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no")
})
public int getImportantForAccessibility() {
return (mPrivateFlags2 & IMPORTANT_FOR_ACCESSIBILITY_MASK)
@@ -6461,6 +6537,73 @@
}
/**
+ * Gets the mode for determining whether this View can take accessibility focus.
+ *
+ * @return The mode for determining whether a View can take accessibility focus.
+ *
+ * @attr ref android.R.styleable#View_accessibilityFocusable
+ *
+ * @see #ACCESSIBILITY_FOCUSABLE_YES
+ * @see #ACCESSIBILITY_FOCUSABLE_NO
+ * @see #ACCESSIBILITY_FOCUSABLE_AUTO
+ *
+ * @hide
+ */
+ @ViewDebug.ExportedProperty(category = "accessibility", mapping = {
+ @ViewDebug.IntToString(from = ACCESSIBILITY_FOCUSABLE_AUTO, to = "auto"),
+ @ViewDebug.IntToString(from = ACCESSIBILITY_FOCUSABLE_YES, to = "yes"),
+ @ViewDebug.IntToString(from = ACCESSIBILITY_FOCUSABLE_NO, to = "no")
+ })
+ public int getAccessibilityFocusable() {
+ return (mPrivateFlags2 & ACCESSIBILITY_FOCUSABLE_MASK) >>> ACCESSIBILITY_FOCUSABLE_SHIFT;
+ }
+
+ /**
+ * Sets how to determine whether this view can take accessibility focus.
+ *
+ * @param mode How to determine whether this view can take accessibility focus.
+ *
+ * @attr ref android.R.styleable#View_accessibilityFocusable
+ *
+ * @see #ACCESSIBILITY_FOCUSABLE_YES
+ * @see #ACCESSIBILITY_FOCUSABLE_NO
+ * @see #ACCESSIBILITY_FOCUSABLE_AUTO
+ *
+ * @hide
+ */
+ public void setAccessibilityFocusable(int mode) {
+ if (mode != getAccessibilityFocusable()) {
+ mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSABLE_MASK;
+ mPrivateFlags2 |= (mode << ACCESSIBILITY_FOCUSABLE_SHIFT)
+ & ACCESSIBILITY_FOCUSABLE_MASK;
+ notifyAccessibilityStateChanged();
+ }
+ }
+
+ /**
+ * Gets whether this view can take accessibility focus.
+ *
+ * @return Whether the view can take accessibility focus.
+ *
+ * @hide
+ */
+ public boolean isAccessibilityFocusable() {
+ final int mode = (mPrivateFlags2 & ACCESSIBILITY_FOCUSABLE_MASK)
+ >>> ACCESSIBILITY_FOCUSABLE_SHIFT;
+ switch (mode) {
+ case ACCESSIBILITY_FOCUSABLE_YES:
+ return true;
+ case ACCESSIBILITY_FOCUSABLE_NO:
+ return false;
+ case ACCESSIBILITY_FOCUSABLE_AUTO:
+ return canTakeAccessibilityFocusFromHover()
+ || getAccessibilityNodeProvider() != null;
+ default:
+ throw new IllegalArgumentException("Unknow accessibility focusable mode: " + mode);
+ }
+ }
+
+ /**
* Gets the parent for accessibility purposes. Note that the parent for
* accessibility is not necessary the immediate parent. It is the first
* predecessor that is important for accessibility.
@@ -6641,7 +6784,10 @@
}
} break;
case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: {
- if (!isAccessibilityFocused()) {
+ final int mode = getAccessibilityFocusable();
+ if (!isAccessibilityFocused()
+ && (mode == ACCESSIBILITY_FOCUSABLE_YES
+ || mode == ACCESSIBILITY_FOCUSABLE_AUTO)) {
return requestAccessibilityFocus();
}
} break;
@@ -6681,12 +6827,11 @@
final int current = getAccessibilityCursorPosition();
final int[] range = iterator.following(current);
if (range == null) {
- setAccessibilityCursorPosition(-1);
return false;
}
final int start = range[0];
final int end = range[1];
- setAccessibilityCursorPosition(start);
+ setAccessibilityCursorPosition(end);
sendViewTextTraversedAtGranularityEvent(
AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
granularity, start, end);
@@ -6702,16 +6847,26 @@
if (iterator == null) {
return false;
}
- final int selectionStart = getAccessibilityCursorPosition();
- final int current = selectionStart >= 0 ? selectionStart : text.length() + 1;
+ int current = getAccessibilityCursorPosition();
+ if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) {
+ current = text.length();
+ } else if (granularity == AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER) {
+ // When traversing by character we always put the cursor after the character
+ // to ease edit and have to compensate before asking the for previous segment.
+ current--;
+ }
final int[] range = iterator.preceding(current);
if (range == null) {
- setAccessibilityCursorPosition(-1);
return false;
}
final int start = range[0];
final int end = range[1];
- setAccessibilityCursorPosition(end);
+ // Always put the cursor after the character to ease edit.
+ if (granularity == AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER) {
+ setAccessibilityCursorPosition(end);
+ } else {
+ setAccessibilityCursorPosition(start);
+ }
sendViewTextTraversedAtGranularityEvent(
AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
granularity, start, end);
@@ -7389,6 +7544,10 @@
* when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER}
* is released, if the view is enabled and clickable.
*
+ * <p>Key presses in software keyboards will generally NOT trigger this listener,
+ * although some may elect to do so in some situations. Do not rely on this to
+ * catch software key presses.
+ *
* @param keyCode A key code that represents the button pressed, from
* {@link android.view.KeyEvent}.
* @param event The KeyEvent object that defines the button action.
@@ -7420,6 +7579,9 @@
* Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
* KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
* the event).
+ * <p>Key presses in software keyboards will generally NOT trigger this listener,
+ * although some may elect to do so in some situations. Do not rely on this to
+ * catch software key presses.
*/
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
return false;
@@ -7430,6 +7592,9 @@
* KeyEvent.Callback.onKeyUp()}: perform clicking of the view
* when {@link KeyEvent#KEYCODE_DPAD_CENTER} or
* {@link KeyEvent#KEYCODE_ENTER} is released.
+ * <p>Key presses in software keyboards will generally NOT trigger this listener,
+ * although some may elect to do so in some situations. Do not rely on this to
+ * catch software key presses.
*
* @param keyCode A key code that represents the button pressed, from
* {@link android.view.KeyEvent}.
@@ -7464,6 +7629,9 @@
* Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
* KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle
* the event).
+ * <p>Key presses in software keyboards will generally NOT trigger this listener,
+ * although some may elect to do so in some situations. Do not rely on this to
+ * catch software key presses.
*
* @param keyCode A key code that represents the button pressed, from
* {@link android.view.KeyEvent}.
@@ -8023,6 +8191,7 @@
private void removeSendViewScrolledAccessibilityEventCallback() {
if (mSendViewScrolledAccessibilityEvent != null) {
removeCallbacks(mSendViewScrolledAccessibilityEvent);
+ mSendViewScrolledAccessibilityEvent.mIsPending = false;
}
}
@@ -16760,14 +16929,20 @@
}
/**
- * Interface definition for a callback to be invoked when a key event is
- * dispatched to this view. The callback will be invoked before the key
- * event is given to the view.
+ * Interface definition for a callback to be invoked when a hardware key event is
+ * dispatched to this view. The callback will be invoked before the key event is
+ * given to the view. This is only useful for hardware keyboards; a software input
+ * method has no obligation to trigger this listener.
*/
public interface OnKeyListener {
/**
- * Called when a key is dispatched to a view. This allows listeners to
+ * Called when a hardware key is dispatched to a view. This allows listeners to
* get a chance to respond before the target view.
+ * <p>Key presses in software keyboards will generally NOT trigger this method,
+ * although some may elect to do so in some situations. Do not assume a
+ * software input method has to be key-based; even if it is, it may use key presses
+ * in a different way than you expect, so there is no way to reliably catch soft
+ * input key presses.
*
* @param v The view the key has been dispatched to.
* @param keyCode The code for the physical key that was pressed
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 3563d4d..76c6d19 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -283,7 +283,7 @@
/**
* Tell the editor that you are done with a batch edit previously
- * initiated with {@link #endBatchEdit}.
+ * initiated with {@link #beginBatchEdit}.
*/
public boolean endBatchEdit();
@@ -307,7 +307,11 @@
* {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD} on all
* key event objects you give to this API; the flag will not be set
* for you.
- *
+ *
+ * <p>Note that it's discouraged to send such key events in normal operation;
+ * this is mainly for use with {@link android.text.InputType#TYPE_NULL} type
+ * text fields. Use the {@link #commitText} family of methods to send text
+ * to the application instead.
* @param event The key event.
*
* @return Returns true on success, false if the input connection is no longer
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index fc59e6e..161e8fb 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -217,7 +217,7 @@
public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
boolean allowImplicitlySelectedSubtype) {
try {
- // Passing null as a locale for ICS
+ // Passing null as a locale until we support multiple enabled spell checker subtypes.
return sService.getCurrentSpellCheckerSubtype(null, allowImplicitlySelectedSubtype);
} catch (RemoteException e) {
Log.e(TAG, "Error in getCurrentSpellCheckerSubtype: " + e);
diff --git a/core/java/android/webkit/AutoCompletePopup.java b/core/java/android/webkit/AutoCompletePopup.java
index 87e878b..c624ce4 100644
--- a/core/java/android/webkit/AutoCompletePopup.java
+++ b/core/java/android/webkit/AutoCompletePopup.java
@@ -181,8 +181,11 @@
// There is no autofill profile setup yet and the user has
// elected to try and set one up. Call through to the
// embedder to action that.
- mWebView.getWebChromeClient().setupAutoFill(
+ WebChromeClient webChromeClient = mWebView.getWebChromeClient();
+ if (webChromeClient != null) {
+ webChromeClient.setupAutoFill(
mHandler.obtainMessage(AUTOFILL_FORM));
+ }
}
} else {
Object selectedItem;
diff --git a/core/java/android/webkit/WebViewInputDispatcher.java b/core/java/android/webkit/WebViewInputDispatcher.java
index d8065e9..f64547f 100644
--- a/core/java/android/webkit/WebViewInputDispatcher.java
+++ b/core/java/android/webkit/WebViewInputDispatcher.java
@@ -661,6 +661,7 @@
// Web kit has decided to consume the event!
if (d.mEventType == EVENT_TYPE_TOUCH) {
enqueueUiCancelTouchEventIfNeededLocked();
+ unscheduleLongPressLocked();
}
} else {
// Web kit is being friendly. Pass the event to the UI.
diff --git a/core/java/android/widget/AccessibilityIterators.java b/core/java/android/widget/AccessibilityIterators.java
index e800e8d..a3d58a4 100644
--- a/core/java/android/widget/AccessibilityIterators.java
+++ b/core/java/android/widget/AccessibilityIterators.java
@@ -56,16 +56,18 @@
if (offset >= mText.length()) {
return null;
}
- int nextLine = -1;
+ int nextLine;
if (offset < 0) {
nextLine = mLayout.getLineForOffset(0);
} else {
final int currentLine = mLayout.getLineForOffset(offset);
- if (currentLine < mLayout.getLineCount() - 1) {
+ if (getLineEdgeIndex(currentLine, DIRECTION_START) == offset) {
+ nextLine = currentLine;
+ } else {
nextLine = currentLine + 1;
}
}
- if (nextLine < 0) {
+ if (nextLine >= mLayout.getLineCount()) {
return null;
}
final int start = getLineEdgeIndex(nextLine, DIRECTION_START);
@@ -82,12 +84,14 @@
if (offset <= 0) {
return null;
}
- int previousLine = -1;
+ int previousLine;
if (offset > mText.length()) {
previousLine = mLayout.getLineForOffset(mText.length());
} else {
- final int currentLine = mLayout.getLineForOffset(offset - 1);
- if (currentLine > 0) {
+ final int currentLine = mLayout.getLineForOffset(offset);
+ if (getLineEdgeIndex(currentLine, DIRECTION_END) + 1 == offset) {
+ previousLine = currentLine;
+ } else {
previousLine = currentLine - 1;
}
}
@@ -141,29 +145,18 @@
return null;
}
- final int currentLine = mLayout.getLineForOffset(offset);
+ final int start = Math.max(0, offset);
+
+ final int currentLine = mLayout.getLineForOffset(start);
final int currentLineTop = mLayout.getLineTop(currentLine);
final int pageHeight = mTempRect.height() - mView.getTotalPaddingTop()
- mView.getTotalPaddingBottom();
+ final int nextPageStartY = currentLineTop + pageHeight;
+ final int lastLineTop = mLayout.getLineTop(mLayout.getLineCount() - 1);
+ final int currentPageEndLine = (nextPageStartY < lastLineTop)
+ ? mLayout.getLineForVertical(nextPageStartY) - 1 : mLayout.getLineCount() - 1;
- final int nextPageStartLine;
- final int nextPageEndLine;
- if (offset < 0) {
- nextPageStartLine = currentLine;
- final int nextPageEndY = currentLineTop + pageHeight;
- nextPageEndLine = mLayout.getLineForVertical(nextPageEndY);
- } else {
- final int nextPageStartY = currentLineTop + pageHeight;
- nextPageStartLine = mLayout.getLineForVertical(nextPageStartY) + 1;
- if (mLayout.getLineTop(nextPageStartLine) <= nextPageStartY) {
- return null;
- }
- final int nextPageEndY = nextPageStartY + pageHeight;
- nextPageEndLine = mLayout.getLineForVertical(nextPageEndY);
- }
-
- final int start = getLineEdgeIndex(nextPageStartLine, DIRECTION_START);
- final int end = getLineEdgeIndex(nextPageEndLine, DIRECTION_END) + 1;
+ final int end = getLineEdgeIndex(currentPageEndLine, DIRECTION_END) + 1;
return getRange(start, end);
}
@@ -181,37 +174,17 @@
return null;
}
- final int currentLine = mLayout.getLineForOffset(offset);
+ final int end = Math.min(mText.length(), offset);
+
+ final int currentLine = mLayout.getLineForOffset(end);
final int currentLineTop = mLayout.getLineTop(currentLine);
final int pageHeight = mTempRect.height() - mView.getTotalPaddingTop()
- mView.getTotalPaddingBottom();
+ final int previousPageEndY = currentLineTop - pageHeight;
+ final int currentPageStartLine = (previousPageEndY > 0) ?
+ mLayout.getLineForVertical(previousPageEndY) + 1 : 0;
- final int previousPageStartLine;
- final int previousPageEndLine;
- if (offset > mText.length()) {
- final int prevousPageStartY = mLayout.getHeight() - pageHeight;
- if (prevousPageStartY < 0) {
- return null;
- }
- previousPageStartLine = mLayout.getLineForVertical(prevousPageStartY);
- previousPageEndLine = mLayout.getLineCount() - 1;
- } else {
- final int prevousPageStartY;
- if (offset == mText.length()) {
- prevousPageStartY = mLayout.getHeight() - 2 * pageHeight;
- } else {
- prevousPageStartY = currentLineTop - 2 * pageHeight;
- }
- if (prevousPageStartY < 0) {
- return null;
- }
- previousPageStartLine = mLayout.getLineForVertical(prevousPageStartY);
- final int previousPageEndY = prevousPageStartY + pageHeight;
- previousPageEndLine = mLayout.getLineForVertical(previousPageEndY) - 1;
- }
-
- final int start = getLineEdgeIndex(previousPageStartLine, DIRECTION_START);
- final int end = getLineEdgeIndex(previousPageEndLine, DIRECTION_END) + 1;
+ final int start = getLineEdgeIndex(currentPageStartLine, DIRECTION_START);
return getRange(start, end);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index bd19f00..3e2d43a 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8376,10 +8376,12 @@
@Override
public int getAccessibilityCursorPosition() {
if (TextUtils.isEmpty(getContentDescription())) {
- return getSelectionEnd();
- } else {
- return super.getAccessibilityCursorPosition();
+ final int selectionEnd = getSelectionEnd();
+ if (selectionEnd >= 0) {
+ return selectionEnd;
+ }
}
+ return super.getAccessibilityCursorPosition();
}
/**
@@ -8391,7 +8393,7 @@
return;
}
if (TextUtils.isEmpty(getContentDescription())) {
- if (index >= 0) {
+ if (index >= 0 && index <= mText.length()) {
Selection.setSelection((Spannable) mText, index);
} else {
Selection.removeSelection((Spannable) mText);
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index f9ef3c5..b2c3091 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -419,6 +419,7 @@
"y", 0,
"onUpdate", mUpdateListener,
"onComplete", finishListener));
+ mHandleAnimations.start();
}
/**
@@ -519,12 +520,15 @@
// Inform listener of any active targets. Typically only one will be active.
deactivateHandle(RETURN_TO_HOME_DURATION, RETURN_TO_HOME_DELAY, 0.0f, mResetListener);
dispatchTriggerEvent(activeTarget);
+ if (!mAlwaysTrackFinger) {
+ // Force ring and targets to finish animation to final expanded state
+ mTargetAnimations.stop();
+ }
} else {
// Animate handle back to the center based on current state.
deactivateHandle(HIDE_ANIMATION_DURATION, HIDE_ANIMATION_DELAY, 1.0f,
mResetListenerWithPing);
hideTargets(true, false);
- mHandleAnimations.start();
}
setGrabbedState(OnTriggerListener.NO_HANDLE);
@@ -542,7 +546,6 @@
mTargetDrawables.get(i).setAlpha(0.0f);
}
}
- mOuterRing.setAlpha(0.0f);
}
private void hideTargets(boolean animate, boolean expanded) {
@@ -809,7 +812,6 @@
switchToState(STATE_START, eventX, eventY);
if (!trySwitchToFirstTouchState(eventX, eventY)) {
mDragging = false;
- mTargetAnimations.cancel();
ping();
}
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e3082ea..155e59c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1983,7 +1983,7 @@
<activity android:name="android.accounts.ChooseTypeAndAccountActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@android:style/Theme.Holo.DialogWhenLarge.NoActionBar"
+ android:theme="@android:style/Theme.Holo.Dialog"
android:label="@string/choose_account_label"
android:process=":ui">
</activity>
diff --git a/core/res/res/layout/choose_selected_account_row.xml b/core/res/res/layout/choose_selected_account_row.xml
deleted file mode 100644
index d88750d..0000000
--- a/core/res/res/layout/choose_selected_account_row.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:paddingLeft="0dip"
- android:paddingRight="0dip"
- android:orientation="horizontal" >
-
- <ImageView android:id="@+id/account_row_icon"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:paddingRight="8dip" />
-
- <TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/account_row_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:gravity="center_vertical"
- android:minHeight="?android:attr/listPreferredItemHeight" />
-
- <ImageView android:id="@+id/account_row_checkmark"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="right"
- android:layout_weight="2"
- android:paddingRight="8dip"
- android:src="@drawable/ic_checkmark_holo_light" />
-
-</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/choose_type_and_account.xml b/core/res/res/layout/choose_type_and_account.xml
index d7068b7bf..9d1d284 100644
--- a/core/res/res/layout/choose_type_and_account.xml
+++ b/core/res/res/layout/choose_type_and_account.xml
@@ -20,53 +20,52 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
- android:paddingLeft="16dip"
- android:paddingRight="16dip">
+ android:orientation="vertical">
- <TextView android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_gravity="left"
- android:text="@string/choose_account_label"
- android:paddingTop="16dip"
- android:paddingBottom="16dip"
- android:textColor="@android:color/holo_blue_light"
- />
-
- <View android:layout_height="3dip"
- android:layout_width="match_parent"
- android:background="#323232"/>
-
+ <!-- Customizable description text -->
<TextView android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_gravity="left|center_vertical"
- android:text="@string/choose_account_text"
android:paddingTop="16dip"
android:paddingBottom="16dip"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
/>
+ <!-- List of accounts, with "Add new account" as the last item -->
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawSelectorOnTop="false"
android:layout_weight="1"
- android:scrollbarAlwaysDrawVerticalTrack="true" />
+ android:scrollbarAlwaysDrawVerticalTrack="true"
+ android:choiceMode="singleChoice" />
+ <!-- Horizontal divider line -->
<View android:layout_height="1dip"
android:layout_width="match_parent"
android:background="?android:attr/dividerHorizontal" />
- <Button android:id="@+id/addAccount"
- style="?android:attr/buttonBarButtonStyle"
+ <!-- Alert dialog style buttons along the bottom. -->
+ <LinearLayout android:id="@+id/button_bar"
+ style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="2dip"
- android:layout_marginRight="2dip"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@string/add_account_button_label"
- />
+ android:measureWithLargestChild="true">
+ <Button android:id="@android:id/button1"
+ style="?android:attr/buttonBarButtonStyle"
+ android:layout_width="wrap_content" android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@android:string/no"
+ android:onClick="onCancelButtonClicked" />
+ <Button android:id="@android:id/button2"
+ style="?android:attr/buttonBarButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@android:string/yes"
+ android:onClick="onOkButtonClicked" />
+ </LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/notification_action_list.xml b/core/res/res/layout/notification_action_list.xml
index fa0a8c8..591c9ea 100644
--- a/core/res/res/layout/notification_action_list.xml
+++ b/core/res/res/layout/notification_action_list.xml
@@ -23,6 +23,7 @@
android:visibility="gone"
android:showDividers="middle"
android:divider="?android:attr/listDivider"
+ android:dividerPadding="12dp"
>
<!-- actions will be added here -->
</LinearLayout>
diff --git a/core/res/res/layout/notification_template_base.xml b/core/res/res/layout/notification_template_base.xml
index ed680a9..47bbbde 100644
--- a/core/res/res/layout/notification_template_base.xml
+++ b/core/res/res/layout/notification_template_base.xml
@@ -36,8 +36,7 @@
android:layout_marginLeft="@dimen/notification_large_icon_width"
android:minHeight="@dimen/notification_large_icon_height"
android:orientation="vertical"
- android:paddingLeft="12dp"
- android:paddingRight="12dp"
+ android:paddingRight="8dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:gravity="top"
@@ -47,6 +46,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="6dp"
+ android:layout_marginLeft="8dp"
android:orientation="horizontal"
>
<TextView android:id="@+id/title"
@@ -81,6 +81,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="-2dp"
android:layout_marginBottom="-2dp"
+ android:layout_marginLeft="8dp"
android:singleLine="true"
android:fadingEdge="horizontal"
android:ellipsize="marquee"
@@ -90,24 +91,17 @@
android:id="@android:id/progress"
android:layout_width="match_parent"
android:layout_height="12dp"
+ android:layout_marginLeft="8dp"
android:visibility="gone"
style="?android:attr/progressBarStyleHorizontal"
/>
- <TextView android:id="@+id/overflow_title"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:visibility="gone"
- android:layout_weight="1"
- />
<LinearLayout
android:id="@+id/line3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:layout_marginLeft="8dp"
>
<TextView android:id="@+id/text"
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
@@ -130,14 +124,14 @@
android:paddingLeft="8dp"
/>
<ImageView android:id="@+id/right_icon"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_width="16dp"
+ android:layout_height="16dp"
android:layout_gravity="center"
android:layout_weight="0"
+ android:layout_marginLeft="8dp"
android:scaleType="centerInside"
- android:paddingLeft="8dp"
android:visibility="gone"
- android:drawableAlpha="180"
+ android:drawableAlpha="153"
/>
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/notification_template_big_base.xml b/core/res/res/layout/notification_template_big_base.xml
index f2c204f..69f0a24 100644
--- a/core/res/res/layout/notification_template_big_base.xml
+++ b/core/res/res/layout/notification_template_big_base.xml
@@ -33,19 +33,16 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill_vertical"
- android:layout_marginLeft="@dimen/notification_large_icon_width"
android:minHeight="@dimen/notification_large_icon_height"
android:orientation="vertical"
- android:paddingLeft="12dp"
- android:paddingRight="12dp"
- android:paddingTop="2dp"
- android:paddingBottom="2dp"
android:gravity="top"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/notification_large_icon_width"
android:minHeight="@dimen/notification_large_icon_height"
+ android:paddingTop="2dp"
android:orientation="vertical"
>
<LinearLayout
@@ -53,6 +50,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="6dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginLeft="8dp"
android:orientation="horizontal"
>
<TextView android:id="@+id/title"
@@ -87,6 +86,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="-2dp"
android:layout_marginBottom="-2dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:singleLine="true"
android:fadingEdge="horizontal"
android:ellipsize="marquee"
@@ -96,6 +97,8 @@
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:singleLine="false"
android:visibility="gone"
/>
@@ -103,7 +106,10 @@
android:id="@+id/line3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:orientation="horizontal"
+ android:gravity="center_vertical"
>
<TextView android:id="@+id/text"
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
@@ -126,29 +132,38 @@
android:paddingLeft="8dp"
/>
<ImageView android:id="@+id/right_icon"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_width="16dp"
+ android:layout_height="16dp"
android:layout_gravity="center"
android:layout_weight="0"
+ android:layout_marginLeft="8dp"
android:scaleType="centerInside"
- android:paddingLeft="8dp"
android:visibility="gone"
- android:drawableAlpha="180"
+ android:drawableAlpha="153"
/>
</LinearLayout>
<ProgressBar
android:id="@android:id/progress"
android:layout_width="match_parent"
android:layout_height="12dp"
+ android:layout_marginBottom="8dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:visibility="gone"
style="?android:attr/progressBarStyleHorizontal"
/>
</LinearLayout>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:id="@+id/action_divider"
+ android:visibility="gone"
+ android:background="?android:attr/dividerHorizontal" />
<include
layout="@layout/notification_action_list"
- android:id="@+id/actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/notification_large_icon_width"
/>
</LinearLayout>
</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_picture.xml b/core/res/res/layout/notification_template_big_picture.xml
index 077616e..ecb3616 100644
--- a/core/res/res/layout/notification_template_big_picture.xml
+++ b/core/res/res/layout/notification_template_big_picture.xml
@@ -53,7 +53,6 @@
<include
layout="@layout/notification_action_list"
android:id="@+id/actions"
- android:layout_marginLeft="8dp"
android:layout_gravity="bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/core/res/res/layout/notification_template_big_text.xml b/core/res/res/layout/notification_template_big_text.xml
index 304f2b5..b86177e 100644
--- a/core/res/res/layout/notification_template_big_text.xml
+++ b/core/res/res/layout/notification_template_big_text.xml
@@ -34,8 +34,6 @@
android:layout_gravity="fill_vertical"
android:layout_marginLeft="@dimen/notification_large_icon_width"
android:orientation="vertical"
- android:paddingLeft="12dp"
- android:paddingRight="12dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:gravity="top"
@@ -44,6 +42,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:layout_weight="1"
>
<LinearLayout
@@ -87,6 +87,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="-2dp"
android:layout_marginBottom="-2dp"
+ android:layout_marginRight="8dp"
android:singleLine="true"
android:fadingEdge="horizontal"
android:ellipsize="marquee"
@@ -97,6 +98,8 @@
android:id="@android:id/progress"
android:layout_width="match_parent"
android:layout_height="12dp"
+ android:layout_marginBottom="8dp"
+ android:layout_marginRight="8dp"
android:visibility="gone"
android:layout_weight="0"
style="?android:attr/progressBarStyleHorizontal"
@@ -105,7 +108,8 @@
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:layout_marginBottom="2dp"
+ android:layout_marginBottom="8dp"
+ android:layout_marginRight="8dp"
android:singleLine="false"
android:visibility="gone"
android:maxLines="8"
@@ -113,6 +117,13 @@
android:layout_weight="1"
/>
</LinearLayout>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:layout_marginTop="-1px"
+ android:id="@+id/action_divider"
+ android:visibility="gone"
+ android:background="?android:attr/dividerHorizontal" />
<include
layout="@layout/notification_action_list"
android:layout_width="match_parent"
@@ -120,22 +131,23 @@
android:visibility="gone"
android:layout_weight="1"
/>
- <TextView android:id="@+id/overflow_title"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+ <ImageView
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:visibility="gone"
- android:layout_weight="0"
- />
+ android:layout_height="1px"
+ android:id="@+id/overflow_divider"
+ android:layout_marginBottom="8dp"
+ android:visibility="visible"
+ android:background="?android:attr/dividerHorizontal" />
<LinearLayout
android:id="@+id/line3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginBottom="8dp"
+ android:layout_marginRight="8dp"
android:orientation="horizontal"
android:layout_weight="0"
+ android:gravity="center_vertical"
>
<TextView android:id="@+id/text"
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
@@ -158,14 +170,14 @@
android:paddingLeft="8dp"
/>
<ImageView android:id="@+id/right_icon"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_width="16dp"
+ android:layout_height="16dp"
android:layout_gravity="center"
android:layout_weight="0"
+ android:layout_marginLeft="8dp"
android:scaleType="centerInside"
- android:paddingLeft="8dp"
android:visibility="gone"
- android:drawableAlpha="180"
+ android:drawableAlpha="153"
/>
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/notification_template_inbox.xml b/core/res/res/layout/notification_template_inbox.xml
index 121a81c..e9a3686 100644
--- a/core/res/res/layout/notification_template_inbox.xml
+++ b/core/res/res/layout/notification_template_inbox.xml
@@ -36,8 +36,6 @@
android:layout_marginLeft="@dimen/notification_large_icon_width"
android:minHeight="@dimen/notification_large_icon_height"
android:orientation="vertical"
- android:paddingLeft="12dp"
- android:paddingRight="12dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:gravity="top"
@@ -46,6 +44,8 @@
android:id="@+id/line1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:paddingTop="6dp"
android:orientation="horizontal"
android:layout_weight="0"
@@ -82,6 +82,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="-2dp"
android:layout_marginBottom="-2dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:singleLine="true"
android:fadingEdge="horizontal"
android:ellipsize="marquee"
@@ -92,6 +94,8 @@
android:id="@android:id/progress"
android:layout_width="match_parent"
android:layout_height="12dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:visibility="gone"
android:layout_weight="0"
style="?android:attr/progressBarStyleHorizontal"
@@ -100,6 +104,8 @@
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:singleLine="true"
android:ellipsize="end"
android:visibility="gone"
@@ -109,6 +115,8 @@
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:singleLine="true"
android:ellipsize="end"
android:visibility="gone"
@@ -118,6 +126,8 @@
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:singleLine="true"
android:ellipsize="end"
android:visibility="gone"
@@ -127,6 +137,8 @@
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:singleLine="true"
android:ellipsize="end"
android:visibility="gone"
@@ -136,6 +148,7 @@
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:layout_marginLeft="8dp"
android:singleLine="true"
android:ellipsize="end"
android:visibility="gone"
@@ -145,6 +158,8 @@
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:singleLine="true"
android:ellipsize="end"
android:visibility="gone"
@@ -154,6 +169,8 @@
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:singleLine="true"
android:ellipsize="end"
android:visibility="gone"
@@ -163,35 +180,44 @@
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
android:singleLine="true"
android:ellipsize="end"
android:visibility="gone"
android:layout_weight="1"
android:text="@android:string/ellipsis"
/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:id="@+id/overflow_divider"
+ android:layout_marginTop="8dp"
+ android:visibility="visible"
+ android:background="?android:attr/dividerHorizontal" />
<include
layout="@layout/notification_action_list"
- android:id="@+id/actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
/>
- <TextView android:id="@+id/overflow_title"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+ <ImageView
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
+ android:layout_height="1px"
+ android:id="@+id/action_divider"
android:visibility="gone"
- android:layout_weight="0"
- />
+ android:background="?android:attr/dividerHorizontal" /><!-- note: divider below actions -->
<LinearLayout
android:id="@+id/line3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginBottom="8dp"
+ android:layout_marginRight="8dp"
android:orientation="horizontal"
android:layout_weight="0"
+ android:gravity="center_vertical"
>
<TextView android:id="@+id/text"
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
@@ -214,14 +240,14 @@
android:paddingLeft="8dp"
/>
<ImageView android:id="@+id/right_icon"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_width="16dp"
+ android:layout_height="16dp"
android:layout_gravity="center"
android:layout_weight="0"
+ android:layout_marginLeft="8dp"
android:scaleType="centerInside"
- android:paddingLeft="8dp"
android:visibility="gone"
- android:drawableAlpha="180"
+ android:drawableAlpha="153"
/>
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index c8bb77e..fb11af3 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"ጥያቄ አጥራ"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"ጥያቄ አስረክብ"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"የድምፅ ፍለጋ"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"በመንካት አስስ ይንቃ?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከጡባዊ ተኮው ጋር ለመግባባት ምን በጣትህ ስር ወይም ምልክቶችን ማከናወን እንዳለብህ ማብራሪያ ልታይ ወይም ልትሰማ ትችላለህ።"</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከስልኩ ጋር ለመግባባት ምን በጣትህ ስር ወይም ምልክቶችን ማከናወን እንዳለብህ ማብራሪያ ልታይ ወይም ልትሰማ ትችላለህ።"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"ከ1 ወር በፊት"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ከ1 ወር በፊት"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"የግቤት ስልቶችን አዘጋጅ"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"የሚዳሰስ የቁልፍ ሰሌዳ"</string>
<string name="hardware" msgid="7517821086888990278">"ሃርድዌር"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"የቁልፍ ሰሌዳ አቀማመጥ ምረጥ"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"የቁልፍ ሰሌዳ አቀማመጥ ለመምረጥ ንካ።"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ዕጩዎች"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ማሰሺያን አስነሳ?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"ጥሪ ተቀበል?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ዘወትር"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"አንዴ ብቻ"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 7798b0a..d70aec8 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"محو طلب البحث"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"إرسال طلب البحث"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"البحث الصوتي"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"هل تريد تمكين ميزة Explore by Touch؟"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"يريد <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> تمكين ميزة Explore by Touch. عند تشغيل ميزة Explore by Touch، سيكون بإمكانك سماع أو مشاهدة أوصاف لما تحت إصبعك أو إجراء إيماءات للتفاعل مع الجهاز اللوحي."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"يريد <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> تمكين ميزة Explore by Touch. عند تشغيل ميزة Explore by Touch، سيكون بإمكانك سماع أو مشاهدة أوصاف لما تحت إصبعك أو إجراء إيماءات للتفاعل مع الهاتف."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"قبل شهر واحد"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"قبل شهر واحد"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"إعداد أسلوب الإدخال"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"لوحة مفاتيح فعلية"</string>
<string name="hardware" msgid="7517821086888990278">"أجهزة"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"تحديد تخطيط لوحة مفاتيح"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"المس لتحديد تخطيط لوحة مفاتيح."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"العناصر المرشحة"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"تشغيل المتصفح؟"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"هل تريد قبول المكالمة؟"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"دومًا"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"مرة واحدة فقط"</string>
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 97876f6..4190bdb 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Neteja la consulta"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Envia la consulta"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Cerca per veu"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Vols activar l\'Exploració per tacte?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vol activar l\'Exploració per tacte. Quan l\'Exploració per tacte està activada, pots escoltar o veure les descripcions del que hi ha sota el dit o fer gestos per interactuar amb la tauleta."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vol activar l\'Exploració per tacte. Quan l\'Exploració per tacte està activada, pots escoltar o veure les descripcions del que hi ha sota el dit o fer gestos per interactuar amb el telèfon."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Fa 1 mes"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Fa menys d\'1 mes"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Configura els mètodes d\'entrada"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Teclat físic"</string>
<string name="hardware" msgid="7517821086888990278">"Maquinari"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecciona una disposició de teclat"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca per seleccionar una disposició de teclat."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Vols iniciar el navegador?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Vols acceptar la trucada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Només una"</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index acd4bba..ad25a3e 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -145,7 +145,7 @@
<string name="shutdown_progress" msgid="2281079257329981203">"Vypínání..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet se vypne."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Váš telefon bude vypnut."</string>
- <string name="shutdown_confirm_question" msgid="2906544768881136183">"Chcete vypnout telefon?"</string>
+ <string name="shutdown_confirm_question" msgid="2906544768881136183">"Chcete zařízení vypnout?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Restart v nouzovém režimu"</string>
<string name="reboot_safemode_confirm" msgid="55293944502784668">"Chcete zařízení restartovat v nouzovém režimu? Deaktivujete tak veškeré nainstalované aplikace třetích stran. Po dalším restartu budou obnoveny."</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"Nejnovější"</string>
@@ -1205,7 +1205,7 @@
<string name="throttled_notification_title" msgid="6269541897729781332">"Byl překročen limit mobilních dat"</string>
<string name="throttled_notification_message" msgid="5443457321354907181">"Dotykem zobrazíte další informace o využití mobilních dat."</string>
<string name="no_matches" msgid="8129421908915840737">"Žádné shody"</string>
- <string name="find_on_page" msgid="1946799233822820384">"Vyhledat na stránce"</string>
+ <string name="find_on_page" msgid="1946799233822820384">"Hledat na stránce"</string>
<plurals name="matches_found">
<item quantity="one" msgid="8167147081136579439">"1 shoda"</item>
<item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> z <xliff:g id="TOTAL">%d</xliff:g>"</item>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index c44f789..8cde21f 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Απαλοιφή ερωτήματος"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Υποβολή ερωτήματος"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Φωνητική αναζήτηση"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Ενεργοποίηση Αναζήτησης μέσω αφής;"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"Η υπηρεσία <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> απαιτεί ενεργοποίηση της Εξερεύνησης μέσω αφής. Όταν είναι ενεργοποιημένη η Εξερεύνηση μέσω αφής, μπορείτε να δείτε ή να ακούσετε περιγραφές για τις επιλογές που βρίσκονται κάτω από το δάχτυλό σας ή να κάνετε κινήσεις αλληλεπίδρασης με το tablet σας."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Η υπηρεσία <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> απαιτεί ενεργοποίηση της Εξερεύνησης μέσω αφής. Όταν είναι ενεργοποιημένη η Εξερεύνηση μέσω αφής, μπορείτε να δείτε ή να ακούσετε περιγραφές για τις επιλογές που βρίσκονται κάτω από το δάχτυλό σας ή να κάνετε κινήσεις αλληλεπίδρασης με το τηλέφωνό σας."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"πριν από 1 μήνα"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Παλαιότερα από 1 μήνα"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Ρύθμιση μεθόδων εισαγωγής"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Φυσικό πληκτρολόγιο"</string>
<string name="hardware" msgid="7517821086888990278">"Υλικό"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Επιλογή διάταξης πληκτρολογίου"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Αγγίξτε για να επιλέξετε διάταξη πληκτρολογίου."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Εκκίνηση προγράμματος περιήγησης;"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Αποδοχή κλήσης;"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Πάντα"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Μόνο μία φορά"</string>
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index a54c479..4ad7daf 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Clear query"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Submit query"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Voice search"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Enable Explore by Touch?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wants to enable Explore by Touch. When Explore by Touch is turned on, you can hear or see descriptions of what\'s under your finger or perform gestures to interact with the tablet."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wants to enable Explore by Touch. When Explore by Touch is turned on, you can hear or see descriptions of what\'s under your finger or perform gestures to interact with the phone."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 month ago"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Before 1 month ago"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Set up input methods"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Physical keyboard"</string>
<string name="hardware" msgid="7517821086888990278">"Hardware"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Select keyboard layout"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Touch to select a keyboard layout."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Launch Browser?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 64429e9..4d861fc 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Eliminar la consulta"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Enviar consulta"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Búsqueda por voz"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"¿Habilitar exploración táctil?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quiere habilitar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con la tableta."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quiere habilitar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con el teléfono."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"hace 1 mes"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Anterior a 1 mes atrás"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de introducción"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
<string name="hardware" msgid="7517821086888990278">"Hardware"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecciona un diseño de teclado"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca para seleccionar un diseño de teclado."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"¿Deseas iniciar el navegador?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una vez"</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index f5ffece..f5d8795 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Borrar consulta"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Enviar consulta"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Búsqueda por voz"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"¿Habilitar exploración táctil?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quiere habilitar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con el tablet."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quiere habilitar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con el teléfono."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Hace un mes"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Hace más de un mes"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de introducción"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
<string name="hardware" msgid="7517821086888990278">"Hardware"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecciona un diseño de teclado"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca para seleccionar un diseño de teclado."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"¿Iniciar el navegador?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una vez"</string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index ea57cf5..af4b160 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -318,7 +318,7 @@
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"seo sisestusmeetodiga"</string>
<string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lubab omanikul siduda sisestusmeetodi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"sidumine juurdepääsuteenusega"</string>
- <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Lubab omanikul luua sideme juurdepääsuteenuseteenuse ülataseme liidesega. Tavarakenduste puhul ei tohiks seda kunagi vaja minna."</string>
+ <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Lubab omanikul luua sideme juurdepääsuteenuse ülataseme liidesega. Tavarakenduste puhul ei tohiks seda kunagi vaja minna."</string>
<string name="permlab_bindTextService" msgid="7358378401915287938">"tekstiteenusega sidumine"</string>
<string name="permdesc_bindTextService" msgid="8151968910973998670">"Võimaldab omanikul siduda tekstiteenuse (nt SpellCheckerService) ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindVpnService" msgid="4708596021161473255">"seo VPN-teenusega"</string>
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Tühjenda päring"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Päringu esitamine"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Häälotsing"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Kas lubada puudutusega uurimine?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> soovib lubada puudutusega uurimise. Kui puudutusega uurimine on sisse lülitatud, kuulete või näete kirjeldusi asjade kohta, mis on teie sõrme all, või saate suhelda tahvelarvutiga liigutuste abil."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> soovib lubada puudutusega uurimise. Kui puudutusega uurimine on sisse lülitatud, kuulete või näete kirjeldusi asjade kohta, mis on teie sõrme all, või saate suhelda telefoniga liigutuste abil."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 kuu tagasi"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Varem kui 1 kuu tagasi"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Seadista sisestusmeetodid"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Füüsiline klaviatuur"</string>
<string name="hardware" msgid="7517821086888990278">"Riistvara"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Klaviatuuri paigutuse valimine"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Puudutage klaviatuuri paigutuse valimiseks."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidaadid"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Kas käivitada brauser?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Kas vastata kõnele?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Alati"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Ainult üks kord"</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 393ba0c..cb83ba3 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"پاک کردن عبارت جستجو"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"ارسال عبارت جستجو"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"جستجوی صوتی"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"فعال کردن «کاوش با لمس»؟"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> میخواهد «کاوش با لمس» را فعال کند. وقتی «کاوش با لمس» فعال است، میتوانید توضیحاتی را برای آنچه که زیر انگشت شما است مشاهده کرده یا بشنوید یا برای استفاده از رایانه لوحی از حرکات اشاره استفاده کنید."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> میخواهد «کاوش با لمس» را فعال کند. وقتی «کاوش با لمس» فعال است، میتوانید توضیحاتی را برای آنچه که زیر انگشت شما است مشاهده کرده یا بشنوید یا برای استفاده از تلفن خود از حرکات اشاره استفاده کنید."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ماه قبل"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"قبل از 1 ماه گذشته"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"تنظیم روشهای ورودی"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"صفحه کلید فیزیکی"</string>
<string name="hardware" msgid="7517821086888990278">"سختافزار"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"انتخاب طرحبندی صفحه کلید"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"برای انتخاب یک طرحبندی صفحه کلید لمس کنید…"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"داوطلبین"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"مرورگر راهاندازی شود؟"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"تماس را میپذیرید؟"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"همیشه"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"فقط یک بار"</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index f249c2c..b2879e9 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -606,30 +606,30 @@
<item msgid="1735177144948329370">"Faks Rumah"</item>
<item msgid="603878674477207394">"Pager"</item>
<item msgid="1650824275177931637">"Lainnya"</item>
- <item msgid="9192514806975898961">"Ubahsuaian"</item>
+ <item msgid="9192514806975898961">"Khusus"</item>
</string-array>
<string-array name="emailAddressTypes">
<item msgid="8073994352956129127">"Rumah"</item>
<item msgid="7084237356602625604">"Kantor"</item>
<item msgid="1112044410659011023">"Lainnya"</item>
- <item msgid="2374913952870110618">"Ubahsuaian"</item>
+ <item msgid="2374913952870110618">"Khusus"</item>
</string-array>
<string-array name="postalAddressTypes">
<item msgid="6880257626740047286">"Rumah"</item>
<item msgid="5629153956045109251">"Kantor"</item>
<item msgid="4966604264500343469">"Lainnya"</item>
- <item msgid="4932682847595299369">"Ubahsuaian"</item>
+ <item msgid="4932682847595299369">"Khusus"</item>
</string-array>
<string-array name="imAddressTypes">
<item msgid="1738585194601476694">"Rumah"</item>
<item msgid="1359644565647383708">"Kantor"</item>
<item msgid="7868549401053615677">"Lainnya"</item>
- <item msgid="3145118944639869809">"Ubahsuaian"</item>
+ <item msgid="3145118944639869809">"Khusus"</item>
</string-array>
<string-array name="organizationTypes">
<item msgid="7546335612189115615">"Kantor"</item>
<item msgid="4378074129049520373">"Lainnya"</item>
- <item msgid="3455047468583965104">"Ubahsuaian"</item>
+ <item msgid="3455047468583965104">"Khusus"</item>
</string-array>
<string-array name="imProtocols">
<item msgid="8595261363518459565">"AIM"</item>
@@ -641,7 +641,7 @@
<item msgid="2506857312718630823">"ICQ"</item>
<item msgid="1648797903785279353">"Jabber"</item>
</string-array>
- <string name="phoneTypeCustom" msgid="1644738059053355820">"Ubahsuaian"</string>
+ <string name="phoneTypeCustom" msgid="1644738059053355820">"Khusus"</string>
<string name="phoneTypeHome" msgid="2570923463033985887">"Rumah"</string>
<string name="phoneTypeMobile" msgid="6501463557754751037">"Seluler"</string>
<string name="phoneTypeWork" msgid="8863939667059911633">"Kantor"</string>
@@ -662,24 +662,24 @@
<string name="phoneTypeWorkPager" msgid="649938731231157056">"Pager Kantor"</string>
<string name="phoneTypeAssistant" msgid="5596772636128562884">"Asisten"</string>
<string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
- <string name="eventTypeCustom" msgid="7837586198458073404">"Ubahsuaian"</string>
+ <string name="eventTypeCustom" msgid="7837586198458073404">"Khusus"</string>
<string name="eventTypeBirthday" msgid="2813379844211390740">"Hari Ulang Tahun"</string>
<string name="eventTypeAnniversary" msgid="3876779744518284000">"Hari Peringatan"</string>
<string name="eventTypeOther" msgid="7388178939010143077">"Lainnya"</string>
- <string name="emailTypeCustom" msgid="8525960257804213846">"Ubahsuaian"</string>
+ <string name="emailTypeCustom" msgid="8525960257804213846">"Khusus"</string>
<string name="emailTypeHome" msgid="449227236140433919">"Rumah"</string>
<string name="emailTypeWork" msgid="3548058059601149973">"Kantor"</string>
<string name="emailTypeOther" msgid="2923008695272639549">"Lainnya"</string>
<string name="emailTypeMobile" msgid="119919005321166205">"Seluler"</string>
- <string name="postalTypeCustom" msgid="8903206903060479902">"Ubahsuaian"</string>
+ <string name="postalTypeCustom" msgid="8903206903060479902">"Khusus"</string>
<string name="postalTypeHome" msgid="8165756977184483097">"Rumah"</string>
<string name="postalTypeWork" msgid="5268172772387694495">"Kantor"</string>
<string name="postalTypeOther" msgid="2726111966623584341">"Lainnya"</string>
- <string name="imTypeCustom" msgid="2074028755527826046">"Ubahsuaian"</string>
+ <string name="imTypeCustom" msgid="2074028755527826046">"Khusus"</string>
<string name="imTypeHome" msgid="6241181032954263892">"Rumah"</string>
<string name="imTypeWork" msgid="1371489290242433090">"Kantor"</string>
<string name="imTypeOther" msgid="5377007495735915478">"Lainnya"</string>
- <string name="imProtocolCustom" msgid="6919453836618749992">"Ubahsuaian"</string>
+ <string name="imProtocolCustom" msgid="6919453836618749992">"Khusus"</string>
<string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
<string name="imProtocolMsn" msgid="144556545420769442">"Windows Live"</string>
<string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
@@ -691,8 +691,8 @@
<string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
<string name="orgTypeWork" msgid="29268870505363872">"Kantor"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Lainnya"</string>
- <string name="orgTypeCustom" msgid="225523415372088322">"Ubahsuaian"</string>
- <string name="relationTypeCustom" msgid="3542403679827297300">"Ubahsuaian"</string>
+ <string name="orgTypeCustom" msgid="225523415372088322">"Khusus"</string>
+ <string name="relationTypeCustom" msgid="3542403679827297300">"Khusus"</string>
<string name="relationTypeAssistant" msgid="6274334825195379076">"Asisten"</string>
<string name="relationTypeBrother" msgid="8757913506784067713">"Saudara laki-laki"</string>
<string name="relationTypeChild" msgid="1890746277276881626">"Anak"</string>
@@ -707,7 +707,7 @@
<string name="relationTypeRelative" msgid="1799819930085610271">"Sanak saudara"</string>
<string name="relationTypeSister" msgid="1735983554479076481">"Saudara perempuan"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"Pasangan"</string>
- <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Ubahsuaian"</string>
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Khusus"</string>
<string name="sipAddressTypeHome" msgid="6093598181069359295">"Beranda"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"Kerjaan"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"Lainnya"</string>
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Hapus kueri"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Mengirimkan kueri"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Penelusuran suara"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Aktifkan Menjelajah dengan Sentuhan?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mengaktifkan Menjelajah dengan Sentuhan. Saat Menjelajah dengan Sentuhan diaktifkan, Anda dapat melihat atau mendengar deskripsi dari apa yang ada di bawah jari Anda atau melakukan gerakan untuk berinteraksi dengan tablet."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mengaktifkan Menjelajah dengan Sentuhan. Saat Menjelajah dengan Sentuhan diaktifkan, Anda dapat mendengar atau melihat deskripsi dari apa yang ada di bawah jari Anda atau melakukan gerakan untuk berinteraksi dengan ponsel."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 bulan yang lalu"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Sebelum 1 bulan yang lalu"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Menyiapkan metode masukan"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Keyboard fisik"</string>
<string name="hardware" msgid="7517821086888990278">"Perangkat Keras"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pilih tata letak keyboard"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Sentuh untuk memilih tata letak keyboard."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Luncurkan Browser?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Selalu"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Hanya sekali"</string>
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 65cb688..265da95 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"נקה שאילתה"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"שלח שאילתה"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"חיפוש קולי"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"האם להפעיל את התכונה \'חקור על ידי מגע\'?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> רוצה להפעיל את התכונה \'חקור על ידי מגע\'. כאשר התכונה \'חקור על ידי מגע\' מופעלת, אתה יכול לשמוע או לראות תיאורים של הפריטים שעליהם אצבעך מונחת או לקיים אינטראקציה עם הטאבלט באמצעות מחוות."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> רוצה להפעיל את התכונה \'חקור על ידי מגע\'. כאשר התכונה \'חקור על ידי מגע\' מופעלת, אתה יכול לשמוע או לראות תיאורים של הפריטים שעליהם אצבעך מונחת או לקיים אינטראקציה עם הטלפון באמצעות מחוות."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"לפני חודש אחד"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"לפני חודש אחד"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"הגדר שיטות קלט"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"מקלדת פיזית"</string>
<string name="hardware" msgid="7517821086888990278">"חומרה"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"בחירת פריסת מקלדת"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"גע כדי לבחור פריסת מקלדת."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"מועמדים"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"להפעיל את הדפדפן?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"האם לקבל את השיחה?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"תמיד"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"רק פעם אחת"</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 03de346..4e3fe51 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"검색어 삭제"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"검색어 보내기"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"음성 검색"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"\'터치하여 탐색\'을 사용하시겠습니까?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>을(를) 사용하려면 \'터치하여 탐색\' 기능을 사용하도록 설정해야 합니다. \'터치하여 탐색\'을 사용하도록 설정하면, 화면을 터치하여 손가락 아래에 표시된 항목에 대한 설명을 듣고 보거나 태블릿으로 상호작용하기 위한 동작을 수행할 수 있습니다."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>을(를) 사용하려면 \'터치하여 탐색\' 기능을 사용하도록 설정해야 합니다. \'터치하여 탐색\'을 사용하도록 설정하면, 화면을 터치하여 손가락 아래에 표시된 항목에 대한 설명을 듣고 보거나 휴대전화로 상호작용하기 위한 동작을 수행할 수 있습니다."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"한 달 전"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"한 달 전"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"입력 방법 설정"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"물리적 키보드"</string>
<string name="hardware" msgid="7517821086888990278">"하드웨어"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"키보드 레이아웃 선택"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"터치하여 키보드 레이아웃을 선택합니다."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"브라우저를 실행하시겠습니까?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"통화를 수락하시겠습니까?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"항상"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"한 번만"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0474391..52b7a4b 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Išvalyti užklausą"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Patvirtinti užklausą"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Paieška balsu"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Įgalinti naršymą liečiant?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"„<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>“ nori įgalinti naršymą liečiant. Kai naršymas liečiant bus įjungtas, galėsite išgirsti ar peržiūrėti pirštu liečiamų elementų aprašus arba atlikdami gestus naudoti planšetinį kompiuterį."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"„<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>“ nori įgalinti naršymą liečiant. Kai naršymas liečiant bus įjungtas, galėsite išgirsti ar peržiūrėti pirštu liečiamų elementų aprašus arba atlikdami gestus naudoti telefoną."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Prieš 1 mėn."</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Prieš maždaug 1 mėnesį"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Nustatyti įvesties metodus"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Fizinė klaviatūra"</string>
<string name="hardware" msgid="7517821086888990278">"Apar. įr."</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pasirinkite klaviatūros išdėstymą"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Palieskite, kad pasirinktumėte klaviatūros išdėstymą."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidatai"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Paleisti naršyklę?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Priimti skambutį?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Visada"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Tik kartą"</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index aaed6e2..1fb76f6 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Notīrīt vaicājumu"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Iesniedziet vaicājumu."</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Meklēšana ar balsi"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Vai iesp. “Pārlūkot pieskaroties”?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vēlas iespējot funkciju “Atklāt pieskaroties”. Kad ir ieslēgta funkcija “Atklāt pieskaroties”, var dzirdēt vai redzēt tā vienuma aprakstu, virs kura atrodas pirksts, vai veikt žestus, lai mijiedarbotos ar planšetdatoru."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vēlas iespējot funkciju “Atklāt pieskaroties”. Kad ir ieslēgta funkcija “Atklāt pieskaroties”, var dzirdēt vai redzēt tā vienuma aprakstu, virs kura atrodas pirksts, vai veikt žestus, lai mijiedarbotos ar tālruni."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Pirms 1 mēneša"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vairāk nekā pirms 1 mēneša"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Iestatīt ievades metodes"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Fiziskā tastatūra"</string>
<string name="hardware" msgid="7517821086888990278">"Aparatūra"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Atlasiet tastatūras izkārtojumu"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Pieskarieties, lai atlasītu tastatūras izkārtojumu."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidāti"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Vai palaist pārlūkprogrammu?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Vai atbildēt uz zvanu?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Vienmēr"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Tikai vienreiz"</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index fec15b2..2168b9a 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Pertanyaan jelas"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Serah pertanyaan"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Carian suara"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Dayakan Jelajah melalui Sentuhan?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mendayakan Jelajah melalui Sentuhan. Apabila Jelajah melalui Sentuhan didayakan, anda boleh mendengar atau melihat penerangan tentang apa di bawah jari anda atau melakukan gerak isyarat untuk berinteraksi dengan tablet."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mendayakan Jelajah melalui Sentuhan. Apabila Jelajah melalui Sentuhan didayakan, anda boleh mendengar atau melihat penerangan tentang apa di bawah jari anda atau melakukan gerak isyarat untuk berinteraksi dengan telefon."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 bulan yang lalu"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Sebelum 1 bulan yang lalu"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Sediakan kaedah input"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Papan kekunci fizikal"</string>
<string name="hardware" msgid="7517821086888990278">"Perkakasan"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pilih susun atur papan kekunci"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Sentuh untuk memilih susun atur papan kekunci."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Lancarkan Penyemak Imbas?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sentiasa"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Hanya sekali"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index a634006..a1cbe5a 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Wyczyść zapytanie"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Wyślij zapytanie"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Wyszukiwanie głosowe"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Włączyć Czytanie dotykiem?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> chce włączyć Czytanie dotykiem. Gdy ta funkcja jest włączona, słyszysz i widzisz opisy elementów, które są pod Twoim palcem, oraz możesz obsługiwać tablet gestami."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> chce włączyć Czytanie dotykiem. Gdy ta funkcja jest włączona, słyszysz i widzisz opisy elementów, które są pod Twoim palcem, oraz możesz obsługiwać telefon gestami."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 miesiąc temu"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ponad 1 miesiąc temu"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Konfiguruj metody wprowadzania"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Klawiatura fizyczna"</string>
<string name="hardware" msgid="7517821086888990278">"Sprzęt"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Wybierz układ klawiatury"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Kliknij, by wybrać układ klawiatury."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Uruchomić przeglądarkę?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Odebrać połączenie?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Zawsze"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Tylko raz"</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 2a4855c..3acafb1 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Limpar consulta"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Enviar consulta"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Pesquisa por voz"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Ativar exploração pelo toque?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quer ativar a exploração pelo toque. Com ela, você pode ouvir ou ver descrições do que está sob seu dedo e interagir com o tablet através de gestos."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quer ativar a exploração pelo toque. Com ela, você pode ouvir ou ver descrições do que está sob seu dedo e interagir com o telefone através de gestos."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 mês atrás"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Antes de 1 mês atrás"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de entrada"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
<string name="hardware" msgid="7517821086888990278">"Hardware"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecione o layout de teclado"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toque para selecionar um layout de teclado."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Abrir Navegador?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Só uma vez"</string>
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 90398a3..2e019d4 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -317,8 +317,8 @@
<string name="permdesc_readInputState" msgid="8387754901688728043">"Programu omogoča spremljanje tipk, ki jih pritisnete med interakcijo z drugim programom (na primer vnos gesla). Navadni programi tega nikoli ne potrebujejo."</string>
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"povezovanje z načinom vnosa"</string>
<string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lastniku omogoča, da se poveže z vmesnikom načina vnosa najvišje ravni. Tega nikoli ni treba uporabiti za navadne programe."</string>
- <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vezano na storitev za ljudi s posebnimi potrebami"</string>
- <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Lastniku omogoča povezovanje z vmesnikom storitve za ljudi s posebnimi potrebami najvišje ravni. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
+ <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"povezovanje s storitvijo za ljudi s posebnimi potrebami"</string>
+ <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Lastniku omogoča povezovanje z vmesnikom najvišje ravni storitve za ljudi s posebnimi potrebami. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
<string name="permlab_bindTextService" msgid="7358378401915287938">"poveži z besedilno storitvijo"</string>
<string name="permdesc_bindTextService" msgid="8151968910973998670">"Dovoljuje, da se lastnik poveže z vmesnikom besedilne storitve najvišje ravni (npr. SpellCheckerService). Tega nikoli ni treba uporabiti za navadne programe."</string>
<string name="permlab_bindVpnService" msgid="4708596021161473255">"povezava s storitvijo navideznega zasebnega omrežja"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 40345d1..35079c5 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Futa swali"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Wasilisha hoja"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Utafutaji wa sauti"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Wezesha Kuchunguza kwa Kugusa?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> inataka kuwezesha Kuchunguza kwa Kugusa. Wakati Kuchunguza kwa Kugusa kumewezeshwa, unaweza kusikia au kuona maelezo ya ni nini kilichochini ya kidole chako au kufanya ishara za kuingiliana na kumpyuta ndogo."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> inataka kuwezesha Kuchunguza kwa Kugusa. Wakati Kuchunguza kwa Kugusa kumewezeshwa, unaweza kusikia au kuona maelezo ya ni nini kilichochini ya kidole chako au kufanya ishara za kuingiliana na simu."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Mwezi 1 uliopita"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Kabla ya mwezi 1 uliopita"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Weka mbinu za ingizo"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Kibodi halisi"</string>
<string name="hardware" msgid="7517821086888990278">"Maunzi"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Teua mpangilio wa kibodi"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Gusa kuchagua mpangilio wa kibodi."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"wagombeaji"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Zindua Kivinjari?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Kubali simu?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Kila mara"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Mara moja tu"</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 8de8e5e..34e4433 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"ล้างข้อความค้นหา"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"ส่งข้อความค้นหา"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"ค้นหาด้วยเสียง"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"เปิดใช้งาน \"สำรวจโดยการแตะ\" หรือไม่"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ต้องการเปิดใช้งาน \"สำรวจโดยการแตะ\" เมื่อเปิดใช้งานแล้ว คุณสามารถฟังหรือดูคำอธิบายของสิ่งที่อยู่ใต้นิ้วของคุณ หรือใช้ท่าทางสัมผัสต่างๆ เพื่อโต้ตอบกับแท็บเล็ตได้"</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ต้องการเปิดใช้งาน \"สำรวจโดยการแตะ\" เมื่อเปิดใช้งานแล้ว คุณสามารถฟังหรือดูคำอธิบายของสิ่งที่อยู่ใต้นิ้วของคุณ หรือใช้ท่าทางสัมผัสต่างๆ เพื่อโต้ตอบกับโทรศัพท์ได้"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 เดือนที่ผ่านมา"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ก่อน 1 เดือนที่แล้ว"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"ตั้งค่าวิธีการป้อนข้อมูล"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"แป้นพิมพ์บนเครื่อง"</string>
<string name="hardware" msgid="7517821086888990278">"ฮาร์ดแวร์"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"เลือกรูปแบบแป้นพิมพ์"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"แตะเพื่อเลือกรูปแบบแป้นพิมพ์"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ตัวเลือก"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"เปิดเบราว์เซอร์หรือไม่"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"รับสายหรือไม่"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ทุกครั้ง"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"เฉพาะครั้งนี้"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index a659e9e..666d131 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"I-clear ang query"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Isumite ang query"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Paghahanap gamit ang boses"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Paganahin ang Galugad sa pagpindot?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"Nais paganahin ng <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ang Galugarin sa pamamagitan ng pagpindot. Kapag naka-on ang Galugarin sa pamamagitan ng pagpindot, maaari mong marinig o makita ang mga paglalarawan ng nasa ilalim ng iyong daliri o maaari kang magsagawa ng mga galaw upang makipag-ugnayan sa tablet."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Nais paganahin ng <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ang Galugarin sa pamamagitan ng pagpindot. Kapag naka-on ang Galugarin sa pamamagitan ng pagpindot, maaari mong marinig o makita ang mga paglalarawan ng nasa ilalim ng iyong daliri o maaari kang magsagawa ng mga galaw upang makipag-ugnayan sa telepono."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 buwan ang nakalipas"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Bago ang nakalipas na 1 buwan"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"I-set up paraan ng pag-input"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Aktwal na keyboard"</string>
<string name="hardware" msgid="7517821086888990278">"Hardware"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pumili ng layout ng keyboard"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Pindutin upang pumili ng layout ng keyboard."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"mga kandidato"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Ilunsad ang Browser?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Tanggapin ang tawag?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Palagi"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Isang beses lang"</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 5d06934..3e3b506 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Очистити запит"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Наіслати запит"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Голосовий пошук"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Увімкнути дослідження дотиком?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> хоче ввімкнути функцію дослідження дотиком. Увімкнувши функцію дослідження дотиком, можна чути або бачити опис елемента, розташованого під вашим пальцем, або виконувати жести для взаємодії з планшетним ПК."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> хоче ввімкнути функцію дослідження дотиком. Увімкнувши функцію дослідження дотиком, можна чути або бачити опис елемента, розташованого під вашим пальцем, або виконувати жести для взаємодії з телефоном."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 міс. тому"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Раніше 1 місяця тому"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Налаштувати методи введення"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Фізична клавіатура"</string>
<string name="hardware" msgid="7517821086888990278">"Обладнання"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Виберіть розкладку клавіатури"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Торкніться, щоб вибрати розкладку клавіатури."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Запустити веб-переглядач?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Прийняти виклик?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Завжди"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Лише цього разу"</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index cce563a..af89a2d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"Xóa truy vấn"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Gửi truy vấn"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Tìm kiếm bằng giọng nói"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Bật Khám phá bằng cách chạm?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> muốn bật Khám phá bằng cách chạm. Khi Khám phá bằng cách chạm được bật, bạn có thể nghe hoặc xem mô tả dưới ngón tay bạn hoặc thực hiện cử chỉ để tương tác với máy tính bảng."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> muốn bật Khám phá bằng cách chạm. Khi Khám phá bằng cách chạm được bật, bạn có thể nghe hoặc xem mô tả dưới ngón tay bạn hoặc thực hiện cử chỉ để tương tác với điện thoại."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 tháng trước"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Trước 1 tháng trước"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Thiết lập phương thức nhập"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Bàn phím thực"</string>
<string name="hardware" msgid="7517821086888990278">"Phần cứng"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Chọn bố cục bàn phím"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Chạm để chọn bố cục bàn phím."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ứng viên"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Khởi chạy trình duyệt?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Chấp nhận cuộc gọi?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Luôn chọn"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Chỉ một lần"</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 7cd2d9d..865761b 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -185,10 +185,10 @@
<string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"使用耗电量较大的功能。"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"日历"</string>
<string name="permgroupdesc_calendar" msgid="5777534316982184416">"直接访问日历和活动。"</string>
- <string name="permgrouplab_dictionary" msgid="4148597128843641379">"读取用户字典"</string>
- <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"读取用户字典中的字词。"</string>
- <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"写入用户字典"</string>
- <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"将字词添加到用户字典。"</string>
+ <string name="permgrouplab_dictionary" msgid="4148597128843641379">"读取用户词典"</string>
+ <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"读取用户词典中的字词。"</string>
+ <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"写入用户词典"</string>
+ <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"将字词添加到用户词典。"</string>
<string name="permgrouplab_bookmarks" msgid="1949519673103968229">"书签和历史记录"</string>
<string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"直接访问书签和浏览器历史记录。"</string>
<string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"闹钟"</string>
@@ -211,7 +211,7 @@
<string name="permgroupdesc_syncSettings" msgid="7603195265129031797">"访问同步设置。"</string>
<string name="permgrouplab_accounts" msgid="3359646291125325519">"您的帐户"</string>
<string name="permgroupdesc_accounts" msgid="4948732641827091312">"访问可用的帐户。"</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"硬件控件"</string>
+ <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"硬件控制"</string>
<string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"直接访问手机上的硬件。"</string>
<string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"手机通话"</string>
<string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"监管、记录和处理电话呼叫。"</string>
@@ -554,7 +554,7 @@
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"允许应用获取有关当前同步的 Feed 的详情。"</string>
<string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"写入订阅的供稿"</string>
<string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"允许应用修改您当前同步的 Feed。恶意应用可能会更改您的同步 Feed。"</string>
- <string name="permlab_readDictionary" msgid="4107101525746035718">"读取您添加到字典的字词"</string>
+ <string name="permlab_readDictionary" msgid="4107101525746035718">"读取您添加到词典的字词"</string>
<string name="permdesc_readDictionary" msgid="8977815988329283705">"允许应用读取用户可能在用户词典中已存储的任意私有字词、名称和短语。"</string>
<string name="permlab_writeDictionary" msgid="2296383164914812772">"写入用户定义的词典"</string>
<string name="permdesc_writeDictionary" msgid="8185385716255065291">"允许应用向用户词典中写入新词。"</string>
@@ -1111,7 +1111,7 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"如果您打开 USB 存储设备,您正在使用的某些应用将会停止,并且在您关闭 USB 存储设备前都将无法使用。"</string>
<string name="dlg_error_title" msgid="7323658469626514207">"USB 操作失败"</string>
<string name="dlg_ok" msgid="7376953167039865701">"确定"</string>
- <string name="usb_mtp_notification_title" msgid="3699913097391550394">"作为媒体设备连接"</string>
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"已作为媒体设备连接"</string>
<string name="usb_ptp_notification_title" msgid="1960817192216064833">"作为相机连接"</string>
<string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"作为安装程序连接"</string>
<string name="usb_accessory_notification_title" msgid="7848236974087653666">"已连接到 USB 配件"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 0c7d269..7966153 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -855,12 +855,9 @@
<string name="searchview_description_clear" msgid="1330281990951833033">"xazulula umbuzo"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Thumela umbuzo"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Ukusesha ngezwi"</string>
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Nika amandla i-Explore by Touch?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"I-<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ifuna ukunika amandla i-Explore by Touch. Uma i-Explore by Touch ikhanya, ungezwa noma ubone izincazelo ezingaphansi komunwe wakho noma wenze izenzo zomzimba ukuze uxhumane nethebhulethi."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"I-<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ifuna ukunika amandla i-Explore by Touch. Uma i-Explore by Touch ikhanya, ungezwa noma ubone izincazelo ezingaphansi komunwe wakho noma wenze izenzo zomzimba ukuze uxhumane nefoni."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"inyanga engu-1 edlule"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ngaphambi kwenyanga engu-1 edlule"</string>
<plurals name="num_seconds_ago">
@@ -1127,10 +1124,8 @@
<string name="configure_input_methods" msgid="9091652157722495116">"Izilungiselelo zezindlela zokufakwayo"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Ukwakheka kwekhibhodi"</string>
<string name="hardware" msgid="7517821086888990278">"I-Hardware"</string>
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Khetha isendlalelo sekhibhodi"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Thinta ukuze ukhethe isendlalelo sekhibhodi."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"abahlanganyeli"</u></string>
@@ -1324,6 +1319,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Qala Isiphequluli?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Amukela ucingo?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Njalo"</string>
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Kanje nje"</string>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2f540a5..e9a3385 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2136,7 +2136,8 @@
query the screen. Note: While not recommended, an accessibility service may
decide to ignore this attribute and operate on all views in the view tree. -->
<attr name="importantForAccessibility" format="integer">
- <!-- The system determines whether the view is important for accessibility (recommended). -->
+ <!-- The system determines whether the view is important for accessibility - default
+ (recommended). -->
<enum name="auto" value="0" />
<!-- The view is important for accessibility. -->
<enum name="yes" value="1" />
@@ -2144,6 +2145,40 @@
<enum name="no" value="2" />
</attr>
+ <!-- @hide Controls whether this view can take accessibility focus. -->
+ <attr name="accessibilityFocusable" format="integer">
+ <!-- The system determines whether the view can take accessibility focus - default
+ (recommended).
+ <p>
+ Such a view is consideted by the focus search if it is:
+ <ul>
+ <li>
+ Important for accessibility and actionable (clickable, long clickable, focusable)
+ </li>
+ <li>
+ Important for accessibility, not actionable (clickable, long clickable, focusable),
+ and does not have an actionable predecessor.
+ </li>
+ </ul>
+ An accessibility srvice can request putting accessibility focus on such a view.
+ </p> -->
+ <enum name="auto" value="0" />
+ <!-- The view can take accessibility focus.
+ <p>
+ A view that can take accessibility focus is always considered during focus
+ search and an accessibility service can request putting accessibility focus
+ on it.
+ </p> -->
+ <enum name="yes" value="1" />
+ <!-- The view can not take accessibility focus.
+ <p>
+ A view that can not take accessibility focus is never considered during focus
+ search and an accessibility service can not request putting accessibility focus
+ on it.
+ </p> -->
+ <enum name="no" value="2" />
+ </attr>
+
</declare-styleable>
<!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 98e7769..09e3fbb 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -577,11 +577,11 @@
<!-- True if WallpaperService is enabled -->
<bool name="config_enableWallpaperService">true</bool>
- <!-- Component name of the service providing network location support. -->
- <string name="config_networkLocationProvider" translatable="false">@null</string>
+ <!-- Package name providing network location support. -->
+ <string name="config_networkLocationProviderPackageName" translatable="false">@null</string>
- <!-- Component name of the service providing geocoder API support. -->
- <string name="config_geocodeProvider" translatable="false">@null</string>
+ <!-- Package name providing geocoder API support. -->
+ <string name="config_geocodeProviderPackageName" translatable="false">@null</string>
<!-- Boolean indicating if current platform supports bluetooth SCO for off call
use cases -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5d8ddc9a..bf9fe42 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -28,7 +28,6 @@
this.
-->
<java-symbol type="id" name="account_name" />
- <java-symbol type="id" name="account_row_checkmark" />
<java-symbol type="id" name="account_row_icon" />
<java-symbol type="id" name="account_row_text" />
<java-symbol type="id" name="account_type" />
@@ -41,7 +40,6 @@
<java-symbol type="id" name="action_menu_presenter" />
<java-symbol type="id" name="action_mode_close_button" />
<java-symbol type="id" name="activity_chooser_view_content" />
- <java-symbol type="id" name="addAccount" />
<java-symbol type="id" name="albumart" />
<java-symbol type="id" name="alertTitle" />
<java-symbol type="id" name="allow_button" />
@@ -122,7 +120,6 @@
<java-symbol type="id" name="old_app_action" />
<java-symbol type="id" name="old_app_description" />
<java-symbol type="id" name="old_app_icon" />
- <java-symbol type="id" name="overflow_title" />
<java-symbol type="id" name="package_label" />
<java-symbol type="id" name="packages_list" />
<java-symbol type="id" name="pause" />
@@ -212,6 +209,8 @@
<java-symbol type="id" name="inbox_text6" />
<java-symbol type="id" name="inbox_more" />
<java-symbol type="id" name="status_bar_latest_event_content" />
+ <java-symbol type="id" name="action_divider" />
+ <java-symbol type="id" name="overflow_divider" />
<java-symbol type="attr" name="actionModeShareDrawable" />
<java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -301,6 +300,7 @@
<java-symbol type="dimen" name="notification_title_text_size" />
<java-symbol type="dimen" name="notification_subtext_size" />
+ <java-symbol type="string" name="add_account_button_label" />
<java-symbol type="string" name="addToDictionary" />
<java-symbol type="string" name="action_bar_home_description" />
<java-symbol type="string" name="action_bar_up_description" />
@@ -1027,7 +1027,6 @@
<java-symbol type="layout" name="choose_account" />
<java-symbol type="layout" name="choose_account_row" />
<java-symbol type="layout" name="choose_account_type" />
- <java-symbol type="layout" name="choose_selected_account_row" />
<java-symbol type="layout" name="choose_type_and_account" />
<java-symbol type="layout" name="grant_credentials_permission" />
<java-symbol type="layout" name="number_picker" />
@@ -1460,8 +1459,8 @@
<java-symbol type="string" name="car_mode_disable_notification_title" />
<java-symbol type="string" name="chooser_wallpaper" />
<java-symbol type="string" name="config_datause_iface" />
- <java-symbol type="string" name="config_geocodeProvider" />
- <java-symbol type="string" name="config_networkLocationProvider" />
+ <java-symbol type="string" name="config_geocodeProviderPackageName" />
+ <java-symbol type="string" name="config_networkLocationProviderPackageName" />
<java-symbol type="string" name="config_wimaxManagerClassname" />
<java-symbol type="string" name="config_wimaxNativeLibLocation" />
<java-symbol type="string" name="config_wimaxServiceClassname" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5929439..65457b3 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3382,9 +3382,8 @@
<string name="choose_account_label">Choose an account</string>
<string name="add_account_label">"Add an account"</string>
- <string name="choose_account_text">"Which account do you want to use?"</string>
- <!-- Button label to add an account [CHAR LIMIT=20] -->
+ <!-- List item to add an account [CHAR LIMIT=20] -->
<string name="add_account_button_label">Add account</string>
<!-- NumberPicker - accessibility support -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index a54cdf1..223d17a 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -239,7 +239,7 @@
</style>
<!-- Notification content styles -->
<style name="TextAppearance.StatusBar.EventContent">
- <item name="android:textColor">#808080</item>
+ <item name="android:textColor">#999999</item>
<item name="android:textSize">@dimen/notification_text_size</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Title">
@@ -253,11 +253,14 @@
</style>
<style name="TextAppearance.StatusBar.EventContent.Info">
<item name="android:textSize">@dimen/notification_subtext_size</item>
- <item name="android:textColor">#666666</item>
+ <item name="android:textColor">#999999</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Time">
<item name="android:textSize">@dimen/notification_subtext_size</item>
- <item name="android:textColor">#666666</item>
+ <item name="android:textColor">#999999</item>
+ </style>
+ <style name="TextAppearance.StatusBar.EventContent.Emphasis">
+ <item name="android:textColor">#CCCCCC</item>
</style>
<style name="TextAppearance.Small.CalendarViewWeekDayView">
diff --git a/docs/html/guide/topics/ui/index.jd b/docs/html/guide/topics/ui/index.jd
index 45c9ac9..be07249 100644
--- a/docs/html/guide/topics/ui/index.jd
+++ b/docs/html/guide/topics/ui/index.jd
@@ -148,7 +148,7 @@
On<em><something></em>Listener, each with a callback method called <code>On<em><something></em>()</code>.
For example, {@link android.view.View.OnClickListener} (for handling "clicks" on a View),
{@link android.view.View.OnTouchListener} (for handling touch screen events in a View), and
-{@link android.view.View.OnKeyListener} (for handling device key presses within a View). So if you want your View
+{@link android.view.View.OnKeyListener} if you want to handle hardware key presses within a View. So if you want your View
to be notified when it is "clicked" (such as when a button is selected), implement OnClickListener and define
its <code>onClick()</code> callback method (where you perform the action upon click), and register it
to the View with <code>{@link android.view.View#setOnClickListener(View.OnClickListener) setOnClickListener()}</code>.
@@ -158,7 +158,7 @@
that occur within it. Example events you can handle include when the
screen is touched (<code>{@link android.view.View#onTouchEvent(MotionEvent) onTouchEvent()}</code>), when
the trackball is moved (<code>{@link android.view.View#onTrackballEvent(MotionEvent) onTrackballEvent()}</code>),
-or when a key on the device is pressed (<code>{@link android.view.View#onKeyDown(int, KeyEvent)
+or when a <em>hardware</em> key on the device is pressed (<code>{@link android.view.View#onKeyDown(int, KeyEvent)
onKeyDown()}</code>). This allows you to define the default behavior for each event inside your custom View and determine
whether the event should be passed on to some other child View. Again, these are callbacks to the View class,
so your only chance to define them is when you
diff --git a/docs/html/guide/topics/ui/ui-events.jd b/docs/html/guide/topics/ui/ui-events.jd
index 93bad43..707d4b1 100644
--- a/docs/html/guide/topics/ui/ui-events.jd
+++ b/docs/html/guide/topics/ui/ui-events.jd
@@ -64,7 +64,7 @@
This is called when the user navigates onto or away from the item, using the navigation-keys or trackball.</dd>
<dt><code>onKey()</code></dt>
<dd>From {@link android.view.View.OnKeyListener}.
- This is called when the user is focused on the item and presses or releases a key on the device.</dd>
+ This is called when the user is focused on the item and presses or releases a hardware key on the device.</dd>
<dt><code>onTouch()</code></dt>
<dd>From {@link android.view.View.OnTouchListener}.
This is called when the user performs an action qualified as a touch event, including a press, a release,
@@ -143,13 +143,23 @@
within the event, such as a finger gesture, or the eventual up action event.</li>
</ul>
-<p>Remember that key events are always delivered to the View currently in focus. They are dispatched starting from the top
+<p>Remember that hardware key events are always delivered to the View currently in focus. They are dispatched starting from the top
of the View hierarchy, and then down, until they reach the appropriate destination. If your View (or a child of your View)
currently has focus, then you can see the event travel through the <code>{@link android.view.View#dispatchKeyEvent(KeyEvent)
dispatchKeyEvent()}</code> method. As an alternative to capturing key events through your View, you can also receive
all of the events inside your Activity with <code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code>
and <code>{@link android.app.Activity#onKeyUp(int,KeyEvent) onKeyUp()}</code>.</p>
+<p>Also, when thinking about text input for your application, remember that many devices only have software input
+methods. Such methods are not required to be key-based; some may use voice input, handwriting, and so on. Even if
+an input method presents a keyboard-like interface, it will generally <strong>not</strong> trigger the
+<code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code> family of events. You should never
+build a UI that requires specific key presses to be controlled unless you want to limit your application to devices
+with a hardware keyboard. In particular, do not rely on these methods to validate input when the user presses the
+return key; instead, use actions like {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE} to signal the
+input method how your application expects to react, so it may change its UI in a meaningful way. Avoid assumptions
+about how a software input method should work and just trust it to supply already formatted text to your application.</p>
+
<p class="note"><strong>Note:</strong> Android will call event handlers first and then the appropriate default
handlers from the class definition second. As such, returning <em>true</em> from these event listeners will stop
the propagation of the event to other event listeners and will also block the callback to the
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
index b0c1c35..41ec120 100755
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -2623,16 +2623,21 @@
M4OSA_Char* tmpString =
(M4OSA_Char *)videoEditJava_getString(&initialized, pEnv, tempPath,
NULL, M4OSA_NULL);
+ M4OSA_UInt32 length = strlen((const char *)tmpString);
+ // Malloc additional 2 bytes for beginning and tail separator.
+ M4OSA_UInt32 pathLength = length + 2;
+
pContext->initParams.pTempPath = (M4OSA_Char *)
- M4OSA_32bitAlignedMalloc(strlen((const char *)tmpString) + 1, 0x0,
- (M4OSA_Char *)"tempPath");
+ M4OSA_32bitAlignedMalloc(pathLength, 0x0, (M4OSA_Char *)"tempPath");
+
//initialize the first char. so that strcat works.
M4OSA_Char *ptmpChar = (M4OSA_Char*)pContext->initParams.pTempPath;
ptmpChar[0] = 0x00;
strncat((char *)pContext->initParams.pTempPath, (const char *)tmpString,
- (size_t)strlen((const char *)tmpString));
+ length);
strncat((char *)pContext->initParams.pTempPath, (const char *)"/", (size_t)1);
free(tmpString);
+ tmpString = NULL;
pContext->mIsUpdateOverlay = false;
pContext->mOverlayFileName = NULL;
pContext->decoders = NULL;
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 6433cd3..ca29738 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -145,6 +145,6 @@
<string name="notifications_off_title" msgid="8936620513608443224">"通知功能已停用"</string>
<string name="notifications_off_text" msgid="2529001315769385273">"点按此处可重新启用通知功能。"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"屏幕会自动旋转。"</string>
- <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"屏幕锁定为横向浏览模式。"</string>
- <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"屏幕已锁定为纵向浏览模式。"</string>
+ <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"屏幕锁定为横向模式。"</string>
+ <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"屏幕锁定为纵向模式。"</string>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 2786013..26dba67 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -57,7 +57,13 @@
<!-- Show rotation lock button in phone-style notification panel. -->
<bool name="config_showRotationLock">true</bool>
+ <!-- Amount of time to hold off before showing the search panel when the user presses home -->
+ <integer name="config_show_search_delay">200</integer>
+
<!-- Vibration duration for MultiWaveView used in SearchPanelView -->
- <integer translatable="false" name="config_vibration_duration">20</integer>
+ <integer translatable="false" name="config_vibration_duration">0</integer>
+
+ <!-- Vibration duration for MultiWaveView used in SearchPanelView -->
+ <integer translatable="false" name="config_search_panel_view_vibration_duration">20</integer>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
index 060d08e..af88a06 100644
--- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
@@ -16,9 +16,7 @@
package com.android.systemui;
-import android.animation.Animator;
import android.animation.LayoutTransition;
-import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.SearchManager;
import android.content.ActivityNotFoundException;
@@ -26,6 +24,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Vibrator;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Slog;
import android.view.MotionEvent;
@@ -34,12 +35,12 @@
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.widget.FrameLayout;
-
import com.android.internal.widget.multiwaveview.MultiWaveView;
import com.android.internal.widget.multiwaveview.MultiWaveView.OnTriggerListener;
import com.android.systemui.R;
import com.android.systemui.recent.StatusBarTouchProxy;
import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.tablet.StatusBarPanel;
import com.android.systemui.statusbar.tablet.TabletStatusBar;
@@ -49,7 +50,7 @@
private static final int SEARCH_PANEL_HOLD_DURATION = 500;
static final String TAG = "SearchPanelView";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
- private Context mContext;
+ private final Context mContext;
private BaseStatusBar mBar;
private StatusBarTouchProxy mStatusBarTouchProxy;
@@ -77,7 +78,7 @@
Intent intent = getAssistIntent();
return intent == null ? false
: mContext.getPackageManager().queryIntentActivities(intent,
- PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
+ PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
}
private Intent getAssistIntent() {
@@ -106,9 +107,10 @@
private void startAssistActivity() {
// Close Recent Apps if needed
- mBar.animateCollapse();
+ mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL);
// Launch Assist
Intent intent = getAssistIntent();
+ if (intent == null) return;
try {
ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
R.anim.search_launch_enter, R.anim.search_launch_exit);
@@ -142,13 +144,14 @@
case com.android.internal.R.drawable.ic_lockscreen_search:
mWaitingForLaunch = true;
startAssistActivity();
+ vibrate();
postDelayed(new Runnable() {
public void run() {
mWaitingForLaunch = false;
mBar.hideSearchPanel();
}
}, SEARCH_PANEL_HOLD_DURATION);
- break;
+ break;
}
}
@@ -160,7 +163,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mSearchTargetsContainer = (ViewGroup) findViewById(R.id.search_panel_container);
+ mSearchTargetsContainer = findViewById(R.id.search_panel_container);
mStatusBarTouchProxy = (StatusBarTouchProxy) findViewById(R.id.status_bar_touch_proxy);
// TODO: fetch views
mMultiWaveView = (MultiWaveView) findViewById(R.id.multi_wave_view);
@@ -186,7 +189,7 @@
}
}
- private OnPreDrawListener mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
+ private final OnPreDrawListener mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
getViewTreeObserver().removeOnPreDrawListener(this);
mMultiWaveView.resumeAnimations();
@@ -194,10 +197,20 @@
}
};
+ private void vibrate() {
+ Context context = getContext();
+ if (Settings.System.getInt(context.getContentResolver(),
+ Settings.System.HAPTIC_FEEDBACK_ENABLED, 1) != 0) {
+ Resources res = context.getResources();
+ Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+ vibrator.vibrate(res.getInteger(R.integer.config_search_panel_view_vibration_duration));
+ }
+ }
+
public void show(final boolean show, boolean animate) {
if (!show) {
final LayoutTransition transitioner = animate ? createLayoutTransitioner() : null;
- ((ViewGroup)mSearchTargetsContainer).setLayoutTransition(transitioner);
+ ((ViewGroup) mSearchTargetsContainer).setLayoutTransition(transitioner);
}
mShowing = show;
if (show) {
@@ -207,6 +220,7 @@
// right before we are drawn
mMultiWaveView.suspendAnimations();
getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
+ vibrate();
}
setFocusable(true);
setFocusableInTouchMode(true);
@@ -219,7 +233,7 @@
public void hide(boolean animate) {
if (mBar != null) {
// This will indirectly cause show(false, ...) to get called
- mBar.animateCollapse();
+ mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
} else {
setVisibility(View.INVISIBLE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 4351e95..587bfe8 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -58,6 +58,7 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.tablet.StatusBarPanel;
import com.android.systemui.statusbar.tablet.TabletStatusBar;
@@ -368,7 +369,7 @@
}
if (mBar != null) {
// This will indirectly cause show(false, ...) to get called
- mBar.animateCollapse();
+ mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
}
}
@@ -822,7 +823,7 @@
if (viewHolder != null) {
final TaskDescription ad = viewHolder.taskDescription;
startApplicationDetailsActivity(ad.packageName);
- mBar.animateCollapse();
+ mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
} else {
throw new IllegalStateException("Oops, no tag on view " + selectedView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index a352748..f088e0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -253,7 +253,7 @@
mContext.startActivity(intent);
}
- protected View.OnLongClickListener getNotificationLongClicker() {
+ protected View.OnLongClickListener getNotificationLongClicker() {
return new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
@@ -268,7 +268,7 @@
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.notification_inspect_item) {
startApplicationDetailsActivity(packageNameF);
- animateCollapse();
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
} else {
return false;
}
@@ -618,7 +618,7 @@
}
// close the shade if it was open
- animateCollapse();
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
visibilityChanged(false);
// If this click was on the intruder alert, hide that instead
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 4209354..a00d95a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -66,6 +66,13 @@
private static final int MSG_SET_NAVIGATION_ICON_HINTS = 14 << MSG_SHIFT;
+ public static final int FLAG_EXCLUDE_NONE = 0;
+ public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
+ public static final int FLAG_EXCLUDE_RECENTS_PANEL = 1 << 1;
+ public static final int FLAG_EXCLUDE_NOTIFICATION_PANEL = 1 << 2;
+ public static final int FLAG_EXCLUDE_INPUT_METHODS_PANEL = 1 << 3;
+ public static final int FLAG_EXCLUDE_COMPAT_MODE_PANEL = 1 << 4;
+
private StatusBarIconList mList;
private Callbacks mCallbacks;
private Handler mHandler = new H();
@@ -88,7 +95,7 @@
public void removeNotification(IBinder key);
public void disable(int state);
public void animateExpand();
- public void animateCollapse();
+ public void animateCollapse(int flags);
public void setSystemUiVisibility(int vis, int mask);
public void topAppWindowChanged(boolean visible);
public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
@@ -161,9 +168,13 @@
}
public void animateCollapse() {
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
+ }
+
+ public void animateCollapse(int flags) {
synchronized (mList) {
mHandler.removeMessages(MSG_SET_VISIBILITY);
- mHandler.obtainMessage(MSG_SET_VISIBILITY, OP_COLLAPSE, 0, null).sendToTarget();
+ mHandler.obtainMessage(MSG_SET_VISIBILITY, OP_COLLAPSE, flags, null).sendToTarget();
}
}
@@ -277,7 +288,7 @@
if (msg.arg1 == OP_EXPAND) {
mCallbacks.animateExpand();
} else {
- mCallbacks.animateCollapse();
+ mCallbacks.animateCollapse(msg.arg2);
}
break;
case MSG_SET_SYSTEMUI_VISIBILITY:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 344411b..3a50560 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -76,6 +76,7 @@
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.RotationToggle;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
@@ -529,16 +530,29 @@
}
};
+ private int mShowSearchHoldoff = 0;
+ private Runnable mShowSearchPanel = new Runnable() {
+ public void run() {
+ showSearchPanel();
+ }
+ };
+
View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- if (!shouldDisableNavbarGestures()) {
- showSearchPanel();
- }
- break;
- }
- return false;
+ case MotionEvent.ACTION_DOWN:
+ if (!shouldDisableNavbarGestures()) {
+ mHandler.removeCallbacks(mShowSearchPanel);
+ mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff);
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mHandler.removeCallbacks(mShowSearchPanel);
+ break;
+ }
+ return false;
}
};
@@ -733,6 +747,8 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
updateRecentsPanel();
+ mShowSearchHoldoff = mContext.getResources().getInteger(
+ R.integer.config_show_search_delay);
}
private void loadNotificationShade() {
@@ -1057,29 +1073,33 @@
}
public void animateCollapse() {
- animateCollapse(false);
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
}
- public void animateCollapse(boolean excludeRecents) {
- animateCollapse(excludeRecents, 1.0f);
+ public void animateCollapse(int flags) {
+ animateCollapse(flags, 1.0f);
}
- public void animateCollapse(boolean excludeRecents, float velocityMultiplier) {
+ public void animateCollapse(int flags, float velocityMultiplier) {
if (SPEW) {
Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
+ " mExpandedVisible=" + mExpandedVisible
+ " mExpanded=" + mExpanded
+ " mAnimating=" + mAnimating
+ " mAnimY=" + mAnimY
- + " mAnimVel=" + mAnimVel);
+ + " mAnimVel=" + mAnimVel
+ + " flags=" + flags);
}
- if (!excludeRecents) {
+ if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
}
- mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
- mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
+
+ if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) {
+ mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
+ mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
+ }
if (!mExpandedVisible) {
return;
@@ -1941,7 +1961,7 @@
}
}
if (snapshot.isEmpty()) {
- animateCollapse(false);
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
return;
}
new Thread(new Runnable() {
@@ -1989,7 +2009,7 @@
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
- animateCollapse(false);
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
}
}, totalDelay + 225);
}
@@ -2016,14 +2036,14 @@
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
|| Intent.ACTION_SCREEN_OFF.equals(action)) {
- boolean excludeRecents = false;
+ int flags = CommandQueue.FLAG_EXCLUDE_NONE;
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
String reason = intent.getStringExtra("reason");
- if (reason != null) {
- excludeRecents = reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS);
+ if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
+ flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
}
}
- animateCollapse(excludeRecents);
+ animateCollapse(flags);
}
else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
updateResources();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index c0ac50e..8df9b85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -67,6 +67,7 @@
import com.android.systemui.recent.RecentTasksLoader;
import com.android.systemui.recent.RecentsPanelView;
import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DoNotDisturb;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.SignalClusterView;
@@ -186,16 +187,30 @@
private int mNavigationIconHints = 0;
+ private int mShowSearchHoldoff = 0;
+
public Context getContext() { return mContext; }
+ private Runnable mShowSearchPanel = new Runnable() {
+ public void run() {
+ showSearchPanel();
+ }
+ };
+
private View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (!shouldDisableNavbarGestures()) {
- showSearchPanel();
+ mHandler.removeCallbacks(mShowSearchPanel);
+ mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff);
}
break;
+
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mHandler.removeCallbacks(mShowSearchPanel);
+ break;
}
return false;
}
@@ -387,6 +402,8 @@
WindowManagerImpl.getDefault().updateViewLayout(mNotificationPanel,
mNotificationPanelParams);
mRecentsPanel.updateValuesFromResources();
+ mShowSearchHoldoff = mContext.getResources().getInteger(
+ R.integer.config_show_search_delay);
}
protected void loadDimens() {
@@ -1001,22 +1018,31 @@
}
public void animateCollapse() {
- animateCollapse(false);
+ animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
}
- private void animateCollapse(boolean excludeRecents) {
- mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PANEL);
- mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PANEL);
- if (!excludeRecents) {
+ public void animateCollapse(int flags) {
+ if ((flags & CommandQueue.FLAG_EXCLUDE_NOTIFICATION_PANEL) == 0) {
+ mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PANEL);
+ mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PANEL);
+ }
+ if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
}
- mHandler.removeMessages(MSG_CLOSE_INPUT_METHODS_PANEL);
- mHandler.sendEmptyMessage(MSG_CLOSE_INPUT_METHODS_PANEL);
- mHandler.removeMessages(MSG_CLOSE_COMPAT_MODE_PANEL);
- mHandler.sendEmptyMessage(MSG_CLOSE_COMPAT_MODE_PANEL);
- mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
- mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
+ if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) {
+ mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
+ mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
+ }
+ if ((flags & CommandQueue.FLAG_EXCLUDE_INPUT_METHODS_PANEL) == 0) {
+ mHandler.removeMessages(MSG_CLOSE_INPUT_METHODS_PANEL);
+ mHandler.sendEmptyMessage(MSG_CLOSE_INPUT_METHODS_PANEL);
+ }
+ if ((flags & CommandQueue.FLAG_EXCLUDE_COMPAT_MODE_PANEL) == 0) {
+ mHandler.removeMessages(MSG_CLOSE_COMPAT_MODE_PANEL);
+ mHandler.sendEmptyMessage(MSG_CLOSE_COMPAT_MODE_PANEL);
+ }
+
}
@Override // CommandQueue
@@ -1594,11 +1620,11 @@
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
|| Intent.ACTION_SCREEN_OFF.equals(action)) {
- boolean excludeRecents = false;
+ int flags = CommandQueue.FLAG_EXCLUDE_NONE;
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
String reason = intent.getStringExtra("reason");
- if (reason != null) {
- excludeRecents = reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS);
+ if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
+ flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
}
}
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
@@ -1607,9 +1633,9 @@
// TODO: hide other things, like the notification tray,
// with no animation as well
mRecentsPanel.show(false, false);
- excludeRecents = true;
+ flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
}
- animateCollapse(excludeRecents);
+ animateCollapse(flags);
}
}
};
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 1e707b2..985249d 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -26,7 +26,11 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.Signature;
import android.content.res.Resources;
import android.database.Cursor;
import android.location.Address;
@@ -123,8 +127,9 @@
private static boolean sProvidersLoaded = false;
private final Context mContext;
- private final String mNetworkLocationProviderPackageName;
- private final String mGeocodeProviderPackageName;
+ private PackageManager mPackageManager; // final after initialize()
+ private String mNetworkLocationProviderPackageName; // only used on handler thread
+ private String mGeocodeProviderPackageName; // only used on handler thread
private GeocoderProxy mGeocodeProvider;
private IGpsStatusProvider mGpsStatusProvider;
private INetInitiatedListener mNetInitiatedListener;
@@ -490,36 +495,91 @@
addProvider(passiveProvider);
mEnabledProviders.add(passiveProvider.getName());
- // initialize external network location and geocoder services
- PackageManager pm = mContext.getPackageManager();
- if (mNetworkLocationProviderPackageName != null &&
- pm.resolveService(new Intent(mNetworkLocationProviderPackageName), 0) != null) {
- mNetworkLocationProvider =
- new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER,
- mNetworkLocationProviderPackageName, mLocationHandler);
-
- addProvider(mNetworkLocationProvider);
+ // initialize external network location and geocoder services.
+ // The initial value of mNetworkLocationProviderPackageName and
+ // mGeocodeProviderPackageName is just used to determine what
+ // signatures future mNetworkLocationProviderPackageName and
+ // mGeocodeProviderPackageName packages must have. So alternate
+ // providers can be installed under a different package name
+ // so long as they have the same signature as the original
+ // provider packages.
+ if (mNetworkLocationProviderPackageName != null) {
+ String packageName = findBestPackage(LocationProviderProxy.SERVICE_ACTION,
+ mNetworkLocationProviderPackageName);
+ if (packageName != null) {
+ mNetworkLocationProvider = new LocationProviderProxy(mContext,
+ LocationManager.NETWORK_PROVIDER,
+ packageName, mLocationHandler);
+ mNetworkLocationProviderPackageName = packageName;
+ addProvider(mNetworkLocationProvider);
+ }
}
-
- if (mGeocodeProviderPackageName != null &&
- pm.resolveService(new Intent(mGeocodeProviderPackageName), 0) != null) {
- mGeocodeProvider = new GeocoderProxy(mContext, mGeocodeProviderPackageName);
+ if (mGeocodeProviderPackageName != null) {
+ String packageName = findBestPackage(GeocoderProxy.SERVICE_ACTION,
+ mGeocodeProviderPackageName);
+ if (packageName != null) {
+ mGeocodeProvider = new GeocoderProxy(mContext, packageName);
+ mGeocodeProviderPackageName = packageName;
+ }
}
updateProvidersLocked();
}
/**
+ * Pick the best (network location provider or geocode provider) package.
+ * The best package:
+ * - implements serviceIntentName
+ * - has signatures that match that of sigPackageName
+ * - has the highest version value in a meta-data field in the service component
+ */
+ String findBestPackage(String serviceIntentName, String sigPackageName) {
+ Intent intent = new Intent(serviceIntentName);
+ List<ResolveInfo> infos = mPackageManager.queryIntentServices(intent,
+ PackageManager.GET_META_DATA);
+ if (infos == null) return null;
+
+ int bestVersion = Integer.MIN_VALUE;
+ String bestPackage = null;
+ for (ResolveInfo info : infos) {
+ String packageName = info.serviceInfo.packageName;
+ // check signature
+ if (mPackageManager.checkSignatures(packageName, sigPackageName) !=
+ PackageManager.SIGNATURE_MATCH) {
+ Slog.w(TAG, packageName + " implements " + serviceIntentName +
+ " but its signatures don't match those in " + sigPackageName +
+ ", ignoring");
+ continue;
+ }
+ // read version
+ int version = 0;
+ if (info.serviceInfo.metaData != null) {
+ version = info.serviceInfo.metaData.getInt("version", 0);
+ }
+ if (LOCAL_LOGV) Slog.v(TAG, packageName + " implements " + serviceIntentName +
+ " with version " + version);
+ if (version > bestVersion) {
+ bestVersion = version;
+ bestPackage = packageName;
+ }
+ }
+
+ return bestPackage;
+ }
+
+ /**
* @param context the context that the LocationManagerService runs in
*/
public LocationManagerService(Context context) {
super();
mContext = context;
Resources resources = context.getResources();
+
mNetworkLocationProviderPackageName = resources.getString(
- com.android.internal.R.string.config_networkLocationProvider);
+ com.android.internal.R.string.config_networkLocationProviderPackageName);
mGeocodeProviderPackageName = resources.getString(
- com.android.internal.R.string.config_geocodeProvider);
+ com.android.internal.R.string.config_geocodeProviderPackageName);
+
mPackageMonitor.register(context, null, true);
if (LOCAL_LOGV) {
@@ -537,6 +597,7 @@
// Create a wake lock, needs to be done before calling loadProviders() below
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
+ mPackageManager = mContext.getPackageManager();
// Load providers
loadProviders();
@@ -1886,16 +1947,33 @@
}
} else if (msg.what == MESSAGE_PACKAGE_UPDATED) {
String packageName = (String) msg.obj;
- String packageDot = packageName + ".";
- // reconnect to external providers after their packages have been updated
- if (mNetworkLocationProvider != null &&
- mNetworkLocationProviderPackageName.startsWith(packageDot)) {
- mNetworkLocationProvider.reconnect();
+ // reconnect to external providers if there is a better package
+ if (mNetworkLocationProviderPackageName != null &&
+ mPackageManager.resolveService(
+ new Intent(LocationProviderProxy.SERVICE_ACTION)
+ .setPackage(packageName), 0) != null) {
+ // package implements service, perform full check
+ String bestPackage = findBestPackage(
+ LocationProviderProxy.SERVICE_ACTION,
+ mNetworkLocationProviderPackageName);
+ if (packageName.equals(bestPackage)) {
+ mNetworkLocationProvider.reconnect(bestPackage);
+ mNetworkLocationProviderPackageName = packageName;
+ }
}
- if (mGeocodeProvider != null &&
- mGeocodeProviderPackageName.startsWith(packageDot)) {
- mGeocodeProvider.reconnect();
+ if (mGeocodeProviderPackageName != null &&
+ mPackageManager.resolveService(
+ new Intent(GeocoderProxy.SERVICE_ACTION)
+ .setPackage(packageName), 0) != null) {
+ // package implements service, perform full check
+ String bestPackage = findBestPackage(
+ GeocoderProxy.SERVICE_ACTION,
+ mGeocodeProviderPackageName);
+ if (packageName.equals(bestPackage)) {
+ mGeocodeProvider.reconnect(bestPackage);
+ mGeocodeProviderPackageName = packageName;
+ }
}
}
} catch (Exception e) {
@@ -2004,6 +2082,11 @@
// Called by main thread; divert work to LocationWorker.
Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
}
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ // Called by main thread; divert work to LocationWorker.
+ Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
+ }
};
// Wake locks
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index c7b336f..c74dd00 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -198,7 +198,7 @@
}
// TODO: Respect allowImplicitlySelectedSubtype
- // TODO: Save SpellCheckerSubtype by supported languages.
+ // TODO: Save SpellCheckerSubtype by supported languages by looking at "locale".
@Override
public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
String locale, boolean allowImplicitlySelectedSubtype) {
@@ -250,10 +250,10 @@
for (int i = 0; i < sci.getSubtypeCount(); ++i) {
final SpellCheckerSubtype scs = sci.getSubtypeAt(i);
if (hashCode == 0) {
- if (candidateLocale.equals(locale)) {
+ final String scsLocale = scs.getLocale();
+ if (candidateLocale.equals(scsLocale)) {
return scs;
} else if (candidate == null) {
- final String scsLocale = scs.getLocale();
if (candidateLocale.length() >= 2 && scsLocale.length() >= 2
&& candidateLocale.startsWith(scsLocale)) {
// Fall back to the applicable language
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 6464d7f..9d9b5b8 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -62,6 +62,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.IContentProvider;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
@@ -1810,12 +1811,11 @@
}
}
}
- if (app.conProviders.size() > 0) {
- for (ContentProviderRecord cpr : app.conProviders.keySet()) {
- if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) {
- updateLruProcessInternalLocked(cpr.proc, oomAdj,
- updateActivityTime, i+1);
- }
+ for (int j=app.conProviders.size()-1; j>=0; j--) {
+ ContentProviderRecord cpr = app.conProviders.get(j).provider;
+ if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) {
+ updateLruProcessInternalLocked(cpr.proc, oomAdj,
+ updateActivityTime, i+1);
}
}
@@ -3742,7 +3742,7 @@
N = providers.size();
for (i=0; i<N; i++) {
- removeDyingProviderLocked(null, providers.get(i));
+ removeDyingProviderLocked(null, providers.get(i), true);
}
if (doit) {
@@ -6058,53 +6058,72 @@
return msg;
}
- boolean incProviderCount(ProcessRecord r, final ContentProviderRecord cpr,
- IBinder externalProcessToken) {
+ ContentProviderConnection incProviderCountLocked(ProcessRecord r,
+ final ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
if (r != null) {
- Integer cnt = r.conProviders.get(cpr);
- if (DEBUG_PROVIDER) Slog.v(TAG,
- "Adding provider requested by "
- + r.processName + " from process "
- + cpr.info.processName + ": " + cpr.name.flattenToShortString()
- + " cnt=" + (cnt == null ? 1 : cnt));
- if (cnt == null) {
- cpr.clients.add(r);
- r.conProviders.put(cpr, new Integer(1));
- return true;
- } else {
- r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
+ for (int i=0; i<r.conProviders.size(); i++) {
+ ContentProviderConnection conn = r.conProviders.get(i);
+ if (conn.provider == cpr) {
+ if (DEBUG_PROVIDER) Slog.v(TAG,
+ "Adding provider requested by "
+ + r.processName + " from process "
+ + cpr.info.processName + ": " + cpr.name.flattenToShortString()
+ + " scnt=" + conn.stableCount + " uscnt=" + conn.unstableCount);
+ if (stable) {
+ conn.stableCount++;
+ conn.numStableIncs++;
+ } else {
+ conn.unstableCount++;
+ conn.numUnstableIncs++;
+ }
+ return conn;
+ }
}
- } else {
- cpr.addExternalProcessHandleLocked(externalProcessToken);
+ ContentProviderConnection conn = new ContentProviderConnection(cpr, r);
+ if (stable) {
+ conn.stableCount = 1;
+ conn.numStableIncs = 1;
+ } else {
+ conn.unstableCount = 1;
+ conn.numUnstableIncs = 1;
+ }
+ cpr.connections.add(conn);
+ r.conProviders.add(conn);
+ return conn;
}
- return false;
+ cpr.addExternalProcessHandleLocked(externalProcessToken);
+ return null;
}
- boolean decProviderCount(ProcessRecord r, final ContentProviderRecord cpr,
- IBinder externalProcessToken) {
- if (r != null) {
- Integer cnt = r.conProviders.get(cpr);
+ boolean decProviderCountLocked(ContentProviderConnection conn,
+ ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
+ if (conn != null) {
+ cpr = conn.provider;
if (DEBUG_PROVIDER) Slog.v(TAG,
"Removing provider requested by "
- + r.processName + " from process "
+ + conn.client.processName + " from process "
+ cpr.info.processName + ": " + cpr.name.flattenToShortString()
- + " cnt=" + cnt);
- if (cnt == null || cnt.intValue() <= 1) {
- cpr.clients.remove(r);
- r.conProviders.remove(cpr);
- return true;
+ + " scnt=" + conn.stableCount + " uscnt=" + conn.unstableCount);
+ if (stable) {
+ conn.stableCount--;
} else {
- r.conProviders.put(cpr, new Integer(cnt.intValue()-1));
+ conn.unstableCount--;
}
- } else {
- cpr.removeExternalProcessHandleLocked(externalProcessToken);
+ if (conn.stableCount == 0 && conn.unstableCount == 0) {
+ cpr.connections.remove(conn);
+ conn.client.conProviders.remove(conn);
+ return true;
+ }
+ return false;
}
+ cpr.removeExternalProcessHandleLocked(externalProcessToken);
return false;
}
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
- String name, IBinder token) {
+ String name, IBinder token, boolean stable) {
ContentProviderRecord cpr;
+ ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
@@ -6135,20 +6154,19 @@
// of being published... but it is also allowed to run
// in the caller's process, so don't make a connection
// and just let the caller instantiate its own instance.
- if (cpr.provider != null) {
- // don't give caller the provider object, it needs
- // to make its own.
- cpr = new ContentProviderRecord(cpr);
- }
- return cpr;
+ ContentProviderHolder holder = cpr.newHolder(null);
+ // don't give caller the provider object, it needs
+ // to make its own.
+ holder.provider = null;
+ return holder;
}
final long origId = Binder.clearCallingIdentity();
// In this case the provider instance already exists, so we can
// return it right away.
- final boolean countChanged = incProviderCount(r, cpr, token);
- if (countChanged) {
+ conn = incProviderCountLocked(r, cpr, token, stable);
+ if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
// If this is a perceptible app accessing the provider,
// make sure to count it as being accessed and thus
@@ -6181,7 +6199,7 @@
Slog.i(TAG,
"Existing provider " + cpr.name.flattenToShortString()
+ " is crashing; detaching " + r);
- boolean lastRef = decProviderCount(r, cpr, token);
+ boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
appDiedLocked(cpr.proc, cpr.proc.pid, cpr.proc.thread);
if (!lastRef) {
// This wasn't the last ref our process had on
@@ -6189,6 +6207,7 @@
return null;
}
providerRunning = false;
+ conn = null;
}
}
@@ -6251,7 +6270,7 @@
// info and allow the caller to instantiate it. Only do
// this if the provider is the same user as the caller's
// process, or can run as root (so can be in any process).
- return cpr;
+ return cpr.newHolder(null);
}
if (DEBUG_PROVIDER) {
@@ -6312,7 +6331,10 @@
}
mProviderMap.putProviderByName(name, cpr);
- incProviderCount(r, cpr, token);
+ conn = incProviderCountLocked(r, cpr, token, stable);
+ if (conn != null) {
+ conn.waiting = true;
+ }
}
}
@@ -6334,16 +6356,23 @@
Slog.v(TAG_MU, "Waiting to start provider " + cpr + " launchingApp="
+ cpr.launchingApp);
}
+ if (conn != null) {
+ conn.waiting = true;
+ }
cpr.wait();
} catch (InterruptedException ex) {
+ } finally {
+ if (conn != null) {
+ conn.waiting = false;
+ }
}
}
}
- return cpr;
+ return cpr != null ? cpr.newHolder(conn) : null;
}
public final ContentProviderHolder getContentProvider(
- IApplicationThread caller, String name) {
+ IApplicationThread caller, String name, boolean stable) {
enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
@@ -6352,7 +6381,7 @@
throw new SecurityException(msg);
}
- return getContentProviderImpl(caller, name, null);
+ return getContentProviderImpl(caller, name, null, stable);
}
public ContentProviderHolder getContentProviderExternal(String name, IBinder token) {
@@ -6362,45 +6391,30 @@
}
private ContentProviderHolder getContentProviderExternalUnchecked(String name,IBinder token) {
- return getContentProviderImpl(null, name, token);
+ return getContentProviderImpl(null, name, token, true);
}
/**
* Drop a content provider from a ProcessRecord's bookkeeping
* @param cpr
*/
- public void removeContentProvider(IApplicationThread caller, String name) {
+ public void removeContentProvider(IBinder connection, boolean stable) {
enforceNotIsolatedCaller("removeContentProvider");
synchronized (this) {
- int userId = UserId.getUserId(Binder.getCallingUid());
- ContentProviderRecord cpr = mProviderMap.getProviderByName(name, userId);
- if(cpr == null) {
- // remove from mProvidersByClass
- if (DEBUG_PROVIDER) Slog.v(TAG, name +
- " provider not found in providers list");
- return;
+ ContentProviderConnection conn;
+ try {
+ conn = (ContentProviderConnection)connection;
+ } catch (ClassCastException e) {
+ String msg ="removeContentProvider: " + connection
+ + " not a ContentProviderConnection";
+ Slog.w(TAG, msg);
+ throw new IllegalArgumentException(msg);
}
- final ProcessRecord r = getRecordForAppLocked(caller);
- if (r == null) {
- throw new SecurityException(
- "Unable to find app for caller " + caller +
- " when removing content provider " + name);
+ if (conn == null) {
+ throw new NullPointerException("connection is null");
}
- //update content provider record entry info
- ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name);
- ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId);
- if (DEBUG_PROVIDER) Slog.v(TAG, "Removing provider requested by "
- + r.info.processName + " from process "
- + localCpr.appInfo.processName);
- if (localCpr.launchingApp == r) {
- //should not happen. taken care of as a local provider
- Slog.w(TAG, "removeContentProvider called on local provider: "
- + cpr.info.name + " in process " + r.processName);
- return;
- } else {
- if (decProviderCount(r, localCpr, null)) {
- updateOomAdjLocked();
- }
+ if (decProviderCountLocked(conn, null, null, stable)) {
+ updateOomAdjLocked();
}
}
}
@@ -6447,7 +6461,7 @@
}
enforceNotIsolatedCaller("publishContentProviders");
- synchronized(this) {
+ synchronized (this) {
final ProcessRecord r = getRecordForAppLocked(caller);
if (DEBUG_MU)
Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
@@ -6499,6 +6513,103 @@
}
}
+ public boolean refContentProvider(IBinder connection, int stable, int unstable) {
+ ContentProviderConnection conn;
+ try {
+ conn = (ContentProviderConnection)connection;
+ } catch (ClassCastException e) {
+ String msg ="refContentProvider: " + connection
+ + " not a ContentProviderConnection";
+ Slog.w(TAG, msg);
+ throw new IllegalArgumentException(msg);
+ }
+ if (conn == null) {
+ throw new NullPointerException("connection is null");
+ }
+
+ synchronized (this) {
+ if (stable > 0) {
+ conn.numStableIncs += stable;
+ }
+ stable = conn.stableCount + stable;
+ if (stable < 0) {
+ throw new IllegalStateException("stableCount < 0: " + stable);
+ }
+
+ if (unstable > 0) {
+ conn.numUnstableIncs += unstable;
+ }
+ unstable = conn.unstableCount + unstable;
+ if (unstable < 0) {
+ throw new IllegalStateException("unstableCount < 0: " + unstable);
+ }
+
+ if ((stable+unstable) <= 0) {
+ throw new IllegalStateException("ref counts can't go to zero here: stable="
+ + stable + " unstable=" + unstable);
+ }
+ conn.stableCount = stable;
+ conn.unstableCount = unstable;
+ return !conn.dead;
+ }
+ }
+
+ public void unstableProviderDied(IBinder connection) {
+ ContentProviderConnection conn;
+ try {
+ conn = (ContentProviderConnection)connection;
+ } catch (ClassCastException e) {
+ String msg ="refContentProvider: " + connection
+ + " not a ContentProviderConnection";
+ Slog.w(TAG, msg);
+ throw new IllegalArgumentException(msg);
+ }
+ if (conn == null) {
+ throw new NullPointerException("connection is null");
+ }
+
+ // Safely retrieve the content provider associated with the connection.
+ IContentProvider provider;
+ synchronized (this) {
+ provider = conn.provider.provider;
+ }
+
+ if (provider == null) {
+ // Um, yeah, we're way ahead of you.
+ return;
+ }
+
+ // Make sure the caller is being honest with us.
+ if (provider.asBinder().pingBinder()) {
+ // Er, no, still looks good to us.
+ synchronized (this) {
+ Slog.w(TAG, "unstableProviderDied: caller " + Binder.getCallingUid()
+ + " says " + conn + " died, but we don't agree");
+ return;
+ }
+ }
+
+ // Well look at that! It's dead!
+ synchronized (this) {
+ if (conn.provider.provider != provider) {
+ // But something changed... good enough.
+ return;
+ }
+
+ ProcessRecord proc = conn.provider.proc;
+ if (proc == null || proc.thread == null) {
+ // Seems like the process is already cleaned up.
+ return;
+ }
+
+ // As far as we're concerned, this is just like receiving a
+ // death notification... just a bit prematurely.
+ Slog.i(TAG, "Process " + proc.processName + " (pid " + proc.pid
+ + ") early provider death");
+ appDiedLocked(proc, proc.pid, proc.thread);
+ }
+ }
+
public static final void installSystemProviders() {
List<ProviderInfo> providers;
synchronized (mSelf) {
@@ -10515,36 +10626,62 @@
app.executingServices.clear();
}
- private final void removeDyingProviderLocked(ProcessRecord proc,
- ContentProviderRecord cpr) {
- synchronized (cpr) {
- cpr.launchingApp = null;
- cpr.notifyAll();
- }
-
- mProviderMap.removeProviderByClass(cpr.name, UserId.getUserId(cpr.uid));
- String names[] = cpr.info.authority.split(";");
- for (int j = 0; j < names.length; j++) {
- mProviderMap.removeProviderByName(names[j], UserId.getUserId(cpr.uid));
- }
-
- Iterator<ProcessRecord> cit = cpr.clients.iterator();
- while (cit.hasNext()) {
- ProcessRecord capp = cit.next();
- if (!capp.persistent && capp.thread != null
- && capp.pid != 0
- && capp.pid != MY_PID) {
- Slog.i(TAG, "Kill " + capp.processName
- + " (pid " + capp.pid + "): provider " + cpr.info.name
- + " in dying process " + (proc != null ? proc.processName : "??"));
- EventLog.writeEvent(EventLogTags.AM_KILL, capp.pid,
- capp.processName, capp.setAdj, "dying provider "
- + cpr.name.toShortString());
- Process.killProcessQuiet(capp.pid);
+ private final boolean removeDyingProviderLocked(ProcessRecord proc,
+ ContentProviderRecord cpr, boolean always) {
+ final boolean inLaunching = mLaunchingProviders.contains(cpr);
+
+ if (!inLaunching || always) {
+ synchronized (cpr) {
+ cpr.launchingApp = null;
+ cpr.notifyAll();
+ }
+ mProviderMap.removeProviderByClass(cpr.name, UserId.getUserId(cpr.uid));
+ String names[] = cpr.info.authority.split(";");
+ for (int j = 0; j < names.length; j++) {
+ mProviderMap.removeProviderByName(names[j], UserId.getUserId(cpr.uid));
}
}
-
- mLaunchingProviders.remove(cpr);
+
+ for (int i=0; i<cpr.connections.size(); i++) {
+ ContentProviderConnection conn = cpr.connections.get(i);
+ if (conn.waiting) {
+ // If this connection is waiting for the provider, then we don't
+ // need to mess with its process unless we are always removing
+ // or for some reason the provider is not currently launching.
+ if (inLaunching && !always) {
+ continue;
+ }
+ }
+ ProcessRecord capp = conn.client;
+ conn.dead = true;
+ if (conn.stableCount > 0) {
+ if (!capp.persistent && capp.thread != null
+ && capp.pid != 0
+ && capp.pid != MY_PID) {
+ Slog.i(TAG, "Kill " + capp.processName
+ + " (pid " + capp.pid + "): provider " + cpr.info.name
+ + " in dying process " + (proc != null ? proc.processName : "??"));
+ EventLog.writeEvent(EventLogTags.AM_KILL, capp.pid,
+ capp.processName, capp.setAdj, "dying provider "
+ + cpr.name.toShortString());
+ Process.killProcessQuiet(capp.pid);
+ }
+ } else if (capp.thread != null && conn.provider.provider != null) {
+ try {
+ capp.thread.unstableProviderDied(conn.provider.provider.asBinder());
+ } catch (RemoteException e) {
+ }
+ // In the protocol here, we don't expect the client to correctly
+ // clean up this connection, we'll just remove it.
+ cpr.connections.remove(i);
+ conn.client.conProviders.remove(conn);
+ }
+ }
+
+ if (inLaunching && always) {
+ mLaunchingProviders.remove(cpr);
+ }
+ return inLaunching;
}
/**
@@ -10590,34 +10727,21 @@
boolean restart = false;
- int NL = mLaunchingProviders.size();
-
// Remove published content providers.
if (!app.pubProviders.isEmpty()) {
Iterator<ContentProviderRecord> it = app.pubProviders.values().iterator();
while (it.hasNext()) {
ContentProviderRecord cpr = it.next();
+
+ final boolean always = app.bad || !allowRestart;
+ if (removeDyingProviderLocked(app, cpr, always) || always) {
+ // We left the provider in the launching list, need to
+ // restart it.
+ restart = true;
+ }
+
cpr.provider = null;
cpr.proc = null;
-
- // See if someone is waiting for this provider... in which
- // case we don't remove it, but just let it restart.
- int i = 0;
- if (!app.bad && allowRestart) {
- for (; i<NL; i++) {
- if (mLaunchingProviders.get(i) == cpr) {
- restart = true;
- break;
- }
- }
- } else {
- i = NL;
- }
-
- if (i >= NL) {
- removeDyingProviderLocked(app, cpr);
- NL = mLaunchingProviders.size();
- }
}
app.pubProviders.clear();
}
@@ -10629,10 +10753,9 @@
// Unregister from connected content providers.
if (!app.conProviders.isEmpty()) {
- Iterator it = app.conProviders.keySet().iterator();
- while (it.hasNext()) {
- ContentProviderRecord cpr = (ContentProviderRecord)it.next();
- cpr.clients.remove(app);
+ for (int i=0; i<app.conProviders.size(); i++) {
+ ContentProviderConnection conn = app.conProviders.get(i);
+ conn.provider.connections.remove(conn);
}
app.conProviders.clear();
}
@@ -10643,10 +10766,10 @@
// XXX Commented out for now. Trying to figure out a way to reproduce
// the actual situation to identify what is actually going on.
if (false) {
- for (int i=0; i<NL; i++) {
+ for (int i=0; i<mLaunchingProviders.size(); i++) {
ContentProviderRecord cpr = (ContentProviderRecord)
mLaunchingProviders.get(i);
- if (cpr.clients.size() <= 0 && !cpr.hasExternalProcessHandles()) {
+ if (cpr.connections.size() <= 0 && !cpr.hasExternalProcessHandles()) {
synchronized (cpr) {
cpr.launchingApp = null;
cpr.notifyAll();
@@ -10743,7 +10866,7 @@
if (!alwaysBad && !app.bad) {
restart = true;
} else {
- removeDyingProviderLocked(app, cpr);
+ removeDyingProviderLocked(app, cpr, true);
NL = mLaunchingProviders.size();
}
}
@@ -13948,48 +14071,49 @@
while (jt.hasNext() && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
ContentProviderRecord cpr = jt.next();
- if (cpr.clients.size() != 0) {
- Iterator<ProcessRecord> kt = cpr.clients.iterator();
- while (kt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
- ProcessRecord client = kt.next();
- if (client == app) {
- // Being our own client is not interesting.
- continue;
+ for (int i = cpr.connections.size()-1;
+ i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE);
+ i--) {
+ ContentProviderConnection conn = cpr.connections.get(i);
+ ProcessRecord client = conn.client;
+ if (client == app) {
+ // Being our own client is not interesting.
+ continue;
+ }
+ int myHiddenAdj = hiddenAdj;
+ if (myHiddenAdj > client.hiddenAdj) {
+ if (client.hiddenAdj > ProcessList.FOREGROUND_APP_ADJ) {
+ myHiddenAdj = client.hiddenAdj;
+ } else {
+ myHiddenAdj = ProcessList.FOREGROUND_APP_ADJ;
}
- int myHiddenAdj = hiddenAdj;
- if (myHiddenAdj > client.hiddenAdj) {
- if (client.hiddenAdj > ProcessList.FOREGROUND_APP_ADJ) {
- myHiddenAdj = client.hiddenAdj;
- } else {
- myHiddenAdj = ProcessList.FOREGROUND_APP_ADJ;
- }
+ }
+ int clientAdj = computeOomAdjLocked(
+ client, myHiddenAdj, TOP_APP, true, doingAll);
+ if (adj > clientAdj) {
+ if (app.hasShownUi && app != mHomeProcess
+ && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+ app.adjType = "bg-ui-provider";
+ } else {
+ adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
+ ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
+ app.adjType = "provider";
}
- int clientAdj = computeOomAdjLocked(
- client, myHiddenAdj, TOP_APP, true, doingAll);
- if (adj > clientAdj) {
- if (app.hasShownUi && app != mHomeProcess
- && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- app.adjType = "bg-ui-provider";
- } else {
- adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
- ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
- app.adjType = "provider";
- }
- if (!client.hidden) {
- app.hidden = false;
- }
- if (client.keeping) {
- app.keeping = true;
- }
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_PROVIDER_IN_USE;
- app.adjSource = client;
- app.adjSourceOom = clientAdj;
- app.adjTarget = cpr.name;
+ if (!client.hidden) {
+ app.hidden = false;
}
- if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ if (client.keeping) {
+ app.keeping = true;
}
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_PROVIDER_IN_USE;
+ app.adjSource = client;
+ app.adjSourceOom = clientAdj;
+ app.adjTarget = cpr.name;
+ }
+ if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
}
}
// If the provider has external (non-framework) process
diff --git a/services/java/com/android/server/am/ContentProviderConnection.java b/services/java/com/android/server/am/ContentProviderConnection.java
new file mode 100644
index 0000000..84f8f02
--- /dev/null
+++ b/services/java/com/android/server/am/ContentProviderConnection.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 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.server.am;
+
+import android.os.Binder;
+
+/**
+ * Represents a link between a content provider and client.
+ */
+public class ContentProviderConnection extends Binder {
+ public final ContentProviderRecord provider;
+ public final ProcessRecord client;
+ public int stableCount;
+ public int unstableCount;
+ // The client of this connection is currently waiting for the provider to appear.
+ // Protected by the provider lock.
+ public boolean waiting;
+ // The provider of this connection is now dead.
+ public boolean dead;
+
+ // For debugging.
+ public int numStableIncs;
+ public int numUnstableIncs;
+
+ public ContentProviderConnection(ContentProviderRecord _provider, ProcessRecord _client) {
+ provider = _provider;
+ client = _client;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("ContentProviderConnection{");
+ toShortString(sb);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public String toShortString() {
+ StringBuilder sb = new StringBuilder(128);
+ toShortString(sb);
+ return sb.toString();
+ }
+
+ public String toClientString() {
+ StringBuilder sb = new StringBuilder(128);
+ toClientString(sb);
+ return sb.toString();
+ }
+
+ public void toShortString(StringBuilder sb) {
+ sb.append(provider.toShortString());
+ sb.append("->");
+ toClientString(sb);
+ }
+
+ public void toClientString(StringBuilder sb) {
+ sb.append(client.toShortString());
+ sb.append(" s");
+ sb.append(stableCount);
+ sb.append("/");
+ sb.append(numStableIncs);
+ sb.append(" u");
+ sb.append(unstableCount);
+ sb.append("/");
+ sb.append(numUnstableIncs);
+ if (waiting) {
+ sb.append(" WAITING");
+ }
+ if (dead) {
+ sb.append(" DEAD");
+ }
+ }
+}
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java
index 608b09a..fb21b06 100644
--- a/services/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/java/com/android/server/am/ContentProviderRecord.java
@@ -18,6 +18,7 @@
import android.app.IActivityManager.ContentProviderHolder;
import android.content.ComponentName;
+import android.content.IContentProvider;
import android.content.pm.ApplicationInfo;
import android.content.pm.ProviderInfo;
import android.os.IBinder;
@@ -27,28 +28,35 @@
import android.util.Slog;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
-class ContentProviderRecord extends ContentProviderHolder {
+class ContentProviderRecord {
+ final ActivityManagerService service;
+ public final ProviderInfo info;
+ final int uid;
+ final ApplicationInfo appInfo;
+ final ComponentName name;
+ public IContentProvider provider;
+ public boolean noReleaseNeeded;
// All attached clients
- final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
+ final ArrayList<ContentProviderConnection> connections
+ = new ArrayList<ContentProviderConnection>();
+ //final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
// Handles for non-framework processes supported by this provider
HashMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
// Count for external process for which we have no handles.
int externalProcessNoHandleCount;
- final ActivityManagerService service;
- final int uid;
- final ApplicationInfo appInfo;
- final ComponentName name;
ProcessRecord proc; // if non-null, hosting process.
ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
String stringName;
+ String shortStringName;
public ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info,
ApplicationInfo ai, ComponentName _name) {
- super(_info);
service = _service;
+ info = _info;
uid = ai.uid;
appInfo = ai;
name = _name;
@@ -56,12 +64,20 @@
}
public ContentProviderRecord(ContentProviderRecord cpr) {
- super(cpr.info);
+ service = cpr.service;
+ info = cpr.info;
uid = cpr.uid;
appInfo = cpr.appInfo;
name = cpr.name;
noReleaseNeeded = cpr.noReleaseNeeded;
- service = cpr.service;
+ }
+
+ public ContentProviderHolder newHolder(ContentProviderConnection conn) {
+ ContentProviderHolder holder = new ContentProviderHolder(info);
+ holder.provider = provider;
+ holder.noReleaseNeeded = noReleaseNeeded;
+ holder.connection = conn;
+ return holder;
}
public boolean canRunHere(ProcessRecord app) {
@@ -120,30 +136,51 @@
return (externalProcessTokenToHandle != null || externalProcessNoHandleCount > 0);
}
- void dump(PrintWriter pw, String prefix) {
- pw.print(prefix); pw.print("package=");
- pw.print(info.applicationInfo.packageName);
- pw.print(" process="); pw.println(info.processName);
+ void dump(PrintWriter pw, String prefix, boolean full) {
+ if (full) {
+ pw.print(prefix); pw.print("package=");
+ pw.print(info.applicationInfo.packageName);
+ pw.print(" process="); pw.println(info.processName);
+ }
pw.print(prefix); pw.print("proc="); pw.println(proc);
if (launchingApp != null) {
pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp);
}
- pw.print(prefix); pw.print("uid="); pw.print(uid);
- pw.print(" provider="); pw.println(provider);
- pw.print(prefix); pw.print("name="); pw.println(info.authority);
- if (info.isSyncable || info.multiprocess || info.initOrder != 0) {
- pw.print(prefix); pw.print("isSyncable="); pw.print(info.isSyncable);
- pw.print("multiprocess="); pw.print(info.multiprocess);
- pw.print(" initOrder="); pw.println(info.initOrder);
+ if (full) {
+ pw.print(prefix); pw.print("uid="); pw.print(uid);
+ pw.print(" provider="); pw.println(provider);
}
- if (hasExternalProcessHandles()) {
- pw.print(prefix); pw.print("externals=");
- pw.println(externalProcessTokenToHandle.size());
+ pw.print(prefix); pw.print("authority="); pw.println(info.authority);
+ if (full) {
+ if (info.isSyncable || info.multiprocess || info.initOrder != 0) {
+ pw.print(prefix); pw.print("isSyncable="); pw.print(info.isSyncable);
+ pw.print(" multiprocess="); pw.print(info.multiprocess);
+ pw.print(" initOrder="); pw.println(info.initOrder);
+ }
}
- if (clients.size() > 0) {
- pw.print(prefix); pw.println("Clients:");
- for (ProcessRecord cproc : clients) {
- pw.print(prefix); pw.print(" - "); pw.println(cproc.toShortString());
+ if (full) {
+ if (hasExternalProcessHandles()) {
+ pw.print(prefix); pw.print("externals=");
+ pw.println(externalProcessTokenToHandle.size());
+ }
+ } else {
+ if (connections.size() > 0 || externalProcessNoHandleCount > 0) {
+ pw.print(prefix); pw.print(connections.size());
+ pw.print(" connections, "); pw.print(externalProcessNoHandleCount);
+ pw.println(" external handles");
+ }
+ }
+ if (connections.size() > 0) {
+ if (full) {
+ pw.print(prefix); pw.println("Connections:");
+ }
+ for (int i=0; i<connections.size(); i++) {
+ ContentProviderConnection conn = connections.get(i);
+ pw.print(prefix); pw.print(" -> "); pw.println(conn.toClientString());
+ if (conn.provider != this) {
+ pw.print(prefix); pw.print(" *** WRONG PROVIDER: ");
+ pw.println(conn.provider);
+ }
}
}
}
@@ -162,6 +199,17 @@
return stringName = sb.toString();
}
+ public String toShortString() {
+ if (shortStringName != null) {
+ return shortStringName;
+ }
+ StringBuilder sb = new StringBuilder(128);
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append('/');
+ sb.append(name.flattenToShortString());
+ return shortStringName = sb.toString();
+ }
+
// This class represents a handle from an external process to a provider.
private class ExternalProcessHandle implements DeathRecipient {
private static final String LOG_TAG = "ExternalProcessHanldle";
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 4529ecc..8a3ba7f 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -125,8 +125,8 @@
final HashMap<String, ContentProviderRecord> pubProviders
= new HashMap<String, ContentProviderRecord>();
// All ContentProviderRecord process is using
- final HashMap<ContentProviderRecord, Integer> conProviders
- = new HashMap<ContentProviderRecord, Integer>();
+ final ArrayList<ContentProviderConnection> conProviders
+ = new ArrayList<ContentProviderConnection>();
boolean persistent; // always keep this application running?
boolean crashing; // are we in the process of crashing?
@@ -257,25 +257,47 @@
pw.println();
}
if (activities.size() > 0) {
- pw.print(prefix); pw.print("activities="); pw.println(activities);
+ pw.print(prefix); pw.println("Activities:");
+ for (int i=0; i<activities.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(activities.get(i));
+ }
}
if (services.size() > 0) {
- pw.print(prefix); pw.print("services="); pw.println(services);
+ pw.print(prefix); pw.println("Services:");
+ for (ServiceRecord sr : services) {
+ pw.print(prefix); pw.print(" - "); pw.println(sr);
+ }
}
if (executingServices.size() > 0) {
- pw.print(prefix); pw.print("executingServices="); pw.println(executingServices);
+ pw.print(prefix); pw.println("Executing Services:");
+ for (ServiceRecord sr : executingServices) {
+ pw.print(prefix); pw.print(" - "); pw.println(sr);
+ }
}
if (connections.size() > 0) {
- pw.print(prefix); pw.print("connections="); pw.println(connections);
+ pw.print(prefix); pw.println("Connections:");
+ for (ConnectionRecord cr : connections) {
+ pw.print(prefix); pw.print(" - "); pw.println(cr);
+ }
}
if (pubProviders.size() > 0) {
- pw.print(prefix); pw.print("pubProviders="); pw.println(pubProviders);
+ pw.print(prefix); pw.println("Published Providers:");
+ for (HashMap.Entry<String, ContentProviderRecord> ent : pubProviders.entrySet()) {
+ pw.print(prefix); pw.print(" - "); pw.println(ent.getKey());
+ pw.print(prefix); pw.print(" -> "); pw.println(ent.getValue());
+ }
}
if (conProviders.size() > 0) {
- pw.print(prefix); pw.print("conProviders="); pw.println(conProviders);
+ pw.print(prefix); pw.println("Connected Providers:");
+ for (int i=0; i<conProviders.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(conProviders.get(i).toShortString());
+ }
}
if (receivers.size() > 0) {
- pw.print(prefix); pw.print("receivers="); pw.println(receivers);
+ pw.print(prefix); pw.println("Receivers:");
+ for (ReceiverList rl : receivers) {
+ pw.print(prefix); pw.print(" - "); pw.println(rl);
+ }
}
}
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java
index ccc928f..d148ec3 100644
--- a/services/java/com/android/server/am/ProviderMap.java
+++ b/services/java/com/android/server/am/ProviderMap.java
@@ -177,27 +177,9 @@
while (it.hasNext()) {
Map.Entry<ComponentName, ContentProviderRecord> e = it.next();
ContentProviderRecord r = e.getValue();
- if (dumpAll) {
- pw.print(" * ");
- pw.println(r);
- r.dump(pw, " ");
- } else {
- pw.print(" * ");
- pw.println(r);
- if (r.proc != null) {
- pw.print(" proc=");
- pw.println(r.proc);
- }
- if (r.launchingApp != null) {
- pw.print(" launchingApp=");
- pw.println(r.launchingApp);
- }
- if (r.clients.size() > 0 || r.externalProcessNoHandleCount > 0) {
- pw.print(" "); pw.print(r.clients.size());
- pw.print(" clients, "); pw.print(r.externalProcessNoHandleCount);
- pw.println(" external handles");
- }
- }
+ pw.print(" * ");
+ pw.println(r);
+ r.dump(pw, " ", dumpAll);
}
}
@@ -210,7 +192,7 @@
pw.print(" ");
pw.print(e.getKey());
pw.print(": ");
- pw.println(r);
+ pw.println(r.toShortString());
}
}
@@ -221,10 +203,10 @@
pw.println(" ");
pw.println(" Published content providers (by class):");
dumpProvidersByClassLocked(pw, dumpAll, mGlobalByClass);
- pw.println("");
}
if (mProvidersByClassPerUser.size() > 1) {
+ pw.println("");
for (int i = 0; i < mProvidersByClassPerUser.size(); i++) {
HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.valueAt(i);
pw.println(" User " + mProvidersByClassPerUser.keyAt(i) + ":");
@@ -321,7 +303,7 @@
if (r.proc != null) pw.println(r.proc.pid);
else pw.println("(not running)");
if (dumpAll) {
- r.dump(pw, innerPrefix);
+ r.dump(pw, innerPrefix, true);
}
}
if (r.proc != null && r.proc.thread != null) {
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 4b4a89d..3a767c2 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -19,9 +19,8 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
import android.os.UserId;
+import android.util.Slog;
import java.io.PrintWriter;
@@ -69,6 +68,8 @@
_intent.setSourceBounds(null);
}
}
+ if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
+ "Setting Intent of " + this + " to " + _intent);
intent = _intent;
realActivity = _intent != null ? _intent.getComponent() : null;
origActivity = null;
@@ -80,6 +81,8 @@
targetIntent.setComponent(targetComponent);
targetIntent.setSelector(null);
targetIntent.setSourceBounds(null);
+ if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
+ "Setting Intent of " + this + " to target " + targetIntent);
intent = targetIntent;
realActivity = targetComponent;
origActivity = _intent.getComponent();
@@ -103,9 +106,10 @@
}
void dump(PrintWriter pw, String prefix) {
- if (numActivities != 0 || rootWasReset) {
+ if (numActivities != 0 || rootWasReset || userId != 0) {
pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
- pw.print(" rootWasReset="); pw.println(rootWasReset);
+ pw.print(" rootWasReset="); pw.print(rootWasReset);
+ pw.print(" userId="); pw.println(userId);
}
if (affinity != null) {
pw.print(prefix); pw.print("affinity="); pw.println(affinity);
diff --git a/services/java/com/android/server/location/GeocoderProxy.java b/services/java/com/android/server/location/GeocoderProxy.java
index b38ea13..07f3125 100644
--- a/services/java/com/android/server/location/GeocoderProxy.java
+++ b/services/java/com/android/server/location/GeocoderProxy.java
@@ -39,27 +39,28 @@
private static final String TAG = "GeocoderProxy";
+ public static final String SERVICE_ACTION =
+ "com.android.location.service.GeocodeProvider";
+
private final Context mContext;
private final Intent mIntent;
private final Object mMutex = new Object(); // synchronizes access to mServiceConnection
- private Connection mServiceConnection = new Connection(); // never null
+ private Connection mServiceConnection; // never null after ctor
- public GeocoderProxy(Context context, String serviceName) {
+ public GeocoderProxy(Context context, String packageName) {
mContext = context;
- mIntent = new Intent(serviceName);
- mContext.bindService(mIntent, mServiceConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
- | Context.BIND_ALLOW_OOM_MANAGEMENT);
+ mIntent = new Intent(SERVICE_ACTION);
+ reconnect(packageName);
}
- /**
- * When unbundled NetworkLocationService package is updated, we
- * need to unbind from the old version and re-bind to the new one.
- */
- public void reconnect() {
+ /** Bind to service. Will reconnect if already connected */
+ public void reconnect(String packageName) {
synchronized (mMutex) {
- mContext.unbindService(mServiceConnection);
+ if (mServiceConnection != null) {
+ mContext.unbindService(mServiceConnection);
+ }
mServiceConnection = new Connection();
+ mIntent.setPackage(packageName);
mContext.bindService(mIntent, mServiceConnection,
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
| Context.BIND_ALLOW_OOM_MANAGEMENT);
diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java
index 0bc1664..a227ab6 100644
--- a/services/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/java/com/android/server/location/LocationProviderProxy.java
@@ -42,12 +42,15 @@
private static final String TAG = "LocationProviderProxy";
+ public static final String SERVICE_ACTION =
+ "com.android.location.service.NetworkLocationProvider";
+
private final Context mContext;
private final String mName;
private final Intent mIntent;
private final Handler mHandler;
private final Object mMutex = new Object(); // synchronizes access to non-final members
- private Connection mServiceConnection = new Connection(); // never null
+ private Connection mServiceConnection; // never null after ctor
// cached values set by the location manager
private boolean mLocationTracking = false;
@@ -58,28 +61,26 @@
private NetworkInfo mNetworkInfo;
// constructor for proxying location providers implemented in a separate service
- public LocationProviderProxy(Context context, String name, String serviceName,
+ public LocationProviderProxy(Context context, String name, String packageName,
Handler handler) {
mContext = context;
mName = name;
- mIntent = new Intent(serviceName);
+ mIntent = new Intent(SERVICE_ACTION);
mHandler = handler;
- mContext.bindService(mIntent, mServiceConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
- | Context.BIND_ALLOW_OOM_MANAGEMENT);
+ reconnect(packageName);
}
- /**
- * When unbundled NetworkLocationService package is updated, we
- * need to unbind from the old version and re-bind to the new one.
- */
- public void reconnect() {
+ /** Bind to service. Will reconnect if already connected */
+ public void reconnect(String packageName) {
synchronized (mMutex) {
- mContext.unbindService(mServiceConnection);
+ if (mServiceConnection != null) {
+ mContext.unbindService(mServiceConnection);
+ }
mServiceConnection = new Connection();
+ mIntent.setPackage(packageName);
mContext.bindService(mIntent, mServiceConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
- | Context.BIND_ALLOW_OOM_MANAGEMENT);
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND |
+ Context.BIND_ALLOW_OOM_MANAGEMENT);
}
}
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index d3b667f..04ec820 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -225,9 +225,10 @@
{
ALOGD("nuSensorService thread starting...");
- const size_t numEventMax = 16 * (1 + mVirtualSensorList.size());
- sensors_event_t buffer[numEventMax];
- sensors_event_t scratch[numEventMax];
+ const size_t numEventMax = 16;
+ const size_t minBufferSize = numEventMax * mVirtualSensorList.size();
+ sensors_event_t buffer[minBufferSize];
+ sensors_event_t scratch[minBufferSize];
SensorDevice& device(SensorDevice::getInstance());
const size_t vcount = mVirtualSensorList.size();
@@ -255,10 +256,17 @@
fusion.process(event[i]);
}
}
- for (size_t i=0 ; i<size_t(count) ; i++) {
+ for (size_t i=0 ; i<size_t(count) && k<minBufferSize ; i++) {
for (size_t j=0 ; j<activeVirtualSensorCount ; j++) {
+ if (count + k >= minBufferSize) {
+ ALOGE("buffer too small to hold all events: "
+ "count=%u, k=%u, size=%u",
+ count, k, minBufferSize);
+ break;
+ }
sensors_event_t out;
- if (virtualSensors.valueAt(j)->process(&out, event[i])) {
+ SensorInterface* si = virtualSensors.valueAt(j);
+ if (si->process(&out, event[i])) {
buffer[count + k] = out;
k++;
}
diff --git a/test-runner/src/android/test/mock/MockContentResolver.java b/test-runner/src/android/test/mock/MockContentResolver.java
index 65eb21b..715da0f 100644
--- a/test-runner/src/android/test/mock/MockContentResolver.java
+++ b/test-runner/src/android/test/mock/MockContentResolver.java
@@ -118,6 +118,11 @@
return releaseProvider(icp);
}
+ /** @hide */
+ @Override
+ public void unstableProviderDied(IContentProvider icp) {
+ }
+
/**
* Overrides {@link android.content.ContentResolver#notifyChange(Uri, ContentObserver, boolean)
* ContentResolver.notifChange(Uri, ContentObserver, boolean)}. All parameters are ignored.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentResolver.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentResolver.java
index fec2c3f..8d259d7 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentResolver.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentResolver.java
@@ -72,6 +72,11 @@
return releaseProvider(icp);
}
+ /** @hide */
+ @Override
+ public void unstableProviderDied(IContentProvider icp) {
+ }
+
/**
* Stub for the layoutlib bridge content resolver.
*/