Merge "Fix anchor overlap handling in ListPopupWindow" into oc-dev
diff --git a/Android.mk b/Android.mk
index ee7d471..01fb73e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -224,6 +224,7 @@
core/java/android/net/IEthernetManager.aidl \
core/java/android/net/IEthernetServiceListener.aidl \
core/java/android/net/INetdEventCallback.aidl \
+ core/java/android/net/IIpSecService.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
core/java/android/net/INetworkPolicyListener.aidl \
core/java/android/net/INetworkPolicyManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index c5f4816..48f57b4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4771,7 +4771,7 @@
method public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
method public abstract int getBackStackEntryCount();
method public abstract android.app.Fragment getFragment(android.os.Bundle, java.lang.String);
- method public abstract java.util.Collection<android.app.Fragment> getFragments();
+ method public abstract java.util.List<android.app.Fragment> getFragments();
method public abstract android.app.Fragment getPrimaryNavigationFragment();
method public void invalidateOptionsMenu();
method public abstract boolean isDestroyed();
@@ -25557,7 +25557,7 @@
method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
- method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
@@ -25591,7 +25591,6 @@
method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
- method public android.net.IpSecTransform.Builder setSpi(int, int);
method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
}
@@ -37052,7 +37051,7 @@
ctor public FillResponse.Builder();
method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
method public android.service.autofill.FillResponse build();
- method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
+ method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
@@ -37068,8 +37067,10 @@
field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2
field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3
+ field public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 5; // 0x5
field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0
field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1
+ field public static final int SAVE_DATA_TYPE_USERNAME = 4; // 0x4
}
public static final class SaveInfo.Builder {
diff --git a/api/system-current.txt b/api/system-current.txt
index 9b295bf..bc063b5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4931,7 +4931,7 @@
method public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
method public abstract int getBackStackEntryCount();
method public abstract android.app.Fragment getFragment(android.os.Bundle, java.lang.String);
- method public abstract java.util.Collection<android.app.Fragment> getFragments();
+ method public abstract java.util.List<android.app.Fragment> getFragments();
method public abstract android.app.Fragment getPrimaryNavigationFragment();
method public void invalidateOptionsMenu();
method public abstract boolean isDestroyed();
@@ -27718,13 +27718,11 @@
public final class IpSecManager {
method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
- method public void applyTunnelModeTransform(android.net.Network, android.net.IpSecTransform);
method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
- method public void removeTunnelModeTransform(android.net.Network, android.net.IpSecTransform);
- method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
@@ -27755,12 +27753,10 @@
public static class IpSecTransform.Builder {
ctor public IpSecTransform.Builder(android.content.Context);
method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
- method public android.net.IpSecTransform buildTunnelModeTransform(java.net.InetAddress, java.net.InetAddress);
method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
method public android.net.IpSecTransform.Builder setNattKeepalive(int);
- method public android.net.IpSecTransform.Builder setSpi(int, int);
method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
method public android.net.IpSecTransform.Builder setUnderlyingNetwork(android.net.Network);
}
@@ -40117,7 +40113,7 @@
ctor public FillResponse.Builder();
method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
method public android.service.autofill.FillResponse build();
- method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
+ method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
@@ -40133,8 +40129,10 @@
field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2
field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3
+ field public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 5; // 0x5
field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0
field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1
+ field public static final int SAVE_DATA_TYPE_USERNAME = 4; // 0x4
}
public static final class SaveInfo.Builder {
diff --git a/api/test-current.txt b/api/test-current.txt
index 6db91be..8ea1dde 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4783,7 +4783,7 @@
method public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
method public abstract int getBackStackEntryCount();
method public abstract android.app.Fragment getFragment(android.os.Bundle, java.lang.String);
- method public abstract java.util.Collection<android.app.Fragment> getFragments();
+ method public abstract java.util.List<android.app.Fragment> getFragments();
method public abstract android.app.Fragment getPrimaryNavigationFragment();
method public void invalidateOptionsMenu();
method public abstract boolean isDestroyed();
@@ -25670,7 +25670,7 @@
method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
- method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
@@ -25704,7 +25704,6 @@
method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
- method public android.net.IpSecTransform.Builder setSpi(int, int);
method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
}
@@ -37210,7 +37209,7 @@
ctor public FillResponse.Builder();
method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
method public android.service.autofill.FillResponse build();
- method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
+ method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
@@ -37226,8 +37225,10 @@
field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2
field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3
+ field public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 5; // 0x5
field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0
field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1
+ field public static final int SAVE_DATA_TYPE_USERNAME = 4; // 0x4
}
public static final class SaveInfo.Builder {
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 35011b5..8442585 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -40,8 +40,8 @@
import java.io.IOException;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
@@ -98,11 +98,10 @@
"alwaysPromptForAccount";
/**
- * If set then this string willb e used as the description rather than
+ * If set then this string will be used as the description rather than
* the default.
*/
- public static final String EXTRA_DESCRIPTION_TEXT_OVERRIDE =
- "descriptionTextOverride";
+ public static final String EXTRA_DESCRIPTION_TEXT_OVERRIDE = "descriptionTextOverride";
public static final int REQUEST_NULL = 0;
public static final int REQUEST_CHOOSE_TYPE = 1;
@@ -112,7 +111,8 @@
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 static final String KEY_INSTANCE_STATE_ACCOUNT_LIST = "accountAndVisibilityList";
+ private static final String KEY_INSTANCE_STATE_ACCOUNTS_LIST = "accountsList";
+ private static final String KEY_INSTANCE_STATE_VISIBILITY_LIST = "visibilityList";
private static final int SELECTED_ITEM_NONE = -1;
@@ -122,7 +122,7 @@
private boolean mSelectedAddNewAccount = false;
private String mDescriptionOverride;
- private Map<Account, Integer> mAccounts;
+ private LinkedHashMap<Account, Integer> mAccounts;
// TODO Redesign flow to show NOT_VISIBLE accounts
// and display a warning if they are selected.
// Currently NOT_VISBILE accounts are not shown at all.
@@ -164,6 +164,10 @@
// save some items we use frequently
final Intent intent = getIntent();
+ mSetOfAllowableAccounts = getAllowableAccountSet(intent);
+ mSetOfRelevantAccountTypes = getReleventAccountTypes(intent);
+ mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
+
if (savedInstanceState != null) {
mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
mExistingAccounts =
@@ -174,8 +178,15 @@
savedInstanceState.getString(KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);
mSelectedAddNewAccount =
savedInstanceState.getBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
- mAccounts = (Map<Account, Integer>) savedInstanceState
- .getSerializable(KEY_INSTANCE_STATE_ACCOUNT_LIST);
+ // restore mAccounts
+ Parcelable[] accounts =
+ savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_ACCOUNTS_LIST);
+ ArrayList<Integer> visibility =
+ savedInstanceState.getIntegerArrayList(KEY_INSTANCE_STATE_VISIBILITY_LIST);
+ mAccounts = new LinkedHashMap<>();
+ for (int i = 0; i < accounts.length; i++) {
+ mAccounts.put((Account) accounts[i], visibility.get(i));
+ }
} else {
mPendingRequest = REQUEST_NULL;
mExistingAccounts = null;
@@ -185,20 +196,21 @@
if (selectedAccount != null) {
mSelectedAccountName = selectedAccount.name;
}
+ mAccounts = getAcceptableAccountChoices(AccountManager.get(this));
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "selected account name is " + mSelectedAccountName);
}
+ mPossiblyVisibleAccounts = new ArrayList<>(mAccounts.size());
+ for (Map.Entry<Account, Integer> entry : mAccounts.entrySet()) {
+ if (AccountManager.VISIBILITY_NOT_VISIBLE != entry.getValue()) {
+ mPossiblyVisibleAccounts.add(entry.getKey());
+ }
+ }
- mSetOfAllowableAccounts = getAllowableAccountSet(intent);
- mSetOfRelevantAccountTypes = getReleventAccountTypes(intent);
- mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
-
- mAccounts = getAcceptableAccountChoices(AccountManager.get(this));
- if (mAccounts.isEmpty()
- && mDisallowAddAccounts) {
+ if (mPossiblyVisibleAccounts.isEmpty() && mDisallowAddAccounts) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.app_not_authorized);
mDontShowPicker = true;
@@ -216,7 +228,7 @@
if (mPendingRequest == REQUEST_NULL) {
// If there are no relevant accounts and only one relevant account type go directly to
// add account. Otherwise let the user choose.
- if (mAccounts.isEmpty()) {
+ if (mPossiblyVisibleAccounts.isEmpty()) {
setNonLabelThemeAndCallSuperCreate(savedInstanceState);
if (mSetOfRelevantAccountTypes.size() == 1) {
runAddAccountForAuthenticator(mSetOfRelevantAccountTypes.iterator().next());
@@ -226,12 +238,6 @@
}
}
- mPossiblyVisibleAccounts = new ArrayList<>(mAccounts.size());
- for (Map.Entry<Account, Integer> entry : mAccounts.entrySet()) {
- if (AccountManager.VISIBILITY_NOT_VISIBLE != entry.getValue()) {
- mPossiblyVisibleAccounts.add(entry.getKey());
- }
- }
String[] listItems = getListOfDisplayableOptions(mPossiblyVisibleAccounts);
mSelectedItemIndex = getItemIndexToSelect(mPossiblyVisibleAccounts, mSelectedAccountName,
mSelectedAddNewAccount);
@@ -270,10 +276,16 @@
mPossiblyVisibleAccounts.get(mSelectedItemIndex).name);
}
}
- // should be HashMap by default.
- HashMap<Account, Integer> accountsHashMap = (mAccounts instanceof HashMap)
- ? (HashMap) mAccounts : new HashMap<Account, Integer>(mAccounts);
- outState.putSerializable(KEY_INSTANCE_STATE_ACCOUNT_LIST, accountsHashMap);
+ // save mAccounts
+ Parcelable[] accounts = new Parcelable[mAccounts.size()];
+ ArrayList<Integer> visibility = new ArrayList<>(mAccounts.size());
+ int i = 0;
+ for (Map.Entry<Account, Integer> e : mAccounts.entrySet()) {
+ accounts[i++] = e.getKey();
+ visibility.add(e.getValue());
+ }
+ outState.putParcelableArray(KEY_INSTANCE_STATE_ACCOUNTS_LIST, accounts);
+ outState.putIntegerArrayList(KEY_INSTANCE_STATE_VISIBILITY_LIST, visibility);
}
public void onCancelButtonClicked(View view) {
@@ -308,7 +320,7 @@
if (resultCode == RESULT_CANCELED) {
// if canceling out of addAccount and the original state caused us to skip this,
// finish this activity
- if (mAccounts.isEmpty()) {
+ if (mPossiblyVisibleAccounts.isEmpty()) {
setResult(Activity.RESULT_CANCELED);
finish();
}
@@ -428,18 +440,20 @@
private void setResultAndFinish(final String accountName, final String accountType) {
// Mark account as visible since user chose it.
Account account = new Account(accountName, accountType);
- Integer oldVisibility = mAccounts.get(account);
- // oldVisibility is null if new account was added
- if (oldVisibility == null) {
- Map<Account, Integer> accountsAndVisibility = AccountManager.get(this)
- .getAccountsAndVisibilityForPackage(mCallingPackage, null /* type */);
- oldVisibility = accountsAndVisibility.get(account);
- }
+ Integer oldVisibility =
+ AccountManager.get(this).getAccountVisibility(account, mCallingPackage);
if (oldVisibility != null
&& oldVisibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) {
AccountManager.get(this).setAccountVisibility(account, mCallingPackage,
AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
}
+
+ if (oldVisibility != null && oldVisibility == AccountManager.VISIBILITY_NOT_VISIBLE) {
+ // Added account is not visible to caller.
+ setResult(Activity.RESULT_CANCELED);
+ finish();
+ return;
+ }
Bundle bundle = new Bundle();
bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);
@@ -448,6 +462,7 @@
Log.v(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: selected account "
+ accountName + ", " + accountType);
}
+
finish();
}
@@ -509,22 +524,24 @@
* that don't match the allowable types, if provided, or that don't match the allowable
* accounts, if provided.
*/
- private Map<Account, Integer> getAcceptableAccountChoices(AccountManager accountManager) {
- Map<Account, Integer> accountsAndVisibility =
- accountManager.getAccountsAndVisibilityForPackage(mCallingPackage, null /* type */);
-
- Map<Account, Integer> accountsToPopulate =
- new HashMap<Account, Integer>(accountsAndVisibility.size());
- for (Map.Entry<Account, Integer> entry : accountsAndVisibility.entrySet()) {
+ private LinkedHashMap<Account, Integer> getAcceptableAccountChoices(AccountManager accountManager) {
+ Map<Account, Integer> accountsAndVisibilityForCaller =
+ accountManager.getAccountsAndVisibilityForPackage(mCallingPackage, null);
+ Account[] allAccounts = accountManager.getAccounts();
+ LinkedHashMap<Account, Integer> accountsToPopulate =
+ new LinkedHashMap<>(accountsAndVisibilityForCaller.size());
+ for (Account account : allAccounts) {
if (mSetOfAllowableAccounts != null
- && !mSetOfAllowableAccounts.contains(entry.getKey())) {
+ && !mSetOfAllowableAccounts.contains(account)) {
continue;
}
if (mSetOfRelevantAccountTypes != null
- && !mSetOfRelevantAccountTypes.contains(entry.getKey().type)) {
+ && !mSetOfRelevantAccountTypes.contains(account.type)) {
continue;
}
- accountsToPopulate.put(entry.getKey(), entry.getValue());
+ if (accountsAndVisibilityForCaller.get(account) != null) {
+ accountsToPopulate.put(account, accountsAndVisibilityForCaller.get(account));
+ }
}
return accountsToPopulate;
}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 3102a93..a3c123f 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -2608,6 +2608,12 @@
}
}
+ void noteStateNotSaved() {
+ if (mChildFragmentManager != null) {
+ mChildFragmentManager.noteStateNotSaved();
+ }
+ }
+
@Deprecated
void performMultiWindowModeChanged(boolean isInMultiWindowMode) {
onMultiWindowModeChanged(isInMultiWindowMode);
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 399987f..75d6295 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -314,14 +314,17 @@
public abstract Fragment getFragment(Bundle bundle, String key);
/**
- * Get a collection of all fragments that are currently added to the FragmentManager.
+ * Get a list of all fragments that are currently added to the FragmentManager.
* This may include those that are hidden as well as those that are shown.
* This will not include any fragments only in the back stack, or fragments that
* are detached or removed.
+ * <p>
+ * The order of the fragments in the list is the order in which they were
+ * added or attached.
*
- * @return A collection of all fragments that are added to the FragmentManager.
+ * @return A list of all fragments that are added to the FragmentManager.
*/
- public abstract Collection<Fragment> getFragments();
+ public abstract List<Fragment> getFragments();
/**
* Save the current instance state of the given Fragment. This can be
@@ -695,6 +698,9 @@
// This is dangerous, but we want to keep from breaking old applications.
boolean mAllowOldReentrantBehavior;
+ // Saved FragmentManagerNonConfig during saveAllState() and cleared in noteStateNotSaved()
+ FragmentManagerNonConfig mSavedNonConfig;
+
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
@@ -907,12 +913,12 @@
}
@Override
- public Collection<Fragment> getFragments() {
+ public List<Fragment> getFragments() {
if (mAdded == null) {
return Collections.EMPTY_LIST;
}
synchronized (mAdded) {
- return (Collection<Fragment>) mAdded.clone();
+ return (List<Fragment>) mAdded.clone();
}
}
@@ -2518,6 +2524,35 @@
}
FragmentManagerNonConfig retainNonConfig() {
+ setRetaining(mSavedNonConfig);
+ return mSavedNonConfig;
+ }
+
+ /**
+ * Recurse the FragmentManagerNonConfig fragments and set the mRetaining to true. This
+ * was previously done while saving the non-config state, but that has been moved to
+ * {@link #saveNonConfig()} called from {@link #saveAllState()}. If mRetaining is set too
+ * early, the fragment won't be destroyed when the FragmentManager is destroyed.
+ */
+ private static void setRetaining(FragmentManagerNonConfig nonConfig) {
+ if (nonConfig == null) {
+ return;
+ }
+ List<Fragment> fragments = nonConfig.getFragments();
+ if (fragments != null) {
+ for (Fragment fragment : fragments) {
+ fragment.mRetaining = true;
+ }
+ }
+ List<FragmentManagerNonConfig> children = nonConfig.getChildNonConfigs();
+ if (children != null) {
+ for (FragmentManagerNonConfig child : children) {
+ setRetaining(child);
+ }
+ }
+ }
+
+ void saveNonConfig() {
ArrayList<Fragment> fragments = null;
ArrayList<FragmentManagerNonConfig> childFragments = null;
if (mActive != null) {
@@ -2529,13 +2564,13 @@
fragments = new ArrayList<>();
}
fragments.add(f);
- f.mRetaining = true;
f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f);
}
boolean addedChild = false;
if (f.mChildFragmentManager != null) {
- FragmentManagerNonConfig child = f.mChildFragmentManager.retainNonConfig();
+ f.mChildFragmentManager.saveNonConfig();
+ FragmentManagerNonConfig child = f.mChildFragmentManager.mSavedNonConfig;
if (child != null) {
if (childFragments == null) {
childFragments = new ArrayList<>();
@@ -2554,9 +2589,10 @@
}
}
if (fragments == null && childFragments == null) {
- return null;
+ mSavedNonConfig = null;
+ } else {
+ mSavedNonConfig = new FragmentManagerNonConfig(fragments, childFragments);
}
- return new FragmentManagerNonConfig(fragments, childFragments);
}
void saveFragmentViewState(Fragment f) {
@@ -2617,6 +2653,7 @@
execPendingActions();
mStateSaved = true;
+ mSavedNonConfig = null;
if (mActive == null || mActive.size() <= 0) {
return null;
@@ -2717,6 +2754,7 @@
if (mPrimaryNav != null) {
fms.mPrimaryNavActiveIndex = mPrimaryNav.mIndex;
}
+ saveNonConfig();
return fms;
}
@@ -2892,9 +2930,17 @@
}
public void noteStateNotSaved() {
+ mSavedNonConfig = null;
mStateSaved = false;
+ final int addedCount = mAdded == null ? 0 : mAdded.size();
+ for (int i = 0; i < addedCount; i++) {
+ Fragment fragment = mAdded.get(i);
+ if (fragment != null) {
+ fragment.noteStateNotSaved();
+ }
+ }
}
-
+
public void dispatchCreate() {
mStateSaved = false;
dispatchMoveToState(Fragment.CREATED);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 6b05bdf..4572578 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -74,7 +74,9 @@
import android.net.EthernetManager;
import android.net.IConnectivityManager;
import android.net.IEthernetManager;
+import android.net.IIpSecService;
import android.net.INetworkPolicyManager;
+import android.net.IpSecManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkScoreManager;
import android.net.nsd.INsdManager;
@@ -261,6 +263,15 @@
return new ConnectivityManager(context, service);
}});
+ registerService(Context.IPSEC_SERVICE, IpSecManager.class,
+ new StaticServiceFetcher<IpSecManager>() {
+ @Override
+ public IpSecManager createService() {
+ IBinder b = ServiceManager.getService(Context.IPSEC_SERVICE);
+ IIpSecService service = IIpSecService.Stub.asInterface(b);
+ return new IpSecManager(service);
+ }});
+
registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
new StaticServiceFetcher<CountryDetector>() {
@Override
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index fe51633..545aef5 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -599,6 +599,10 @@
boolean mSanitized;
HtmlInfo mHtmlInfo;
+ // POJO used to override some autofill-related values when the node is parcelized.
+ // Not written to parcel.
+ AutofillOverlay mAutofillOverlay;
+
int mX;
int mY;
int mScrollX;
@@ -756,6 +760,7 @@
boolean writeSensitive = true;
int flags = mFlags & ~FLAGS_ALL_CONTROL;
+
if (mId != View.NO_ID) {
flags |= FLAGS_HAS_ID;
}
@@ -810,6 +815,13 @@
// Remove 'checked' from sanitized autofill request.
writtenFlags = flags & ~FLAGS_CHECKED;
}
+ if (mAutofillOverlay != null) {
+ if (mAutofillOverlay.focused) {
+ writtenFlags |= ViewNode.FLAGS_FOCUSED;
+ } else {
+ writtenFlags &= ~ViewNode.FLAGS_FOCUSED;
+ }
+ }
out.writeInt(writtenFlags);
if ((flags&FLAGS_HAS_ID) != 0) {
@@ -829,7 +841,14 @@
out.writeParcelable(mAutofillId, 0);
out.writeInt(mAutofillType);
out.writeStringArray(mAutofillHints);
- final AutofillValue sanitizedValue = writeSensitive ? mAutofillValue : null;
+ final AutofillValue sanitizedValue;
+ if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
+ sanitizedValue = mAutofillOverlay.value;
+ } else if (writeSensitive) {
+ sanitizedValue = mAutofillValue;
+ } else {
+ sanitizedValue = null;
+ }
out.writeParcelable(sanitizedValue, 0);
out.writeStringArray(mAutofillOptions);
if (mHtmlInfo instanceof Parcelable) {
@@ -959,6 +978,11 @@
return mAutofillValue;
}
+ /** @hide **/
+ public void setAutofillOverlay(AutofillOverlay overlay) {
+ mAutofillOverlay = overlay;
+ }
+
/**
* Gets the options that can be used to autofill this structure.
*
@@ -1340,6 +1364,16 @@
}
}
+ /**
+ * POJO used to override some autofill-related values when the node is parcelized.
+ *
+ * @hide
+ */
+ static public class AutofillOverlay {
+ public boolean focused;
+ public AutofillValue value;
+ }
+
static class ViewNodeBuilder extends ViewStructure {
final AssistStructure mAssist;
final ViewNode mNode;
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 9457d15..2dfb45f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -6172,6 +6172,7 @@
cpuAbiOverride = dest.readString();
use32bitAbi = (dest.readInt() == 1);
restrictUpdateHash = dest.createByteArray();
+ visibleToInstantApps = dest.readInt() == 1;
}
private static void internStringArrayList(List<String> list) {
@@ -6286,6 +6287,7 @@
dest.writeString(cpuAbiOverride);
dest.writeInt(use32bitAbi ? 1 : 0);
dest.writeByteArray(restrictUpdateHash);
+ dest.writeInt(visibleToInstantApps ? 1 : 0);
}
diff --git a/core/java/android/hardware/SensorAdditionalInfo.java b/core/java/android/hardware/SensorAdditionalInfo.java
index 572a287..ea1d01b 100644
--- a/core/java/android/hardware/SensorAdditionalInfo.java
+++ b/core/java/android/hardware/SensorAdditionalInfo.java
@@ -131,6 +131,64 @@
*/
public static final int TYPE_SAMPLING = 0x10004;
+ /**
+ * Local geo-magnetic Field.
+ *
+ * Additional into to sensor hardware. Local geomagnetic field information based on
+ * device geo location. This type is primarily for for magnetic field calibration and rotation
+ * vector sensor fusion.
+ *
+ * float[3]: strength (uT), declination and inclination angle (rad).
+ * @hide
+ */
+ public static final int TYPE_LOCAL_GEOMAGNETIC_FIELD = 0x30000;
+
+ /**
+ * Local gravity acceleration strength.
+ *
+ * Additional info to sensor hardware for accelerometer calibration.
+ *
+ * float: gravitational acceleration norm in m/s^2.
+ * @hide
+ */
+ public static final int TYPE_LOCAL_GRAVITY = 0x30001;
+
+ /**
+ * Device dock state.
+ *
+ * Additional info to sensor hardware indicating dock states of device.
+ *
+ * int32_t: dock state following definition of {@link android.content.Intent#EXTRA_DOCK_STATE}.
+ * Undefined values are ignored.
+ * @hide
+ */
+ public static final int TYPE_DOCK_STATE = 0x30002;
+
+ /**
+ * High performance mode.
+ *
+ * Additional info to sensor hardware. Device is able to use up more power and take more
+ * resources to improve throughput and latency in high performance mode. One possible use case
+ * is virtual reality, when sensor latency need to be carefully controlled.
+ *
+ * int32_t: 1 or 0, denoting device is in or out of high performance mode, respectively.
+ * Other values are ignored.
+ * @hide
+ */
+ public static final int TYPE_HIGH_PERFORMANCE_MODE = 0x30003;
+
+ /**
+ * Magnetic field calibration hint.
+ *
+ * Additional info to sensor hardware. Device is notified when manually triggered magnetic field
+ * calibration procedure is started or stopped. The calibration procedure is assumed timed out
+ * after 1 minute from start, even if an explicit stop is not received.
+ *
+ * int32_t: 1 for calibration start, 0 for stop, other values are ignored.
+ * @hide
+ */
+ public static final int TYPE_MAGNETIC_FIELD_CALIBRATION = 0x30004;
+
SensorAdditionalInfo(
Sensor aSensor, int aType, int aSerial, int [] aIntValues, float [] aFloatValues) {
sensor = aSensor;
@@ -139,4 +197,18 @@
intValues = aIntValues;
floatValues = aFloatValues;
}
+
+ /** @hide */
+ public static SensorAdditionalInfo createLocalGeomagneticField(
+ float strength, float declination, float inclination) {
+ if (strength < 10 || strength > 100 // much beyond extreme values on earth
+ || declination < 0 || declination > Math.PI
+ || inclination < -Math.PI / 2 || inclination > Math.PI / 2) {
+ throw new IllegalArgumentException("Geomagnetic field info out of range");
+ }
+
+ return new SensorAdditionalInfo(
+ null, TYPE_LOCAL_GEOMAGNETIC_FIELD, 0,
+ null, new float[] { strength, declination, inclination});
+ }
}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index a6930b0..1dc6478 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1927,4 +1927,12 @@
}
return delay;
}
+
+ /** @hide */
+ public boolean setOperationParameter(SensorAdditionalInfo parameter) {
+ return setOperationParameterImpl(parameter);
+ }
+
+ /** @hide */
+ protected abstract boolean setOperationParameterImpl(SensorAdditionalInfo parameter);
}
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 7029847..0677179 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -67,6 +67,9 @@
private static native int nativeConfigDirectChannel(
long nativeInstance, int channelHandle, int sensorHandle, int rate);
+ private static native int nativeSetOperationParameter(
+ long nativeInstance, int type, float[] floatValues, int[] intValues);
+
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static boolean sNativeClassInited = false;
@@ -928,4 +931,9 @@
}
}
+
+ protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) {
+ return nativeSetOperationParameter(
+ mNativeInstance, parameter.type, parameter.floatValues, parameter.intValues) == 0;
+ }
}
diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl
new file mode 100644
index 0000000..0aa3ce6
--- /dev/null
+++ b/core/java/android/net/IIpSecService.aidl
@@ -0,0 +1,46 @@
+/*
+** Copyright 2017, 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 android.net;
+
+import android.net.Network;
+import android.net.IpSecConfig;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * @hide
+ */
+interface IIpSecService
+{
+ Bundle reserveSecurityParameterIndex(
+ int direction, in String remoteAddress, int requestedSpi, in IBinder binder);
+
+ void releaseSecurityParameterIndex(int resourceId);
+
+ Bundle openUdpEncapsulationSocket(int port, in IBinder binder);
+
+ void closeUdpEncapsulationSocket(in ParcelFileDescriptor socket);
+
+ Bundle createTransportModeTransform(in IpSecConfig c, in IBinder binder);
+
+ void deleteTransportModeTransform(int transformId);
+
+ void applyTransportModeTransform(in ParcelFileDescriptor socket, int transformId);
+
+ void removeTransportModeTransform(in ParcelFileDescriptor socket, int transformId);
+}
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index da5cb37..7fea4a2 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -164,6 +164,8 @@
private static boolean isTruncationLengthValid(String algo, int truncLenBits) {
switch (algo) {
+ case ALGO_CRYPT_AES_CBC:
+ return (truncLenBits == 128 || truncLenBits == 192 || truncLenBits == 256);
case ALGO_AUTH_HMAC_MD5:
return (truncLenBits >= 96 && truncLenBits <= 128);
case ALGO_AUTH_HMAC_SHA1:
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
index b58bf42..13dc19f 100644
--- a/core/java/android/net/IpSecConfig.java
+++ b/core/java/android/net/IpSecConfig.java
@@ -23,7 +23,7 @@
/** @hide */
public final class IpSecConfig implements Parcelable {
- private static final String TAG = IpSecConfig.class.getSimpleName();
+ private static final String TAG = "IpSecConfig";
//MODE_TRANSPORT or MODE_TUNNEL
int mode;
@@ -43,13 +43,13 @@
int spi;
// Encryption Algorithm
- IpSecAlgorithm encryptionAlgo;
+ IpSecAlgorithm encryption;
// Authentication Algorithm
- IpSecAlgorithm authenticationAlgo;
+ IpSecAlgorithm authentication;
}
- Flow[] flow = new Flow[2];
+ Flow[] flow = new Flow[] {new Flow(), new Flow()};
// For tunnel mode IPv4 UDP Encapsulation
// IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE
@@ -57,17 +57,15 @@
int encapLocalPort;
int encapRemotePort;
- // An optional protocol to match with the selector
- int selectorProto;
-
- // A bitmask of FEATURE_* indicating which of the fields
- // of this class are valid.
- long features;
-
// An interval, in seconds between the NattKeepalive packets
int nattKeepaliveInterval;
- public InetAddress getLocalIp() {
+ // Transport or Tunnel
+ public int getMode() {
+ return mode;
+ }
+
+ public InetAddress getLocalAddress() {
return localAddress;
}
@@ -75,19 +73,19 @@
return flow[direction].spi;
}
- public InetAddress getRemoteIp() {
+ public InetAddress getRemoteAddress() {
return remoteAddress;
}
- public IpSecAlgorithm getEncryptionAlgo(int direction) {
- return flow[direction].encryptionAlgo;
+ public IpSecAlgorithm getEncryption(int direction) {
+ return flow[direction].encryption;
}
- public IpSecAlgorithm getAuthenticationAlgo(int direction) {
- return flow[direction].authenticationAlgo;
+ public IpSecAlgorithm getAuthentication(int direction) {
+ return flow[direction].authentication;
}
- Network getNetwork() {
+ public Network getNetwork() {
return network;
}
@@ -103,18 +101,10 @@
return encapRemotePort;
}
- public int getSelectorProto() {
- return selectorProto;
- }
-
- int getNattKeepaliveInterval() {
+ public int getNattKeepaliveInterval() {
return nattKeepaliveInterval;
}
- public boolean hasProperty(int featureBits) {
- return (features & featureBits) == featureBits;
- }
-
// Parcelable Methods
@Override
@@ -124,31 +114,25 @@
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeLong(features);
// TODO: Use a byte array or other better method for storing IPs that can also include scope
out.writeString((localAddress != null) ? localAddress.getHostAddress() : null);
// TODO: Use a byte array or other better method for storing IPs that can also include scope
out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null);
out.writeParcelable(network, flags);
out.writeInt(flow[IpSecTransform.DIRECTION_IN].spi);
- out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryptionAlgo, flags);
- out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authenticationAlgo, flags);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryption, flags);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authentication, flags);
out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spi);
- out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo, flags);
- out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo, flags);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryption, flags);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authentication, flags);
out.writeInt(encapType);
out.writeInt(encapLocalPort);
out.writeInt(encapRemotePort);
- out.writeInt(selectorProto);
}
// Package Private: Used by the IpSecTransform.Builder;
// there should be no public constructor for this object
- IpSecConfig() {
- flow[IpSecTransform.DIRECTION_IN].spi = 0;
- flow[IpSecTransform.DIRECTION_OUT].spi = 0;
- nattKeepaliveInterval = 0; //FIXME constant
- }
+ IpSecConfig() {}
private static InetAddress readInetAddressFromParcel(Parcel in) {
String addrString = in.readString();
@@ -164,24 +148,22 @@
}
private IpSecConfig(Parcel in) {
- features = in.readLong();
localAddress = readInetAddressFromParcel(in);
remoteAddress = readInetAddressFromParcel(in);
network = (Network) in.readParcelable(Network.class.getClassLoader());
flow[IpSecTransform.DIRECTION_IN].spi = in.readInt();
- flow[IpSecTransform.DIRECTION_IN].encryptionAlgo =
+ flow[IpSecTransform.DIRECTION_IN].encryption =
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
- flow[IpSecTransform.DIRECTION_IN].authenticationAlgo =
+ flow[IpSecTransform.DIRECTION_IN].authentication =
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
flow[IpSecTransform.DIRECTION_OUT].spi = in.readInt();
- flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo =
+ flow[IpSecTransform.DIRECTION_OUT].encryption =
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
- flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo =
+ flow[IpSecTransform.DIRECTION_OUT].authentication =
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
encapType = in.readInt();
encapLocalPort = in.readInt();
encapRemotePort = in.readInt();
- selectorProto = in.readInt();
}
public static final Parcelable.Creator<IpSecConfig> CREATOR =
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 2c544e9..6852beb 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -17,10 +17,11 @@
import static com.android.internal.util.Preconditions.checkNotNull;
-import android.annotation.SystemApi;
-import android.content.Context;
-import android.os.INetworkManagementService;
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.Bundle;
import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
import android.util.AndroidException;
import dalvik.system.CloseGuard;
import java.io.FileDescriptor;
@@ -41,6 +42,29 @@
private static final String TAG = "IpSecManager";
/**
+ * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index.
+ *
+ * <p>No IPsec packet may contain an SPI of 0.
+ */
+ public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
+
+ /** @hide */
+ public interface Status {
+ public static final int OK = 0;
+ public static final int RESOURCE_UNAVAILABLE = 1;
+ public static final int SPI_UNAVAILABLE = 2;
+ }
+
+ /** @hide */
+ public static final String KEY_STATUS = "status";
+ /** @hide */
+ public static final String KEY_RESOURCE_ID = "resourceId";
+ /** @hide */
+ public static final String KEY_SPI = "spi";
+ /** @hide */
+ public static final int INVALID_RESOURCE_ID = 0;
+
+ /**
* Indicates that the combination of remote InetAddress and SPI was non-unique for a given
* request. If encountered, selection of a new SPI is required before a transform may be
* created. Note, this should happen very rarely if the SPI is chosen to be sufficiently random
@@ -79,42 +103,30 @@
}
}
- private final Context mContext;
- private final INetworkManagementService mService;
+ private final IIpSecService mService;
public static final class SecurityParameterIndex implements AutoCloseable {
- private final Context mContext;
- private final InetAddress mDestinationAddress;
+ private final IIpSecService mService;
+ private final InetAddress mRemoteAddress;
private final CloseGuard mCloseGuard = CloseGuard.get();
- private int mSpi;
+ private int mSpi = INVALID_SECURITY_PARAMETER_INDEX;
+ private int mResourceId;
/** Return the underlying SPI held by this object */
public int getSpi() {
return mSpi;
}
- private SecurityParameterIndex(Context context, InetAddress destinationAddress, int spi)
- throws ResourceUnavailableException, SpiUnavailableException {
- mContext = context;
- mDestinationAddress = destinationAddress;
- mSpi = spi;
- mCloseGuard.open("open");
- }
-
/**
* Release an SPI that was previously reserved.
*
- * <p>Release an SPI for use by other users in the system. This will fail if the SPI is
- * currently in use by an IpSecTransform.
- *
- * @param destinationAddress SPIs must be unique for each combination of SPI and destination
- * address. Thus, the destinationAddress to which the SPI will communicate must be
- * supplied.
- * @param spi the previously reserved SPI to be freed.
+ * <p>Release an SPI for use by other users in the system. If a SecurityParameterIndex is
+ * applied to an IpSecTransform, it will become unusable for future transforms but should
+ * still be closed to ensure system resources are released.
*/
@Override
public void close() {
- mSpi = INVALID_SECURITY_PARAMETER_INDEX; // TODO: Invalid SPI
+ mSpi = INVALID_SECURITY_PARAMETER_INDEX;
mCloseGuard.close();
}
@@ -126,23 +138,61 @@
close();
}
+
+ private SecurityParameterIndex(
+ @NonNull IIpSecService service, int direction, InetAddress remoteAddress, int spi)
+ throws ResourceUnavailableException, SpiUnavailableException {
+ mService = service;
+ mRemoteAddress = remoteAddress;
+ try {
+ Bundle result =
+ mService.reserveSecurityParameterIndex(
+ direction, remoteAddress.getHostAddress(), spi, new Binder());
+
+ if (result == null) {
+ throw new NullPointerException("Received null response from IpSecService");
+ }
+
+ int status = result.getInt(KEY_STATUS);
+ switch (status) {
+ case Status.OK:
+ break;
+ case Status.RESOURCE_UNAVAILABLE:
+ throw new ResourceUnavailableException(
+ "No more SPIs may be allocated by this requester.");
+ case Status.SPI_UNAVAILABLE:
+ throw new SpiUnavailableException("Requested SPI is unavailable", spi);
+ default:
+ throw new RuntimeException(
+ "Unknown status returned by IpSecService: " + status);
+ }
+ mSpi = result.getInt(KEY_SPI);
+ mResourceId = result.getInt(KEY_RESOURCE_ID);
+
+ if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) {
+ throw new RuntimeException("Invalid SPI returned by IpSecService: " + status);
+ }
+
+ if (mResourceId == INVALID_RESOURCE_ID) {
+ throw new RuntimeException(
+ "Invalid Resource ID returned by IpSecService: " + status);
+ }
+
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ mCloseGuard.open("open");
+ }
}
/**
- * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index.
- *
- * <p>No IPsec packet may contain an SPI of 0.
- */
- public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
-
- /**
- * Reserve an SPI for traffic bound towards the specified destination address.
+ * Reserve an SPI for traffic bound towards the specified remote address.
*
* <p>If successful, this SPI is guaranteed available until released by a call to {@link
* SecurityParameterIndex#close()}.
*
- * @param destinationAddress SPIs must be unique for each combination of SPI and destination
- * address.
+ * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT}
+ * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress.
* @param requestedSpi the requested SPI, or '0' to allocate a random SPI.
* @return the reserved SecurityParameterIndex
* @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
@@ -150,9 +200,9 @@
* @throws SpiUnavailableException indicating that a particular SPI cannot be reserved
*/
public SecurityParameterIndex reserveSecurityParameterIndex(
- InetAddress destinationAddress, int requestedSpi)
+ int direction, InetAddress remoteAddress, int requestedSpi)
throws SpiUnavailableException, ResourceUnavailableException {
- return new SecurityParameterIndex(mContext, destinationAddress, requestedSpi);
+ return new SecurityParameterIndex(mService, direction, remoteAddress, requestedSpi);
}
/**
@@ -190,7 +240,13 @@
}
/* Call down to activate a transform */
- private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {}
+ private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {
+ try {
+ mService.applyTransportModeTransform(pfd, transform.getResourceId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
/**
* Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to
@@ -203,7 +259,6 @@
* @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform.
* @hide
*/
- @SystemApi
public void applyTunnelModeTransform(Network net, IpSecTransform transform) {}
/**
@@ -235,7 +290,13 @@
}
/* Call down to activate a transform */
- private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {}
+ private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {
+ try {
+ mService.removeTransportModeTransform(pfd, transform.getResourceId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
/**
* Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of
@@ -248,7 +309,6 @@
* network
* @hide
*/
- @SystemApi
public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
/**
@@ -260,19 +320,19 @@
*/
public static final class UdpEncapsulationSocket implements AutoCloseable {
private final FileDescriptor mFd;
- private final Context mContext;
+ private final IIpSecService mService;
private final CloseGuard mCloseGuard = CloseGuard.get();
- private UdpEncapsulationSocket(Context context, int port)
+ private UdpEncapsulationSocket(@NonNull IIpSecService service, int port)
throws ResourceUnavailableException {
- mContext = context;
+ mService = service;
mCloseGuard.open("constructor");
// TODO: go down to the kernel and get a socket on the specified
mFd = new FileDescriptor();
}
- private UdpEncapsulationSocket(Context context) throws ResourceUnavailableException {
- mContext = context;
+ private UdpEncapsulationSocket(IIpSecService service) throws ResourceUnavailableException {
+ mService = service;
mCloseGuard.open("constructor");
// TODO: go get a random socket on a random port
mFd = new FileDescriptor();
@@ -339,7 +399,7 @@
public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
throws IOException, ResourceUnavailableException {
// Temporary code
- return new UdpEncapsulationSocket(mContext, port);
+ return new UdpEncapsulationSocket(mService, port);
}
/**
@@ -363,7 +423,7 @@
public UdpEncapsulationSocket openUdpEncapsulationSocket()
throws IOException, ResourceUnavailableException {
// Temporary code
- return new UdpEncapsulationSocket(mContext);
+ return new UdpEncapsulationSocket(mService);
}
/**
@@ -372,8 +432,7 @@
* @param context the application context for this manager
* @hide
*/
- public IpSecManager(Context context, INetworkManagementService service) {
- mContext = checkNotNull(context, "missing context");
+ public IpSecManager(IIpSecService service) {
mService = checkNotNull(service, "missing service");
}
}
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index d6dd28be..801e98c 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -15,11 +15,21 @@
*/
package android.net;
+import static android.net.IpSecManager.INVALID_RESOURCE_ID;
+import static android.net.IpSecManager.KEY_RESOURCE_ID;
+import static android.net.IpSecManager.KEY_STATUS;
+
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.Context;
-import android.system.ErrnoException;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
+import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -86,39 +96,64 @@
@Retention(RetentionPolicy.SOURCE)
public @interface EncapType {}
- /**
- * Sentinel for an invalid transform (means that this transform is inactive).
- *
- * @hide
- */
- public static final int INVALID_TRANSFORM_ID = -1;
-
private IpSecTransform(Context context, IpSecConfig config) {
mContext = context;
mConfig = config;
- mTransformId = INVALID_TRANSFORM_ID;
+ mResourceId = INVALID_RESOURCE_ID;
+ }
+
+ private IIpSecService getIpSecService() {
+ IBinder b = ServiceManager.getService(android.content.Context.IPSEC_SERVICE);
+ if (b == null) {
+ throw new RemoteException("Failed to connect to IpSecService")
+ .rethrowAsRuntimeException();
+ }
+
+ return IIpSecService.Stub.asInterface(b);
+ }
+
+ private void checkResultStatusAndThrow(int status)
+ throws IOException, IpSecManager.ResourceUnavailableException,
+ IpSecManager.SpiUnavailableException {
+ switch (status) {
+ case IpSecManager.Status.OK:
+ return;
+ // TODO: Pass Error string back from bundle so that errors can be more specific
+ case IpSecManager.Status.RESOURCE_UNAVAILABLE:
+ throw new IpSecManager.ResourceUnavailableException(
+ "Failed to allocate a new IpSecTransform");
+ case IpSecManager.Status.SPI_UNAVAILABLE:
+ Log.wtf(TAG, "Attempting to use an SPI that was somehow not reserved");
+ // Fall through
+ default:
+ throw new IllegalStateException(
+ "Failed to Create a Transform with status code " + status);
+ }
}
private IpSecTransform activate()
throws IOException, IpSecManager.ResourceUnavailableException,
IpSecManager.SpiUnavailableException {
- int transformId;
synchronized (this) {
- //try {
- transformId = INVALID_TRANSFORM_ID;
- //} catch (RemoteException e) {
- // throw e.rethrowFromSystemServer();
- //}
+ try {
+ IIpSecService svc = getIpSecService();
+ Bundle result = svc.createTransportModeTransform(mConfig, new Binder());
+ int status = result.getInt(KEY_STATUS);
+ checkResultStatusAndThrow(status);
+ mResourceId = result.getInt(KEY_RESOURCE_ID, INVALID_RESOURCE_ID);
- if (transformId < 0) {
- throw new ErrnoException("addTransform", -transformId).rethrowAsIOException();
+ /* Keepalive will silently fail if not needed by the config; but, if needed and
+ * it fails to start, we need to bail because a transform will not be reliable
+ * to use if keepalive is expected to offload and fails.
+ */
+ // FIXME: if keepalive fails, we need to fail spectacularly
+ startKeepalive(mContext);
+ Log.d(TAG, "Added Transform with Id " + mResourceId);
+ mCloseGuard.open("build");
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
}
-
- startKeepalive(mContext); // Will silently fail if not required
- mTransformId = transformId;
- Log.d(TAG, "Added Transform with Id " + transformId);
}
- mCloseGuard.open("build");
return this;
}
@@ -133,21 +168,27 @@
* transform is no longer needed.
*/
public void close() {
- Log.d(TAG, "Removing Transform with Id " + mTransformId);
+ Log.d(TAG, "Removing Transform with Id " + mResourceId);
// Always safe to attempt cleanup
- if (mTransformId == INVALID_TRANSFORM_ID) {
+ if (mResourceId == INVALID_RESOURCE_ID) {
+ mCloseGuard.close();
return;
}
- //try {
- stopKeepalive();
- //} catch (RemoteException e) {
- // transform.setTransformId(transformId);
- // throw e.rethrowFromSystemServer();
- //} finally {
- mTransformId = INVALID_TRANSFORM_ID;
- //}
- mCloseGuard.close();
+ try {
+ /* Order matters here because the keepalive is best-effort but could fail in some
+ * horrible way to be removed if the wifi (or cell) subsystem has crashed, and we
+ * still want to clear out the transform.
+ */
+ IIpSecService svc = getIpSecService();
+ svc.deleteTransportModeTransform(mResourceId);
+ stopKeepalive();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ } finally {
+ mResourceId = INVALID_RESOURCE_ID;
+ mCloseGuard.close();
+ }
}
@Override
@@ -164,7 +205,7 @@
}
private final IpSecConfig mConfig;
- private int mTransformId;
+ private int mResourceId;
private final Context mContext;
private final CloseGuard mCloseGuard = CloseGuard.get();
private ConnectivityManager.PacketKeepalive mKeepalive;
@@ -200,6 +241,7 @@
/* Package */
void startKeepalive(Context c) {
+ // FIXME: NO_KEEPALIVE needs to be a constant
if (mConfig.getNattKeepaliveInterval() == 0) {
return;
}
@@ -208,7 +250,7 @@
(ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
if (mKeepalive != null) {
- Log.e(TAG, "Keepalive already started for this IpSecTransform.");
+ Log.wtf(TAG, "Keepalive already started for this IpSecTransform.");
return;
}
@@ -218,10 +260,11 @@
mConfig.getNetwork(),
mConfig.getNattKeepaliveInterval(),
mKeepaliveCallback,
- mConfig.getLocalIp(),
+ mConfig.getLocalAddress(),
mConfig.getEncapLocalPort(),
- mConfig.getRemoteIp());
+ mConfig.getRemoteAddress());
try {
+ // FIXME: this is still a horrible way to fudge the synchronous callback
mKeepaliveSyncLock.wait(2000);
} catch (InterruptedException e) {
}
@@ -232,6 +275,11 @@
}
/* Package */
+ int getResourceId() {
+ return mResourceId;
+ }
+
+ /* Package */
void stopKeepalive() {
if (mKeepalive == null) {
return;
@@ -247,16 +295,6 @@
}
}
- /* Package */
- void setTransformId(int transformId) {
- mTransformId = transformId;
- }
-
- /* Package */
- int getTransformId() {
- return mTransformId;
- }
-
/**
* Builder object to facilitate the creation of IpSecTransform objects.
*
@@ -280,7 +318,7 @@
*/
public IpSecTransform.Builder setEncryption(
@TransformDirection int direction, IpSecAlgorithm algo) {
- mConfig.flow[direction].encryptionAlgo = algo;
+ mConfig.flow[direction].encryption = algo;
return this;
}
@@ -295,7 +333,7 @@
*/
public IpSecTransform.Builder setAuthentication(
@TransformDirection int direction, IpSecAlgorithm algo) {
- mConfig.flow[direction].authenticationAlgo = algo;
+ mConfig.flow[direction].authentication = algo;
return this;
}
@@ -305,32 +343,9 @@
* given destination address.
*
* <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
- * possible. Random number generation is a reasonable approach to selecting an SPI. For
- * outbound SPIs, they must be reserved by calling {@link
- * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
- * fail to build.
- *
- * <p>Unless an SPI is set for a given direction, traffic in that direction will be
- * sent/received without any IPsec applied.
- *
- * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
- * @param spi a unique 32-bit integer to identify transformed traffic
- */
- public IpSecTransform.Builder setSpi(@TransformDirection int direction, int spi) {
- mConfig.flow[direction].spi = spi;
- return this;
- }
-
- /**
- * Set the SPI, which uniquely identifies a particular IPsec session from others. Because
- * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
- * given destination address.
- *
- * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
- * possible. Random number generation is a reasonable approach to selecting an SPI. For
- * outbound SPIs, they must be reserved by calling {@link
- * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
- * fail to activate.
+ * possible. To reserve a value call {@link IpSecManager#reserveSecurityParameterIndex(int,
+ * InetAddress, int)}. Otherwise, SPI collisions would prevent a transform from being
+ * activated. IpSecManager#reserveSecurityParameterIndex(int, InetAddres$s, int)}.
*
* <p>Unless an SPI is set for a given direction, traffic in that direction will be
* sent/received without any IPsec applied.
@@ -341,6 +356,8 @@
*/
public IpSecTransform.Builder setSpi(
@TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) {
+ // TODO: convert to using the resource Id of the SPI. Then build() can validate
+ // the owner in the IpSecService
mConfig.flow[direction].spi = spi.getSpi();
return this;
}
@@ -447,7 +464,6 @@
* properties is invalid.
* @hide
*/
- @SystemApi
public IpSecTransform buildTunnelModeTransform(
InetAddress localAddress, InetAddress remoteAddress) {
//FIXME: argument validation here
@@ -463,7 +479,8 @@
*
* @param context current Context
*/
- public Builder(Context context) {
+ public Builder(@NonNull Context context) {
+ Preconditions.checkNotNull(context);
mContext = context;
mConfig = new IpSecConfig();
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8349510..4c6d22a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -3313,16 +3313,17 @@
final int wifiScanCount = u.getWifiScanCount(which);
final int wifiScanCountBg = u.getWifiScanBackgroundCount(which);
// Note that 'ActualTime' are unpooled and always since reset (regardless of 'which')
- final long wifiScanActualTime = u.getWifiScanActualTime(rawRealtime);
- final long wifiScanActualTimeBg = u.getWifiScanBackgroundTime(rawRealtime);
+ final long wifiScanActualTimeMs = (u.getWifiScanActualTime(rawRealtime) + 500) / 1000;
+ final long wifiScanActualTimeMsBg = (u.getWifiScanBackgroundTime(rawRealtime) + 500)
+ / 1000;
final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
if (fullWifiLockOnTime != 0 || wifiScanTime != 0 || wifiScanCount != 0
- || wifiScanCountBg != 0 || wifiScanActualTime != 0 || wifiScanActualTimeBg != 0
- || uidWifiRunningTime != 0) {
+ || wifiScanCountBg != 0 || wifiScanActualTimeMs != 0
+ || wifiScanActualTimeMsBg != 0 || uidWifiRunningTime != 0) {
dumpLine(pw, uid, category, WIFI_DATA, fullWifiLockOnTime, wifiScanTime,
uidWifiRunningTime, wifiScanCount,
/* legacy fields follow, keep at 0 */ 0, 0, 0,
- wifiScanCountBg, wifiScanActualTime, wifiScanActualTimeBg);
+ wifiScanCountBg, wifiScanActualTimeMs, wifiScanActualTimeMsBg);
}
dumpControllerActivityLine(pw, uid, category, WIFI_CONTROLLER_DATA,
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index c43019d..717312b 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.service.autofill;
import static android.view.autofill.Helper.DEBUG;
@@ -23,6 +24,7 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.widget.RemoteViews;
@@ -112,7 +114,7 @@
*
* <p>The service could require user authentication at the {@link FillResponse} or the
* {@link Dataset} level, prior to autofilling an activity - see
- * {@link FillResponse.Builder#setAuthentication(IntentSender, RemoteViews)} and
+ * {@link FillResponse.Builder#setAuthentication(AutofillId[], IntentSender, RemoteViews)} and
* {@link Dataset.Builder#setAuthentication(IntentSender)}.
*
* <p>It is recommended that you encrypt only the sensitive data but leave the labels unencrypted
@@ -126,7 +128,7 @@
* possible options) which will start your auth flow and after successfully authenticating
* the user will be presented with the Home and Work options to pick one. Hence, you have
* flexibility how to implement your auth while storing labels non-encrypted and data
- * encrypted provides a better user experience.</p>
+ * encrypted provides a better user experience.
*/
public final class FillResponse implements Parcelable {
@@ -135,6 +137,7 @@
private final Bundle mExtras;
private final RemoteViews mPresentation;
private final IntentSender mAuthentication;
+ private AutofillId[] mAuthenticationIds;
private FillResponse(@NonNull Builder builder) {
mDatasets = builder.mDatasets;
@@ -142,6 +145,7 @@
mExtras = builder.mExtras;
mPresentation = builder.mPresentation;
mAuthentication = builder.mAuthentication;
+ mAuthenticationIds = builder.mAuthenticationIds;
}
/** @hide */
@@ -169,6 +173,11 @@
return mAuthentication;
}
+ /** @hide */
+ public @Nullable AutofillId[] getAuthenticationIds() {
+ return mAuthenticationIds;
+ }
+
/**
* Builder for {@link FillResponse} objects. You must to provide at least
* one dataset or set an authentication intent with a presentation view.
@@ -179,6 +188,7 @@
private Bundle mExtras;
private RemoteViews mPresentation;
private IntentSender mAuthentication;
+ private AutofillId[] mAuthenticationIds;
private boolean mDestroyed;
/**
@@ -193,7 +203,7 @@
* be encrypted. The provided {@link android.app.PendingIntent intent} must be an
* activity which implements your authentication flow. Also if you provide an auth
* intent you also need to specify the presentation view to be shown in the fill UI
- * for the user to trigger your authentication flow.</p>
+ * for the user to trigger your authentication flow.
*
* <p>When a user triggers autofill, the system launches the provided intent
* whose extras will have the {@link AutofillManager#EXTRA_ASSIST_STRUCTURE screen
@@ -205,40 +215,54 @@
* user's data was locked and marked that the response needs an authentication then
* in the response returned if authentication succeeds you need to provide all
* available data sets some of which may need to be further authenticated, for
- * example a credit card whose CVV needs to be entered.</p>
+ * example a credit card whose CVV needs to be entered.
*
* <p>If you provide an authentication intent you must also provide a presentation
* which is used to visualize visualize the response for triggering the authentication
- * flow.</p>
+ * flow.
*
* <p></><strong>Note:</strong> Do not make the provided pending intent
* immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the
- * platform needs to fill in the authentication arguments.</p>
+ * platform needs to fill in the authentication arguments.
*
* @param authentication Intent to an activity with your authentication flow.
* @param presentation The presentation to visualize the response.
- * @return This builder.
+ * @param ids id of Views that when focused will display the authentication UI affordance.
*
+ * @return This builder.
* @see android.app.PendingIntent#getIntentSender()
*/
- public @NonNull Builder setAuthentication(@Nullable IntentSender authentication,
- @Nullable RemoteViews presentation) {
+ public @NonNull Builder setAuthentication(@NonNull AutofillId[] ids,
+ @Nullable IntentSender authentication, @Nullable RemoteViews presentation) {
throwIfDestroyed();
+ // TODO(b/33197203): assert ids is not null nor empty once old version is removed
if (authentication == null ^ presentation == null) {
throw new IllegalArgumentException("authentication and presentation"
+ " must be both non-null or null");
}
mAuthentication = authentication;
mPresentation = presentation;
+ mAuthenticationIds = ids;
return this;
}
/**
+ * TODO(b/33197203): will be removed once clients use the version that takes ids
+ * @hide
+ * @deprecated
+ */
+ @Deprecated
+ public @NonNull Builder setAuthentication(@Nullable IntentSender authentication,
+ @Nullable RemoteViews presentation) {
+ return setAuthentication(null, authentication, presentation);
+ }
+
+ /**
* Adds a new {@link Dataset} to this response.
*
* @return This builder.
*/
- public@NonNull Builder addDataset(@Nullable Dataset dataset) {
+ public @NonNull Builder addDataset(@Nullable Dataset dataset) {
throwIfDestroyed();
if (dataset == null) {
return this;
@@ -282,6 +306,7 @@
return this;
}
+
/**
* Builds a new {@link FillResponse} instance. You must provide at least
* one dataset or some savable ids or an authentication with a presentation
@@ -308,7 +333,7 @@
}
/////////////////////////////////////
- // Object "contract" methods. //
+ // Object "contract" methods. //
/////////////////////////////////////
@Override
public String toString() {
@@ -320,11 +345,13 @@
.append(", hasExtras=").append(mExtras != null)
.append(", hasPresentation=").append(mPresentation != null)
.append(", hasAuthentication=").append(mAuthentication != null)
+ .append(", authenticationSize=").append(mAuthenticationIds != null
+ ? mAuthenticationIds.length : "N/A")
.toString();
}
/////////////////////////////////////
- // Parcelable "contract" methods. //
+ // Parcelable "contract" methods. //
/////////////////////////////////////
@Override
@@ -337,6 +364,7 @@
parcel.writeTypedArrayList(mDatasets, flags);
parcel.writeParcelable(mSaveInfo, flags);
parcel.writeParcelable(mExtras, flags);
+ parcel.writeParcelableArray(mAuthenticationIds, flags);
parcel.writeParcelable(mAuthentication, flags);
parcel.writeParcelable(mPresentation, flags);
}
@@ -356,8 +384,8 @@
}
builder.setSaveInfo(parcel.readParcelable(null));
builder.setExtras(parcel.readParcelable(null));
- builder.setAuthentication(parcel.readParcelable(null),
- parcel.readParcelable(null));
+ builder.setAuthentication(parcel.readParcelableArray(null, AutofillId.class),
+ parcel.readParcelable(null), parcel.readParcelable(null));
return builder.build();
}
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 95608a5..f75b7af 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -129,6 +129,16 @@
*/
public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3;
+ /**
+ * Type used when the {@link FillResponse} represents just an username, without a password.
+ */
+ public static final int SAVE_DATA_TYPE_USERNAME = 4;
+
+ /**
+ * Type used when the {@link FillResponse} represents just an email address, without a password.
+ */
+ public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 5;
+
private final @SaveDataType int mType;
private final CharSequence mNegativeActionTitle;
private final IntentSender mNegativeActionListener;
@@ -222,6 +232,8 @@
case SAVE_DATA_TYPE_PASSWORD:
case SAVE_DATA_TYPE_ADDRESS:
case SAVE_DATA_TYPE_CREDIT_CARD:
+ case SAVE_DATA_TYPE_USERNAME:
+ case SAVE_DATA_TYPE_EMAIL_ADDRESS:
mType = type;
break;
default:
diff --git a/core/java/android/text/method/DateKeyListener.java b/core/java/android/text/method/DateKeyListener.java
index e14cd2c..0accbf6 100644
--- a/core/java/android/text/method/DateKeyListener.java
+++ b/core/java/android/text/method/DateKeyListener.java
@@ -22,6 +22,7 @@
import android.view.KeyEvent;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
import java.util.HashMap;
import java.util.LinkedHashSet;
@@ -37,8 +38,11 @@
public class DateKeyListener extends NumberKeyListener
{
public int getInputType() {
- return InputType.TYPE_CLASS_DATETIME
- | InputType.TYPE_DATETIME_VARIATION_DATE;
+ if (mNeedsAdvancedInput) {
+ return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ } else {
+ return InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE;
+ }
}
@Override
@@ -65,7 +69,13 @@
final boolean success = NumberKeyListener.addDigits(chars, locale)
&& NumberKeyListener.addFormatCharsFromSkeletons(
chars, locale, SKELETONS, SYMBOLS_TO_IGNORE);
- mCharacters = success ? NumberKeyListener.collectionToArray(chars) : CHARACTERS;
+ if (success) {
+ mCharacters = NumberKeyListener.collectionToArray(chars);
+ mNeedsAdvancedInput = !ArrayUtils.containsAll(CHARACTERS, mCharacters);
+ } else {
+ mCharacters = CHARACTERS;
+ mNeedsAdvancedInput = false;
+ }
}
/**
@@ -110,6 +120,7 @@
};
private final char[] mCharacters;
+ private final boolean mNeedsAdvancedInput;
private static final Object sLock = new Object();
@GuardedBy("sLock")
diff --git a/core/java/android/text/method/DateTimeKeyListener.java b/core/java/android/text/method/DateTimeKeyListener.java
index 62e3ade..551db55 100644
--- a/core/java/android/text/method/DateTimeKeyListener.java
+++ b/core/java/android/text/method/DateTimeKeyListener.java
@@ -22,6 +22,7 @@
import android.view.KeyEvent;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
import java.util.HashMap;
import java.util.LinkedHashSet;
@@ -37,10 +38,13 @@
public class DateTimeKeyListener extends NumberKeyListener
{
public int getInputType() {
- return InputType.TYPE_CLASS_DATETIME
- | InputType.TYPE_DATETIME_VARIATION_NORMAL;
+ if (mNeedsAdvancedInput) {
+ return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ } else {
+ return InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_NORMAL;
+ }
}
-
+
@Override
@NonNull
protected char[] getAcceptedChars()
@@ -70,7 +74,13 @@
chars, locale, SKELETON_12HOUR, SYMBOLS_TO_IGNORE)
&& NumberKeyListener.addFormatCharsFromSkeleton(
chars, locale, SKELETON_24HOUR, SYMBOLS_TO_IGNORE);
- mCharacters = success ? NumberKeyListener.collectionToArray(chars) : CHARACTERS;
+ if (success) {
+ mCharacters = NumberKeyListener.collectionToArray(chars);
+ mNeedsAdvancedInput = !ArrayUtils.containsAll(CHARACTERS, mCharacters);
+ } else {
+ mCharacters = CHARACTERS;
+ mNeedsAdvancedInput = false;
+ }
}
/**
@@ -114,6 +124,7 @@
};
private final char[] mCharacters;
+ private final boolean mNeedsAdvancedInput;
private static final Object sLock = new Object();
@GuardedBy("sLock")
diff --git a/core/java/android/text/method/DigitsKeyListener.java b/core/java/android/text/method/DigitsKeyListener.java
index 26c69ab..d9f2dcf 100644
--- a/core/java/android/text/method/DigitsKeyListener.java
+++ b/core/java/android/text/method/DigitsKeyListener.java
@@ -27,6 +27,7 @@
import android.view.KeyEvent;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
import java.util.HashMap;
import java.util.LinkedHashSet;
@@ -42,8 +43,12 @@
public class DigitsKeyListener extends NumberKeyListener
{
private char[] mAccepted;
+ private boolean mNeedsAdvancedInput;
private final boolean mSign;
private final boolean mDecimal;
+ private final boolean mStringMode;
+ @Nullable
+ private final Locale mLocale;
private static final String DEFAULT_DECIMAL_POINT_CHARS = ".";
private static final String DEFAULT_SIGN_CHARS = "-+";
@@ -112,11 +117,17 @@
this(locale, false, false);
}
- private void setToCompat(boolean sign, boolean decimal) {
+ private void setToCompat() {
mDecimalPointChars = DEFAULT_DECIMAL_POINT_CHARS;
mSignChars = DEFAULT_SIGN_CHARS;
- final int kind = (sign ? SIGN : 0) | (decimal ? DECIMAL : 0);
+ final int kind = (mSign ? SIGN : 0) | (mDecimal ? DECIMAL : 0);
mAccepted = COMPATIBILITY_CHARACTERS[kind];
+ mNeedsAdvancedInput = false;
+ }
+
+ private void calculateNeedForAdvancedInput() {
+ final int kind = (mSign ? SIGN : 0) | (mDecimal ? DECIMAL : 0);
+ mNeedsAdvancedInput = !ArrayUtils.containsAll(COMPATIBILITY_CHARACTERS[kind], mAccepted);
}
// Takes a sign string and strips off its bidi controls, if any.
@@ -144,14 +155,16 @@
public DigitsKeyListener(@Nullable Locale locale, boolean sign, boolean decimal) {
mSign = sign;
mDecimal = decimal;
+ mStringMode = false;
+ mLocale = locale;
if (locale == null) {
- setToCompat(sign, decimal);
+ setToCompat();
return;
}
LinkedHashSet<Character> chars = new LinkedHashSet<>();
final boolean success = NumberKeyListener.addDigits(chars, locale);
if (!success) {
- setToCompat(sign, decimal);
+ setToCompat();
return;
}
if (sign || decimal) {
@@ -161,7 +174,7 @@
final String plusString = stripBidiControls(symbols.getPlusSignString());
if (minusString.length() > 1 || plusString.length() > 1) {
// non-BMP and multi-character signs are not supported.
- setToCompat(sign, decimal);
+ setToCompat();
return;
}
final char minus = minusString.charAt(0);
@@ -181,7 +194,7 @@
final String separatorString = symbols.getDecimalSeparatorString();
if (separatorString.length() > 1) {
// non-BMP and multi-character decimal separators are not supported.
- setToCompat(sign, decimal);
+ setToCompat();
return;
}
final Character separatorChar = Character.valueOf(separatorString.charAt(0));
@@ -190,13 +203,19 @@
}
}
mAccepted = NumberKeyListener.collectionToArray(chars);
+ calculateNeedForAdvancedInput();
}
private DigitsKeyListener(@NonNull final String accepted) {
mSign = false;
mDecimal = false;
+ mStringMode = true;
+ mLocale = null;
mAccepted = new char[accepted.length()];
accepted.getChars(0, accepted.length(), mAccepted, 0);
+ // Theoretically we may need advanced input, but for backward compatibility, we don't change
+ // the input type.
+ mNeedsAdvancedInput = false;
}
/**
@@ -280,13 +299,38 @@
return result;
}
- public int getInputType() {
- int contentType = InputType.TYPE_CLASS_NUMBER;
- if (mSign) {
- contentType |= InputType.TYPE_NUMBER_FLAG_SIGNED;
+ /**
+ * Returns a DigitsKeyListener based on an the settings of a existing DigitsKeyListener, with
+ * the locale modified.
+ *
+ * @hide
+ */
+ @NonNull
+ public static DigitsKeyListener getInstance(
+ @Nullable Locale locale,
+ @NonNull DigitsKeyListener listener) {
+ if (listener.mStringMode) {
+ return listener; // string-mode DigitsKeyListeners have no locale.
+ } else {
+ return getInstance(locale, listener.mSign, listener.mDecimal);
}
- if (mDecimal) {
- contentType |= InputType.TYPE_NUMBER_FLAG_DECIMAL;
+ }
+
+ /**
+ * Returns the input type for the listener.
+ */
+ public int getInputType() {
+ int contentType;
+ if (mNeedsAdvancedInput) {
+ contentType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ } else {
+ contentType = InputType.TYPE_CLASS_NUMBER;
+ if (mSign) {
+ contentType |= InputType.TYPE_NUMBER_FLAG_SIGNED;
+ }
+ if (mDecimal) {
+ contentType |= InputType.TYPE_NUMBER_FLAG_DECIMAL;
+ }
}
return contentType;
}
diff --git a/core/java/android/text/method/TimeKeyListener.java b/core/java/android/text/method/TimeKeyListener.java
index c9f9f9f..5b1db11 100644
--- a/core/java/android/text/method/TimeKeyListener.java
+++ b/core/java/android/text/method/TimeKeyListener.java
@@ -22,6 +22,7 @@
import android.view.KeyEvent;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
import java.util.HashMap;
import java.util.LinkedHashSet;
@@ -37,8 +38,11 @@
public class TimeKeyListener extends NumberKeyListener
{
public int getInputType() {
- return InputType.TYPE_CLASS_DATETIME
- | InputType.TYPE_DATETIME_VARIATION_TIME;
+ if (mNeedsAdvancedInput) {
+ return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ } else {
+ return InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_TIME;
+ }
}
@Override
@@ -70,7 +74,13 @@
chars, locale, SKELETON_12HOUR, SYMBOLS_TO_IGNORE)
&& NumberKeyListener.addFormatCharsFromSkeleton(
chars, locale, SKELETON_24HOUR, SYMBOLS_TO_IGNORE);
- mCharacters = success ? NumberKeyListener.collectionToArray(chars) : CHARACTERS;
+ if (success) {
+ mCharacters = NumberKeyListener.collectionToArray(chars);
+ mNeedsAdvancedInput = !ArrayUtils.containsAll(CHARACTERS, mCharacters);
+ } else {
+ mCharacters = CHARACTERS;
+ mNeedsAdvancedInput = false;
+ }
}
/**
@@ -114,6 +124,7 @@
};
private final char[] mCharacters;
+ private final boolean mNeedsAdvancedInput;
private static final Object sLock = new Object();
@GuardedBy("sLock")
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1b60ebc..7d9253b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -598,6 +598,11 @@
private Layout mLayout;
private boolean mLocalesChanged = false;
+ // True if setKeyListener() has been explicitly called
+ private boolean mListenerChanged = false;
+ // True if internationalized input should be used for numbers and date and time.
+ private final boolean mUseInternationalizedInput;
+
@ViewDebug.ExportedProperty(category = "text")
private int mGravity = Gravity.TOP | Gravity.START;
private boolean mHorizontallyScrolling;
@@ -1356,6 +1361,9 @@
final boolean numberPasswordInputType = variation
== (EditorInfo.TYPE_CLASS_NUMBER | EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD);
+ mUseInternationalizedInput =
+ context.getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O;
+
if (inputMethod != null) {
Class<?> c;
@@ -1398,15 +1406,11 @@
mEditor.mInputType = inputType = EditorInfo.TYPE_CLASS_PHONE;
} else if (numeric != 0) {
createEditorIfNeeded();
- mEditor.mKeyListener = DigitsKeyListener.getInstance((numeric & SIGNED) != 0,
- (numeric & DECIMAL) != 0);
- inputType = EditorInfo.TYPE_CLASS_NUMBER;
- if ((numeric & SIGNED) != 0) {
- inputType |= EditorInfo.TYPE_NUMBER_FLAG_SIGNED;
- }
- if ((numeric & DECIMAL) != 0) {
- inputType |= EditorInfo.TYPE_NUMBER_FLAG_DECIMAL;
- }
+ mEditor.mKeyListener = DigitsKeyListener.getInstance(
+ mUseInternationalizedInput ? getTextLocale() : null,
+ (numeric & SIGNED) != 0,
+ (numeric & DECIMAL) != 0);
+ inputType = mEditor.mKeyListener.getInputType();
mEditor.mInputType = inputType;
} else if (autotext || autocap != -1) {
TextKeyListener.Capitalize cap;
@@ -2308,19 +2312,13 @@
* @attr ref android.R.styleable#TextView_autoText
*/
public void setKeyListener(KeyListener input) {
+ mListenerChanged = true;
setKeyListenerOnly(input);
fixFocusableAndClickableSettings();
if (input != null) {
createEditorIfNeeded();
- try {
- mEditor.mInputType = mEditor.mKeyListener.getInputType();
- } catch (IncompatibleClassChangeError e) {
- mEditor.mInputType = EditorInfo.TYPE_CLASS_TEXT;
- }
- // Change inputType, without affecting transformation.
- // No need to applySingleLine since mSingleLine is unchanged.
- setInputTypeSingleLine(mSingleLine);
+ setInputTypeFromEditor();
} else {
if (mEditor != null) mEditor.mInputType = EditorInfo.TYPE_NULL;
}
@@ -2329,6 +2327,17 @@
if (imm != null) imm.restartInput(this);
}
+ private void setInputTypeFromEditor() {
+ try {
+ mEditor.mInputType = mEditor.mKeyListener.getInputType();
+ } catch (IncompatibleClassChangeError e) {
+ mEditor.mInputType = EditorInfo.TYPE_CLASS_TEXT;
+ }
+ // Change inputType, without affecting transformation.
+ // No need to applySingleLine since mSingleLine is unchanged.
+ setInputTypeSingleLine(mSingleLine);
+ }
+
private void setKeyListenerOnly(KeyListener input) {
if (mEditor == null && input == null) return; // null is the default value
@@ -3390,6 +3399,29 @@
return mTextPaint.getTextLocales();
}
+ private void changeListenerLocaleTo(@NonNull Locale locale) {
+ if (mListenerChanged) {
+ // If a listener has been explicitly set, don't change it. We may break something.
+ return;
+ }
+ if (mEditor != null) {
+ KeyListener listener = mEditor.mKeyListener;
+ if (listener instanceof DigitsKeyListener) {
+ listener = DigitsKeyListener.getInstance(locale, (DigitsKeyListener) listener);
+ } else if (listener instanceof DateKeyListener) {
+ listener = DateKeyListener.getInstance(locale);
+ } else if (listener instanceof TimeKeyListener) {
+ listener = TimeKeyListener.getInstance(locale);
+ } else if (listener instanceof DateTimeKeyListener) {
+ listener = DateTimeKeyListener.getInstance(locale);
+ } else {
+ return;
+ }
+ setKeyListenerOnly(listener);
+ setInputTypeFromEditor();
+ }
+ }
+
/**
* Set the default {@link LocaleList} of the text in this TextView to a one-member list
* containing just the given value.
@@ -3401,6 +3433,7 @@
public void setTextLocale(@NonNull Locale locale) {
mLocalesChanged = true;
mTextPaint.setTextLocale(locale);
+ changeListenerLocaleTo(locale);
if (mLayout != null) {
nullLayouts();
requestLayout();
@@ -3422,6 +3455,7 @@
public void setTextLocales(@NonNull @Size(min = 1) LocaleList locales) {
mLocalesChanged = true;
mTextPaint.setTextLocales(locales);
+ changeListenerLocaleTo(locales.get(0));
if (mLayout != null) {
nullLayouts();
requestLayout();
@@ -3433,7 +3467,9 @@
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (!mLocalesChanged) {
- mTextPaint.setTextLocales(LocaleList.getDefault());
+ final LocaleList locales = LocaleList.getDefault();
+ mTextPaint.setTextLocales(locales);
+ changeListenerLocaleTo(locales.get(0));
if (mLayout != null) {
nullLayouts();
requestLayout();
@@ -5567,26 +5603,35 @@
input = TextKeyListener.getInstance(autotext, cap);
} else if (cls == EditorInfo.TYPE_CLASS_NUMBER) {
input = DigitsKeyListener.getInstance(
+ mUseInternationalizedInput ? getTextLocale() : null,
(type & EditorInfo.TYPE_NUMBER_FLAG_SIGNED) != 0,
(type & EditorInfo.TYPE_NUMBER_FLAG_DECIMAL) != 0);
+ if (mUseInternationalizedInput) {
+ type = input.getInputType(); // Override type, if necessary for i18n.
+ }
} else if (cls == EditorInfo.TYPE_CLASS_DATETIME) {
+ final Locale locale = mUseInternationalizedInput ? getTextLocale() : null;
switch (type & EditorInfo.TYPE_MASK_VARIATION) {
case EditorInfo.TYPE_DATETIME_VARIATION_DATE:
- input = DateKeyListener.getInstance();
+ input = DateKeyListener.getInstance(locale);
break;
case EditorInfo.TYPE_DATETIME_VARIATION_TIME:
- input = TimeKeyListener.getInstance();
+ input = TimeKeyListener.getInstance(locale);
break;
default:
- input = DateTimeKeyListener.getInstance();
+ input = DateTimeKeyListener.getInstance(locale);
break;
}
+ if (mUseInternationalizedInput) {
+ type = input.getInputType(); // Override type, if necessary for i18n.
+ }
} else if (cls == EditorInfo.TYPE_CLASS_PHONE) {
input = DialerKeyListener.getInstance();
} else {
input = TextKeyListener.getInstance();
}
setRawInputType(type);
+ mListenerChanged = false;
if (direct) {
createEditorIfNeeded();
mEditor.mKeyListener = input;
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index f4dd5a6..2c8e4e0 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -236,6 +236,29 @@
return false;
}
+ public static boolean contains(@Nullable char[] array, char value) {
+ if (array == null) return false;
+ for (char element : array) {
+ if (element == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Test if all {@code check} items are contained in {@code array}.
+ */
+ public static <T> boolean containsAll(@Nullable char[] array, char[] check) {
+ if (check == null) return true;
+ for (char checkItem : check) {
+ if (!contains(array, checkItem)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static long total(@Nullable long[] array) {
long total = 0;
if (array != null) {
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index dae4310..520302e 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -282,6 +282,25 @@
return mgr->configureDirectChannel(channelHandle, sensorHandle, rate);
}
+static jint nativeSetOperationParameter(JNIEnv *_env, jclass _this, jlong sensorManager,
+ jint type, jfloatArray floats, jintArray ints) {
+ SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
+ Vector<float> floatVector;
+ Vector<int32_t> int32Vector;
+
+ if (floats != nullptr) {
+ floatVector.resize(_env->GetArrayLength(floats));
+ _env->GetFloatArrayRegion(floats, 0, _env->GetArrayLength(floats), floatVector.editArray());
+ }
+
+ if (ints != nullptr) {
+ int32Vector.resize(_env->GetArrayLength(ints));
+ _env->GetIntArrayRegion(ints, 0, _env->GetArrayLength(ints), int32Vector.editArray());
+ }
+
+ return mgr->setOperationParameter(type, floatVector, int32Vector);
+}
+
//----------------------------------------------------------------------------
class Receiver : public LooperCallback {
@@ -499,6 +518,10 @@
{"nativeConfigDirectChannel",
"(JIII)I",
(void*)nativeConfigDirectChannel },
+
+ {"nativeSetOperationParameter",
+ "(JI[F[I)I",
+ (void*)nativeSetOperationParameter },
};
static const JNINativeMethod gBaseEventQueueMethods[] = {
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bf2f355..459b48f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4602,6 +4602,10 @@
<string name="autofill_save_type_address">address</string>
<!-- Label for the type of data being saved for autofill when it represents a credit card [CHAR LIMIT=NONE] -->
<string name="autofill_save_type_credit_card">credit card</string>
+ <!-- Label for the type of data being saved for autofill when it represents an username [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_type_username">username</string>
+ <!-- Label for the type of data being saved for autofill when it represents an email address [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_type_email_address">email address</string>
<!-- Primary ETWS (Earthquake and Tsunami Warning System) default message for earthquake -->
<string name="etws_primary_default_message_earthquake">Stay calm and seek shelter nearby.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c12116a..fa13fbf 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2883,6 +2883,8 @@
<java-symbol type="string" name="autofill_save_type_password" />
<java-symbol type="string" name="autofill_save_type_address" />
<java-symbol type="string" name="autofill_save_type_credit_card" />
+ <java-symbol type="string" name="autofill_save_type_username" />
+ <java-symbol type="string" name="autofill_save_type_email_address" />
<!-- Accessibility fingerprint gestures -->
<java-symbol type="string" name="capability_title_canCaptureFingerprintGestures" />
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 23bf3d6..431d5d8 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -34,6 +34,7 @@
libutils \
libbinder \
libmedia \
+ libmediametrics \
libmediadrm \
libmidi \
libskia \
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 2e6ed69b..63850ae 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -149,6 +149,12 @@
<!-- Description of printer info icon. [CHAR LIMIT=50] -->
<string name="printer_info_desc">More information about this printer</string>
+ <!-- Label for the notification channel that contains print jobs without problems. [CHAR LIMIT=40] -->
+ <string name="notification_channel_progress">Running print jobs</string>
+
+ <!-- Label for the notification channel that contains print jobs with problems. [CHAR LIMIT=40] -->
+ <string name="notification_channel_failure">Failed print jobs</string>
+
<!-- Notification that we could not create a file name for the printed PDF. [CHAR LIMIT=50] -->
<string name="could_not_create_file">Could not create file</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
index cd1d540..9d737e0 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
@@ -20,13 +20,12 @@
import android.annotation.Nullable;
import android.app.Notification;
import android.app.Notification.Action;
-import android.app.Notification.InboxStyle;
+import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.AsyncTask;
@@ -57,14 +56,14 @@
public static final String LOG_TAG = "NotificationController";
+ private static final String NOTIFICATION_CHANNEL_PROGRESS = "PRINT_PROGRESS";
+ private static final String NOTIFICATION_CHANNEL_FAILURES = "PRINT_FAILURES";
+
private static final String INTENT_ACTION_CANCEL_PRINTJOB = "INTENT_ACTION_CANCEL_PRINTJOB";
private static final String INTENT_ACTION_RESTART_PRINTJOB = "INTENT_ACTION_RESTART_PRINTJOB";
private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
- private static final String PRINT_JOB_NOTIFICATION_GROUP_KEY = "PRINT_JOB_NOTIFICATIONS";
- private static final String PRINT_JOB_NOTIFICATION_SUMMARY = "PRINT_JOB_NOTIFICATIONS_SUMMARY";
-
private final Context mContext;
private final NotificationManager mNotificationManager;
@@ -78,6 +77,15 @@
mNotificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mNotifications = new ArraySet<>(0);
+
+ mNotificationManager.createNotificationChannel(
+ new NotificationChannel(NOTIFICATION_CHANNEL_PROGRESS,
+ context.getString(R.string.notification_channel_progress),
+ NotificationManager.IMPORTANCE_LOW));
+ mNotificationManager.createNotificationChannel(
+ new NotificationChannel(NOTIFICATION_CHANNEL_FAILURES,
+ context.getString(R.string.notification_channel_failure),
+ NotificationManager.IMPORTANCE_DEFAULT));
}
public void onUpdateNotifications(List<PrintJobInfo> printJobs) {
@@ -104,13 +112,6 @@
final int numPrintJobs = printJobs.size();
- // Create summary notification
- if (numPrintJobs > 1) {
- createStackedNotification(printJobs);
- } else {
- mNotificationManager.cancel(PRINT_JOB_NOTIFICATION_SUMMARY, 0);
- }
-
// Create per print job notification
for (int i = 0; i < numPrintJobs; i++) {
PrintJobInfo printJob = printJobs.get(i);
@@ -178,16 +179,16 @@
*/
private void createNotification(@NonNull PrintJobInfo printJob, @Nullable Action firstAction,
@Nullable Action secondAction) {
- Notification.Builder builder = new Notification.Builder(mContext)
+ Notification.Builder builder = new Notification.Builder(mContext, computeChannel(printJob))
.setContentIntent(createContentIntent(printJob.getId()))
.setSmallIcon(computeNotificationIcon(printJob))
.setContentTitle(computeNotificationTitle(printJob))
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true)
+ .setOnlyAlertOnce(true)
.setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setGroup(PRINT_JOB_NOTIFICATION_GROUP_KEY);
+ com.android.internal.R.color.system_notification_accent_color));
if (firstAction != null) {
builder.addAction(firstAction);
@@ -238,43 +239,6 @@
createNotification(printJob, null, null);
}
- private void createStackedNotification(List<PrintJobInfo> printJobs) {
- Notification.Builder builder = new Notification.Builder(mContext)
- .setContentIntent(createContentIntent(null))
- .setWhen(System.currentTimeMillis())
- .setOngoing(true)
- .setShowWhen(true)
- .setGroup(PRINT_JOB_NOTIFICATION_GROUP_KEY)
- .setGroupSummary(true);
-
- final int printJobCount = printJobs.size();
-
- InboxStyle inboxStyle = new InboxStyle();
-
- int icon = com.android.internal.R.drawable.ic_print;
- for (int i = printJobCount - 1; i>= 0; i--) {
- PrintJobInfo printJob = printJobs.get(i);
-
- inboxStyle.addLine(computeNotificationTitle(printJob));
-
- // if any print job is in an error state show an error icon for the summary
- if (printJob.getState() == PrintJobInfo.STATE_FAILED
- || printJob.getState() == PrintJobInfo.STATE_BLOCKED) {
- icon = com.android.internal.R.drawable.ic_print_error;
- }
- }
-
- builder.setSmallIcon(icon);
- builder.setLargeIcon(
- ((BitmapDrawable) mContext.getResources().getDrawable(icon, null)).getBitmap());
- builder.setNumber(printJobCount);
- builder.setStyle(inboxStyle);
- builder.setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
-
- mNotificationManager.notify(PRINT_JOB_NOTIFICATION_SUMMARY, 0, builder.build());
- }
-
private String computeNotificationTitle(PrintJobInfo printJob) {
switch (printJob.getState()) {
case PrintJobInfo.STATE_FAILED: {
@@ -359,6 +323,22 @@
}
}
+ private static String computeChannel(PrintJobInfo printJob) {
+ if (printJob.isCancelling()) {
+ return NOTIFICATION_CHANNEL_PROGRESS;
+ }
+
+ switch (printJob.getState()) {
+ case PrintJobInfo.STATE_FAILED:
+ case PrintJobInfo.STATE_BLOCKED: {
+ return NOTIFICATION_CHANNEL_FAILURES;
+ }
+ default: {
+ return NOTIFICATION_CHANNEL_PROGRESS;
+ }
+ }
+ }
+
public static final class NotificationBroadcastReceiver extends BroadcastReceiver {
@SuppressWarnings("hiding")
private static final String LOG_TAG = "NotificationBroadcastReceiver";
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 1ea4183..901848a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -149,6 +149,7 @@
private int mRankingScore = Integer.MIN_VALUE;
private int mBadge = NetworkBadging.BADGING_NONE;
+ private boolean mIsScoredNetworkMetered = false;
// used to co-relate internal vs returned accesspoint.
int mId;
@@ -248,6 +249,7 @@
this.mScanResultCache.putAll(that.mScanResultCache);
this.mId = that.mId;
this.mBadge = that.mBadge;
+ this.mIsScoredNetworkMetered = that.mIsScoredNetworkMetered;
this.mRankingScore = that.mRankingScore;
}
@@ -336,16 +338,32 @@
builder.append(",level=").append(getLevel());
builder.append(",rankingScore=").append(mRankingScore);
builder.append(",badge=").append(mBadge);
+ builder.append(",metered=").append(isMetered());
return builder.append(')').toString();
}
/**
+ * Updates the AccessPoint rankingScore, metering, and badge, returning true if the data has
+ * changed.
+ *
+ * @param scoreCache The score cache to use to retrieve scores.
+ * @param scoringUiEnabled Whether to show scoring and badging UI.
+ */
+ boolean update(WifiNetworkScoreCache scoreCache, boolean scoringUiEnabled) {
+ boolean scoreChanged = false;
+ if (scoringUiEnabled) {
+ scoreChanged = updateScores(scoreCache);
+ }
+ return updateMetered(scoreCache) || scoreChanged;
+ }
+
+ /**
* Updates the AccessPoint rankingScore and badge, returning true if the data has changed.
*
* @param scoreCache The score cache to use to retrieve scores.
*/
- boolean updateScores(WifiNetworkScoreCache scoreCache) {
+ private boolean updateScores(WifiNetworkScoreCache scoreCache) {
int oldBadge = mBadge;
int oldRankingScore = mRankingScore;
mBadge = NetworkBadging.BADGING_NONE;
@@ -366,6 +384,23 @@
return (oldBadge != mBadge || oldRankingScore != mRankingScore);
}
+ /**
+ * Updates the AccessPoint's metering based on {@link ScoredNetwork#meteredHint}, returning
+ * true if the metering changed.
+ */
+ private boolean updateMetered(WifiNetworkScoreCache scoreCache) {
+ boolean oldMetering = mIsScoredNetworkMetered;
+ mIsScoredNetworkMetered = false;
+ for (ScanResult result : mScanResultCache.values()) {
+ ScoredNetwork score = scoreCache.getScoredNetwork(result);
+ if (score == null) {
+ continue;
+ }
+ mIsScoredNetworkMetered |= score.meteredHint;
+ }
+ return oldMetering == mIsScoredNetworkMetered;
+ }
+
private void evictOldScanResults() {
long nowMs = SystemClock.elapsedRealtime();
for (Iterator<ScanResult> iter = mScanResultCache.values().iterator(); iter.hasNext(); ) {
@@ -474,6 +509,17 @@
mSeen = seen;
}
+ /**
+ * Returns if the network is marked metered. Metering can be marked through its config in
+ * {@link WifiConfiguration}, after connection in {@link WifiInfo}, or from a score config in
+ * {@link ScoredNetwork}.
+ */
+ public boolean isMetered() {
+ return mIsScoredNetworkMetered
+ || (mConfig != null && mConfig.meteredHint)
+ || (mInfo != null && mInfo.getMeteredHint());
+ }
+
public NetworkInfo getNetworkInfo() {
return mNetworkInfo;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index 8f8167e..e82bf81 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -183,7 +183,7 @@
}
if (mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
mFrictionSld.setState(STATE_SECURED);
- } else if (mAccessPoint.getConfig() != null && mAccessPoint.getConfig().meteredHint) {
+ } else if (mAccessPoint.isMetered()) {
mFrictionSld.setState(STATE_METERED);
}
Drawable drawable = mFrictionSld.getCurrent();
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 50f294c..fc8c42c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -543,11 +543,9 @@
}
}
- if (mNetworkScoringUiEnabled) {
- requestScoresForNetworkKeys(scoresToRequest);
- for (AccessPoint ap : accessPoints) {
- ap.updateScores(mScoreCache);
- }
+ requestScoresForNetworkKeys(scoresToRequest);
+ for (AccessPoint ap : accessPoints) {
+ ap.update(mScoreCache, mNetworkScoringUiEnabled);
}
// Pre-sort accessPoints to speed preference insertion
@@ -648,7 +646,7 @@
if (ap.update(connectionConfig, mLastInfo, mLastNetworkInfo)) {
reorder = true;
}
- if (mNetworkScoringUiEnabled && ap.updateScores(mScoreCache)) {
+ if (ap.update(mScoreCache, mNetworkScoringUiEnabled)) {
reorder = true;
}
}
@@ -659,15 +657,11 @@
}
/**
- * Update all the internal access points rankingScores and badge.
+ * Update all the internal access points rankingScores, badge and metering.
*
* <p>Will trigger a resort and notify listeners of changes if applicable.
*/
private void updateNetworkScores() {
- if (!mNetworkScoringUiEnabled) {
- return;
- }
-
// Lock required to prevent accidental copying of AccessPoint states while the modification
// is in progress. see #copyAndNotifyListeners
long before = System.currentTimeMillis();
@@ -679,7 +673,7 @@
boolean reorder = false;
for (int i = 0; i < mInternalAccessPoints.size(); i++) {
- if (mInternalAccessPoints.get(i).updateScores(mScoreCache)) {
+ if (mInternalAccessPoints.get(i).update(mScoreCache, mNetworkScoringUiEnabled)) {
reorder = true;
}
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 762d9f8..3e01b34 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -17,15 +17,19 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
+import android.net.NetworkKey;
+import android.net.ScoredNetwork;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.WifiSsid;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.hotspot2.pps.HomeSp;
@@ -36,10 +40,11 @@
import android.support.test.runner.AndroidJUnit4;
import android.text.SpannableString;
import android.text.style.TtsSpan;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Collections;
@@ -50,9 +55,11 @@
private static final String TEST_SSID = "test_ssid";
private Context mContext;
+ @Mock private WifiNetworkScoreCache mWifiNetworkScoreCache;
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
mContext = InstrumentationRegistry.getTargetContext();
}
@@ -74,6 +81,7 @@
@Test
public void testCopyAccessPoint_dataShouldMatch() {
WifiConfiguration configuration = createWifiConfiguration();
+ configuration.meteredHint = true;
NetworkInfo networkInfo =
new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
@@ -88,6 +96,7 @@
assertThat(originalAccessPoint.getBssid()).isEqualTo(copy.getBssid());
assertThat(originalAccessPoint.getConfig()).isEqualTo(copy.getConfig());
assertThat(originalAccessPoint.getSecurity()).isEqualTo(copy.getSecurity());
+ assertThat(originalAccessPoint.isMetered()).isEqualTo(copy.isMetered());
assertThat(originalAccessPoint.compareTo(copy) == 0).isTrue();
}
@@ -230,6 +239,55 @@
assertTrue(ap.isPasspointConfig());
}
+ @Test
+ public void testIsMetered_returnTrueWhenWifiConfigurationIsMetered() {
+ WifiConfiguration configuration = createWifiConfiguration();
+ configuration.meteredHint = true;
+
+ NetworkInfo networkInfo =
+ new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
+ AccessPoint accessPoint = new AccessPoint(mContext, configuration);
+ WifiInfo wifiInfo = new WifiInfo();
+ wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
+ wifiInfo.setBSSID(configuration.BSSID);
+ wifiInfo.setNetworkId(configuration.networkId);
+ accessPoint.update(configuration, wifiInfo, networkInfo);
+
+ assertTrue(accessPoint.isMetered());
+ };
+
+ @Test
+ public void testIsMetered_returnTrueWhenWifiInfoIsMetered() {
+ WifiConfiguration configuration = createWifiConfiguration();
+
+ NetworkInfo networkInfo =
+ new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
+ AccessPoint accessPoint = new AccessPoint(mContext, configuration);
+ WifiInfo wifiInfo = new WifiInfo();
+ wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
+ wifiInfo.setBSSID(configuration.BSSID);
+ wifiInfo.setNetworkId(configuration.networkId);
+ wifiInfo.setMeteredHint(true);
+ accessPoint.update(configuration, wifiInfo, networkInfo);
+
+ assertTrue(accessPoint.isMetered());
+ };
+
+ @Test
+ public void testIsMetered_returnTrueWhenScoredNetworkIsMetered() {
+ AccessPoint ap = createAccessPointWithScanResultCache();
+
+ when(mWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
+ .thenReturn(
+ new ScoredNetwork(
+ null /* NetworkKey */,
+ null /* rssiCurve */,
+ true /* metered */));
+ ap.update(mWifiNetworkScoreCache, false /* scoringUiEnabled */);
+
+ assertTrue(ap.isMetered());
+ };
+
private AccessPoint createAccessPointWithScanResultCache() {
Bundle bundle = new Bundle();
ArrayList<ScanResult> scanResults = new ArrayList<>();
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 02deb44..b71915f 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
@@ -302,7 +303,7 @@
new ScoredNetwork(
NETWORK_KEY_2,
mockCurve2,
- false /* meteredHint */,
+ true /* meteredHint */,
attr2);
WifiNetworkScoreCache scoreCache = mScoreCacheCaptor.getValue();
@@ -515,6 +516,23 @@
}
@Test
+ public void scoreCacheUpdateMeteredShouldUpdateAccessPointMetering()
+ throws InterruptedException {
+ WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
+ updateScoresAndWaitForAccessPointsChangedCallback();
+
+ List<AccessPoint> aps = tracker.getAccessPoints();
+
+ for (AccessPoint ap : aps) {
+ if (ap.getSsidStr().equals(SSID_1)) {
+ assertFalse(ap.isMetered());
+ } else if (ap.getSsidStr().equals(SSID_2)) {
+ assertTrue(ap.isMetered());
+ }
+ }
+ }
+
+ @Test
public void noBadgesShouldBeInsertedIntoAccessPointWhenScoringUiDisabled()
throws InterruptedException {
Settings.Global.putInt(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1f559e4..169a034 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -994,6 +994,15 @@
return false;
}
+ private PackageInfo getCallingPackageInfo(int userId) {
+ try {
+ return mPackageManager.getPackageInfo(getCallingPackage(),
+ PackageManager.GET_SIGNATURES, userId);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Package " + getCallingPackage() + " doesn't exist");
+ }
+ }
+
private Cursor getAllSecureSettings(int userId, String[] projection) {
if (DEBUG) {
Slog.v(LOG_TAG, "getAllSecureSettings(" + userId + ")");
@@ -1002,6 +1011,13 @@
// Resolve the userId on whose behalf the call is made.
final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
+ // The relevant "calling package" userId will be the owning userId for some
+ // profiles, and we can't do the lookup inside our [lock held] loop, so work out
+ // up front who the effective "new SSAID" user ID for that settings name will be.
+ final int ssaidUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId,
+ Settings.Secure.ANDROID_ID);
+ final PackageInfo ssaidCallingPkg = getCallingPackageInfo(ssaidUserId);
+
synchronized (mLock) {
List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_SECURE, callingUserId);
@@ -1026,7 +1042,7 @@
// SETTINGS_FILE_SSAID, unless accessed by a system process.
final Setting setting;
if (isNewSsaidSetting(name)) {
- setting = getSsaidSettingLocked(owningUserId);
+ setting = getSsaidSettingLocked(ssaidCallingPkg, owningUserId);
} else {
setting = mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SECURE, owningUserId,
name);
@@ -1060,14 +1076,17 @@
return settings != null ? settings.getNullSetting() : null;
}
- // Get the value.
- synchronized (mLock) {
- // As of Android O, the SSAID is read from an app-specific entry in table
- // SETTINGS_FILE_SSAID, unless accessed by a system process.
- if (isNewSsaidSetting(name)) {
- return getSsaidSettingLocked(owningUserId);
+ // As of Android O, the SSAID is read from an app-specific entry in table
+ // SETTINGS_FILE_SSAID, unless accessed by a system process.
+ if (isNewSsaidSetting(name)) {
+ PackageInfo callingPkg = getCallingPackageInfo(owningUserId);
+ synchronized (mLock) {
+ return getSsaidSettingLocked(callingPkg, owningUserId);
}
+ }
+ // Not the SSAID; do a straight lookup
+ synchronized (mLock) {
return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SECURE,
owningUserId, name);
}
@@ -1078,7 +1097,7 @@
&& UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID;
}
- private Setting getSsaidSettingLocked(int owningUserId) {
+ private Setting getSsaidSettingLocked(PackageInfo callingPkg, int owningUserId) {
// Get uid of caller (key) used to store ssaid value
String name = Integer.toString(
UserHandle.getUid(owningUserId, UserHandle.getAppId(Binder.getCallingUid())));
@@ -1093,7 +1112,7 @@
// Lazy initialize ssaid if not yet present in ssaid table.
if (ssaid == null || ssaid.isNull() || ssaid.getValue() == null) {
- return mSettingsRegistry.generateSsaidLocked(getCallingPackage(), owningUserId);
+ return mSettingsRegistry.generateSsaidLocked(callingPkg, owningUserId);
}
return ssaid;
@@ -2070,15 +2089,7 @@
return ByteBuffer.allocate(4).putInt(data.length).array();
}
- public Setting generateSsaidLocked(String packageName, int userId) {
- final PackageInfo packageInfo;
- try {
- packageInfo = mPackageManager.getPackageInfo(packageName,
- PackageManager.GET_SIGNATURES, userId);
- } catch (RemoteException e) {
- throw new IllegalStateException("Package info doesn't exist");
- }
-
+ public Setting generateSsaidLocked(PackageInfo callingPkg, int userId) {
// Read the user's key from the ssaid table.
Setting userKeySetting = getSettingLocked(SETTINGS_TYPE_SSAID, userId, SSAID_USER_KEY);
if (userKeySetting == null || userKeySetting.isNull()
@@ -2113,11 +2124,12 @@
}
// Mac the package name and each of the signatures.
- byte[] packageNameBytes = packageInfo.packageName.getBytes(StandardCharsets.UTF_8);
+ final String packageName = callingPkg.packageName;
+ byte[] packageNameBytes = packageName.getBytes(StandardCharsets.UTF_8);
m.update(getLengthPrefix(packageNameBytes), 0, 4);
m.update(packageNameBytes);
- for (int i = 0; i < packageInfo.signatures.length; i++) {
- byte[] sig = packageInfo.signatures[i].toByteArray();
+ for (int i = 0; i < callingPkg.signatures.length; i++) {
+ byte[] sig = callingPkg.signatures[i].toByteArray();
m.update(getLengthPrefix(sig), 0, 4);
m.update(sig);
}
@@ -2127,7 +2139,7 @@
.toLowerCase(Locale.US);
// Save the ssaid in the ssaid table.
- final String uid = Integer.toString(packageInfo.applicationInfo.uid);
+ final String uid = Integer.toString(callingPkg.applicationInfo.uid);
final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, userId);
final boolean success = ssaidSettings.insertSettingLocked(uid, ssaid, null, true,
packageName);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index fbd9f0c..4e7cf72 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -87,7 +87,9 @@
private boolean mMenuVisible;
private boolean mAllowMenuTimeout = true;
+
private final List<RemoteAction> mActions = new ArrayList<>();
+
private View mViewRoot;
private Drawable mBackgroundDrawable;
private View mMenuContainer;
@@ -266,7 +268,6 @@
}
notifyMenuVisibility(true);
updateExpandButtonFromBounds(stackBounds, movementBounds);
- setDecorViewVisibility(true);
mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
mMenuContainer.getAlpha(), 1f);
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
@@ -311,11 +312,15 @@
if (animationFinishedRunnable != null) {
animationFinishedRunnable.run();
}
- setDecorViewVisibility(false);
+
+ finish();
}
});
mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener);
mMenuContainerAnimator.start();
+ } else {
+ // If the menu is not visible, just finish now
+ finish();
}
}
@@ -431,7 +436,6 @@
alpha = (int) (fraction * DISMISS_BACKGROUND_ALPHA * 255);
}
mBackgroundDrawable.setAlpha(alpha);
- setDecorViewVisibility(alpha > 0);
}
private void notifyRegisterInputConsumer() {
@@ -508,16 +512,4 @@
v.removeCallbacks(mFinishRunnable);
v.postDelayed(mFinishRunnable, delay);
}
-
- /**
- * Sets the visibility of the root view of the window to disable drawing and touches for the
- * activity. This differs from {@link Activity#setVisible(boolean)} in that it does not set
- * the internal mVisibleFromClient state.
- */
- private void setDecorViewVisibility(boolean visible) {
- final View decorView = getWindow().getDecorView();
- if (decorView != null) {
- decorView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index bcaa395..875fb14 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -50,6 +50,7 @@
public class PipMenuActivityController {
private static final String TAG = "PipMenuActController";
+ private static final boolean DEBUG = false;
public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
public static final String EXTRA_ACTIONS = "actions";
@@ -195,6 +196,10 @@
* Updates the appearance of the menu and scrim on top of the PiP while dismissing.
*/
public void setDismissFraction(float fraction) {
+ if (DEBUG) {
+ Log.d(TAG, "setDismissFraction() hasActivity=" + (mToActivityMessenger != null)
+ + " fraction=" + fraction);
+ }
if (mToActivityMessenger != null) {
mTmpDismissFractionData.clear();
mTmpDismissFractionData.putFloat(EXTRA_DISMISS_FRACTION, fraction);
@@ -216,6 +221,9 @@
* Shows the menu activity.
*/
public void showMenu(Rect stackBounds, Rect movementBounds, boolean allowMenuTimeout) {
+ if (DEBUG) {
+ Log.d(TAG, "showMenu() hasActivity=" + (mToActivityMessenger != null));
+ }
if (mToActivityMessenger != null) {
Bundle data = new Bundle();
data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
@@ -238,6 +246,9 @@
* Pokes the menu, indicating that the user is interacting with it.
*/
public void pokeMenu() {
+ if (DEBUG) {
+ Log.d(TAG, "pokeMenu() hasActivity=" + (mToActivityMessenger != null));
+ }
if (mToActivityMessenger != null) {
Message m = Message.obtain();
m.what = PipMenuActivity.MESSAGE_POKE_MENU;
@@ -253,6 +264,9 @@
* Hides the menu activity.
*/
public void hideMenu() {
+ if (DEBUG) {
+ Log.d(TAG, "hideMenu() hasActivity=" + (mToActivityMessenger != null));
+ }
if (mToActivityMessenger != null) {
Message m = Message.obtain();
m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
@@ -365,6 +379,10 @@
* Handles changes in menu visibility.
*/
private void onMenuVisibilityChanged(boolean visible, boolean resize) {
+ if (DEBUG) {
+ Log.d(TAG, "onMenuVisibilityChanged() mMenuVisible=" + mMenuVisible
+ + " menuVisible=" + visible + " resize=" + resize);
+ }
if (visible) {
mInputConsumerController.unregisterInputConsumer();
} else {
@@ -389,6 +407,7 @@
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
pw.println(innerPrefix + "mMenuVisible=" + mMenuVisible);
+ pw.println(innerPrefix + "mToActivityMessenger=" + mToActivityMessenger);
pw.println(innerPrefix + "mListeners=" + mListeners.size());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index a14a712..fb8574d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -23,6 +23,7 @@
import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN;
import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
@@ -253,7 +254,7 @@
* Flings the PiP to the closest snap target.
*/
Rect flingToSnapTarget(float velocity, float velocityX, float velocityY, Rect movementBounds,
- AnimatorUpdateListener listener) {
+ AnimatorUpdateListener updateListener, AnimatorListener listener) {
cancelAnimations();
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
velocityX, velocityY);
@@ -263,8 +264,11 @@
mFlingAnimationUtils.apply(mBoundsAnimator, 0,
distanceBetweenRectOffsets(mBounds, toBounds),
velocity);
- if (listener != null) {
- mBoundsAnimator.addUpdateListener(listener);
+ if (updateListener != null) {
+ mBoundsAnimator.addUpdateListener(updateListener);
+ }
+ if (listener != null){
+ mBoundsAnimator.addListener(listener);
}
mBoundsAnimator.start();
}
@@ -274,14 +278,18 @@
/**
* Animates the PiP to the closest snap target.
*/
- Rect animateToClosestSnapTarget(Rect movementBounds, AnimatorUpdateListener listener) {
+ Rect animateToClosestSnapTarget(Rect movementBounds, AnimatorUpdateListener updateListener,
+ AnimatorListener listener) {
cancelAnimations();
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds);
if (!mBounds.equals(toBounds)) {
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, SNAP_STACK_DURATION,
FAST_OUT_SLOW_IN, mUpdateBoundsListener);
- if (listener != null) {
- mBoundsAnimator.addUpdateListener(listener);
+ if (updateListener != null) {
+ mBoundsAnimator.addUpdateListener(updateListener);
+ }
+ if (listener != null){
+ mBoundsAnimator.addListener(listener);
}
mBoundsAnimator.start();
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index d68836c..161bdac 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -16,6 +16,8 @@
package com.android.systemui.pip.phone;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.IActivityManager;
@@ -391,7 +393,10 @@
final float distance = bounds.bottom - target;
fraction = Math.min(distance / bounds.height(), 1f);
}
- mMenuController.setDismissFraction(fraction);
+ if (Float.compare(fraction, 0f) != 0 || mMenuController.isMenuVisible()) {
+ // Update if the fraction > 0, or if fraction == 0 and the menu was already visible
+ mMenuController.setDismissFraction(fraction);
+ }
}
}
@@ -611,22 +616,34 @@
setMinimizedStateInternal(false);
}
- // If the menu is still visible, and we aren't minimized, then just poke the menu
- // so that it will timeout after the user stops touching it
+ AnimatorListenerAdapter postAnimationCallback = null;
if (mMenuController.isMenuVisible()) {
+ // If the menu is still visible, and we aren't minimized, then just poke the
+ // menu so that it will timeout after the user stops touching it
mMenuController.showMenu(mMotionHelper.getBounds(), mMovementBounds,
true /* allowMenuTimeout */);
+ } else {
+ // If the menu is not visible, then we can still be showing the activity for the
+ // dismiss overlay, so just finish it after the animation completes
+ postAnimationCallback = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mMenuController.hideMenu();
+ }
+ };
}
if (isFling) {
mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds,
- mUpdateScrimListener);
+ mUpdateScrimListener, postAnimationCallback);
} else {
- mMotionHelper.animateToClosestSnapTarget(mMovementBounds, mUpdateScrimListener);
+ mMotionHelper.animateToClosestSnapTarget(mMovementBounds, mUpdateScrimListener,
+ postAnimationCallback);
}
} else if (mIsMinimized) {
// This was a tap, so no longer minimized
- mMotionHelper.animateToClosestSnapTarget(mMovementBounds, null /* listener */);
+ mMotionHelper.animateToClosestSnapTarget(mMovementBounds, null /* updateListener */,
+ null /* animatorListener */);
setMinimizedStateInternal(false);
} else if (!mIsMenuVisible) {
mMenuController.showMenu(mMotionHelper.getBounds(), mMovementBounds,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 8042321..715dc82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -434,7 +434,8 @@
iconState.scaleY = 1.0f;
iconState.hidden = false;
}
- if (row.isAboveShelf() || (!row.isInShelf() && isLastChild && row.areGutsExposed())) {
+ if (row.isAboveShelf() || (!row.isInShelf() && (isLastChild && row.areGutsExposed()
+ || row.getTranslationZ() > mAmbientState.getBaseZHeight()))) {
iconState.hidden = true;
}
int shelfColor = icon.getStaticDrawableColor();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
index c8659fb..5b594be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -190,7 +190,9 @@
view.setScaleY(scaleY);
}
- boolean becomesInvisible = this.alpha == 0.0f || (this.hidden && !isAnimating(view));
+ int oldVisibility = view.getVisibility();
+ boolean becomesInvisible = this.alpha == 0.0f
+ || (this.hidden && (!isAnimating(view) || oldVisibility != View.VISIBLE));
boolean animatingAlpha = isAnimating(view, TAG_ANIMATOR_ALPHA);
if (animatingAlpha) {
updateAlphaAnimation(view);
@@ -212,7 +214,6 @@
}
// apply visibility
- int oldVisibility = view.getVisibility();
int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
if (newVisibility != oldVisibility) {
if (!(view instanceof ExpandableView) || !((ExpandableView) view).willBeGone()) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 15ec98f..f8b8e76 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -194,13 +194,17 @@
}
}
+ private String getComponentNameFromSettings() {
+ return Settings.Secure.getStringForUser(
+ mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId);
+ }
+
void updateLocked(boolean disabled) {
final boolean wasEnabled = isEnabled();
mDisabled = disabled;
ComponentName serviceComponent = null;
ServiceInfo serviceInfo = null;
- final String componentName = Settings.Secure.getStringForUser(
- mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId);
+ final String componentName = getComponentNameFromSettings();
if (!TextUtils.isEmpty(componentName)) {
try {
serviceComponent = ComponentName.unflattenFromString(componentName);
@@ -413,8 +417,7 @@
void disableSelf() {
final long identity = Binder.clearCallingIdentity();
try {
- final String autoFillService = Settings.Secure.getStringForUser(
- mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId);
+ final String autoFillService = getComponentNameFromSettings();
if (mInfo.getServiceInfo().getComponentName().equals(
ComponentName.unflattenFromString(autoFillService))) {
Settings.Secure.putStringForUser(mContext.getContentResolver(),
@@ -432,12 +435,14 @@
void dumpLocked(String prefix, PrintWriter pw) {
final String prefix2 = prefix + " ";
- pw.print(prefix); pw.print("User :"); pw.println(mUserId);
- pw.print(prefix); pw.print("Component:"); pw.println(mInfo != null
+ pw.print(prefix); pw.print("User: "); pw.println(mUserId);
+ pw.print(prefix); pw.print("Component: "); pw.println(mInfo != null
? mInfo.getServiceInfo().getComponentName() : null);
+ pw.print(prefix); pw.print("Component from settings: ");
+ pw.println(getComponentNameFromSettings());
pw.print(prefix); pw.print("Default component: ");
pw.println(mContext.getString(R.string.config_defaultAutofillService));
- pw.print(prefix); pw.print("Disabled:"); pw.println(mDisabled);
+ pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
if (VERBOSE && mInfo != null) {
// ServiceInfo dump is too noisy and redundant (it can be obtained through other dumps)
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 801769c..1ffc82f 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -29,6 +29,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.AutofillOverlay;
import android.app.assist.AssistStructure.ViewNode;
import android.app.assist.AssistStructure.WindowNode;
import android.content.ComponentName;
@@ -100,7 +101,7 @@
@NonNull private final String mPackageName;
@GuardedBy("mLock")
- private final Map<AutofillId, ViewState> mViewStates = new ArrayMap<>();
+ private final ArrayMap<AutofillId, ViewState> mViewStates = new ArrayMap<>();
/**
* Id of the View currently being displayed.
@@ -517,10 +518,10 @@
if (DEBUG) {
Slog.d(TAG, "Creating viewState for " + id + " on " + getFlagAsString(flags));
}
- viewState = new ViewState(this, id, this, ViewState.STATE_INITIAL);
+ viewState = new ViewState(this, id, value, this, ViewState.STATE_INITIAL);
mViewStates.put(id, viewState);
} else if ((flags & FLAG_VIEW_ENTERED) != 0) {
- viewState = startPartitionLocked(id);
+ viewState = startPartitionLocked(id, value);
} else {
if (VERBOSE) Slog.v(TAG, "Ignored " + getFlagAsString(flags) + " for " + id);
return;
@@ -584,25 +585,45 @@
Slog.w(TAG, "updateLocked(): unknown flags " + flags + ": " + getFlagAsString(flags));
}
- private ViewState startPartitionLocked(AutofillId id) {
+ private ViewState startPartitionLocked(AutofillId id, AutofillValue value) {
if (DEBUG) {
Slog.d(TAG, "Starting partition for view id " + id);
}
- final ViewState viewState =
- new ViewState(this, id, this,ViewState.STATE_STARTED_PARTITION);
- mViewStates.put(id, viewState);
+ final ViewState newViewState =
+ new ViewState(this, id, value, this,ViewState.STATE_STARTED_PARTITION);
+ mViewStates.put(id, newViewState);
/*
* TODO(b/33197203 , b/35707731): when start a new partition, it should
*
- * - add autofilled fields as sanitized
- * - set focus on ViewStructure that triggered it
* - pass the first onFillRequest() bundle
* - optional: perhaps add a new flag onFilLRequest() to indicate it's a new partition?
*/
+
+ // Must update value of nodes so:
+ // - proper node is focused
+ // - autofillValue is sent back to service when it was previously autofilled
+ for (int i = 0; i < mViewStates.size(); i++) {
+ final ViewState viewState = mViewStates.valueAt(i);
+
+ final ViewNode node = findViewNodeByIdLocked(viewState.id);
+ if (node == null) {
+ Slog.w(TAG, "startPartitionLocked(): no node for " + viewState.id);
+ continue;
+ }
+
+ final AutofillValue initialValue = viewState.getInitialValue();
+ final AutofillValue filledValue = viewState.getAutofilledValue();
+ final AutofillOverlay overlay = new AutofillOverlay();
+ if (filledValue != null && !filledValue.equals(initialValue)) {
+ overlay.value = filledValue;
+ }
+ overlay.focused = id.equals(viewState.id);
+ node.setAutofillOverlay(overlay);
+ }
mRemoteFillService.onFillRequest(mStructure, null, 0);
- return viewState;
+ return newViewState;
}
@Override
@@ -695,7 +716,7 @@
if (viewState != null) {
viewState.setState(state);
} else {
- viewState = new ViewState(this, id, this, state);
+ viewState = new ViewState(this, id, null, this, state);
if (DEBUG) { // TODO(b/33197203): change to VERBOSE once stable
Slog.d(TAG, "Adding autofillable view with id " + id + " and state " + state);
}
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 549f231..f8919ee 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -67,15 +67,17 @@
private final Session mSession;
private FillResponse mResponse;
+ private AutofillValue mInitialValue;
private AutofillValue mCurrentValue;
private AutofillValue mAutofilledValue;
private Rect mVirtualBounds;
private int mState;
- ViewState(Session session, AutofillId id, Listener listener, int state) {
+ ViewState(Session session, AutofillId id, AutofillValue value, Listener listener, int state) {
mSession = session;
this.id = id;
+ mInitialValue = value;
mListener = listener;
mState = state;
}
@@ -110,6 +112,11 @@
}
@Nullable
+ AutofillValue getInitialValue() {
+ return mInitialValue;
+ }
+
+ @Nullable
FillResponse getResponse() {
return mResponse;
}
@@ -184,14 +191,16 @@
@Override
public String toString() {
- return "ViewState: [id=" + id + ", currentValue=" + mCurrentValue
- + ", bounds=" + mVirtualBounds + ", state=" + getStateAsString() +"]";
+ return "ViewState: [id=" + id + ", initialValue=" + mInitialValue
+ + ", currentValue=" + mCurrentValue + ", autofilledValue=" + mAutofilledValue
+ + ", bounds=" + mVirtualBounds + ", state=" + getStateAsString() + "]";
}
void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("id:" ); pw.println(this.id);
pw.print(prefix); pw.print("state:" ); pw.println(getStateAsString());
pw.print(prefix); pw.print("has response:" ); pw.println(mResponse != null);
+ pw.print(prefix); pw.print("initialValue:" ); pw.println(mInitialValue);
pw.print(prefix); pw.print("currentValue:" ); pw.println(mCurrentValue);
pw.print(prefix); pw.print("autofilledValue:" ); pw.println(mAutofilledValue);
pw.print(prefix); pw.print("virtualBounds:" ); pw.println(mVirtualBounds);
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 509351b..2c08afa 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -117,6 +117,12 @@
case SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD:
type = context.getString(R.string.autofill_save_type_credit_card);
break;
+ case SaveInfo.SAVE_DATA_TYPE_USERNAME:
+ type = context.getString(R.string.autofill_save_type_username);
+ break;
+ case SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS:
+ type = context.getString(R.string.autofill_save_type_email_address);
+ break;
default:
type = null;
}
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
new file mode 100644
index 0000000..a7ce95b
--- /dev/null
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -0,0 +1,494 @@
+/*
+ * Copyright (C) 2017 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;
+
+import static android.Manifest.permission.DUMP;
+import static android.net.IpSecManager.INVALID_RESOURCE_ID;
+import static android.net.IpSecManager.KEY_RESOURCE_ID;
+import static android.net.IpSecManager.KEY_SPI;
+import static android.net.IpSecManager.KEY_STATUS;
+
+import android.content.Context;
+import android.net.IIpSecService;
+import android.net.INetd;
+import android.net.IpSecAlgorithm;
+import android.net.IpSecConfig;
+import android.net.IpSecManager;
+import android.net.IpSecTransform;
+import android.net.util.NetdService;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/** @hide */
+public class IpSecService extends IIpSecService.Stub {
+ private static final String TAG = "IpSecService";
+ private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final String NETD_SERVICE_NAME = "netd";
+ private static final int[] DIRECTIONS =
+ new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN};
+
+ /** Binder context for this service */
+ private final Context mContext;
+
+ private Object mLock = new Object();
+
+ private static final int NETD_FETCH_TIMEOUT = 5000; //ms
+
+ private AtomicInteger mNextResourceId = new AtomicInteger(0x00FADED0);
+
+ private abstract class ManagedResource implements IBinder.DeathRecipient {
+ final int pid;
+ final int uid;
+ private IBinder mBinder;
+
+ ManagedResource(IBinder binder) {
+ super();
+ mBinder = binder;
+ pid = Binder.getCallingPid();
+ uid = Binder.getCallingUid();
+
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+
+ /**
+ * When this record is no longer needed for managing system resources this function should
+ * unlink all references held by the record to allow efficient garbage collection.
+ */
+ public final void release() {
+ //Release all the underlying system resources first
+ releaseResources();
+
+ if (mBinder != null) {
+ mBinder.unlinkToDeath(this, 0);
+ }
+ mBinder = null;
+
+ //remove this record so that it can be cleaned up
+ nullifyRecord();
+ }
+
+ /**
+ * If the Binder object dies, this function is called to free the system resources that are
+ * being managed by this record and to subsequently release this record for garbage
+ * collection
+ */
+ public final void binderDied() {
+ release();
+ }
+
+ /**
+ * Implement this method to release all object references contained in the subclass to allow
+ * efficient garbage collection of the record. This should remove any references to the
+ * record from all other locations that hold a reference as the record is no longer valid.
+ */
+ protected abstract void nullifyRecord();
+
+ /**
+ * Implement this method to release all system resources that are being protected by this
+ * record. Once the resources are released, the record should be invalidated and no longer
+ * used by calling releaseRecord()
+ */
+ protected abstract void releaseResources();
+ };
+
+ private final class TransformRecord extends ManagedResource {
+ private IpSecConfig mConfig;
+ private int mResourceId;
+
+ TransformRecord(IpSecConfig config, int resourceId, IBinder binder) {
+ super(binder);
+ mConfig = config;
+ mResourceId = resourceId;
+ }
+
+ public IpSecConfig getConfig() {
+ return mConfig;
+ }
+
+ @Override
+ protected void releaseResources() {
+ for (int direction : DIRECTIONS) {
+ try {
+ getNetdInstance()
+ .ipSecDeleteSecurityAssociation(
+ mResourceId,
+ direction,
+ (mConfig.getLocalAddress() != null)
+ ? mConfig.getLocalAddress().getHostAddress()
+ : "",
+ (mConfig.getRemoteAddress() != null)
+ ? mConfig.getRemoteAddress().getHostAddress()
+ : "",
+ mConfig.getSpi(direction));
+ } catch (ServiceSpecificException e) {
+ // FIXME: get the error code and throw is at an IOException from Errno Exception
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to delete SA with ID: " + mResourceId);
+ }
+ }
+ }
+
+ @Override
+ protected void nullifyRecord() {
+ mConfig = null;
+ mResourceId = INVALID_RESOURCE_ID;
+ }
+ }
+
+ private final class SpiRecord extends ManagedResource {
+ private final int mDirection;
+ private final String mLocalAddress;
+ private final String mRemoteAddress;
+ private final IBinder mBinder;
+ private int mSpi;
+ private int mResourceId;
+
+ SpiRecord(
+ int resourceId,
+ int direction,
+ String localAddress,
+ String remoteAddress,
+ int spi,
+ IBinder binder) {
+ super(binder);
+ mResourceId = resourceId;
+ mDirection = direction;
+ mLocalAddress = localAddress;
+ mRemoteAddress = remoteAddress;
+ mSpi = spi;
+ mBinder = binder;
+ }
+
+ protected void releaseResources() {
+ try {
+ getNetdInstance()
+ .ipSecDeleteSecurityAssociation(
+ mResourceId, mDirection, mLocalAddress, mRemoteAddress, mSpi);
+ } catch (ServiceSpecificException e) {
+ // FIXME: get the error code and throw is at an IOException from Errno Exception
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId);
+ }
+ }
+
+ protected void nullifyRecord() {
+ mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
+ mResourceId = INVALID_RESOURCE_ID;
+ }
+ }
+
+ @GuardedBy("mSpiRecords")
+ private final SparseArray<SpiRecord> mSpiRecords = new SparseArray<>();
+
+ @GuardedBy("mTransformRecords")
+ private final SparseArray<TransformRecord> mTransformRecords = new SparseArray<>();
+
+ /**
+ * Constructs a new IpSecService instance
+ *
+ * @param context Binder context for this service
+ */
+ private IpSecService(Context context) {
+ mContext = context;
+ }
+
+ static IpSecService create(Context context) throws InterruptedException {
+ final IpSecService service = new IpSecService(context);
+ service.connectNativeNetdService();
+ return service;
+ }
+
+ public void systemReady() {
+ if (isNetdAlive()) {
+ Slog.d(TAG, "IpSecService is ready");
+ } else {
+ Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!");
+ }
+ }
+
+ private void connectNativeNetdService() {
+ // Avoid blocking the system server to do this
+ Thread t =
+ new Thread(
+ new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ NetdService.get(NETD_FETCH_TIMEOUT);
+ }
+ }
+ });
+ t.run();
+ }
+
+ INetd getNetdInstance() throws RemoteException {
+ final INetd netd = NetdService.getInstance();
+ if (netd == null) {
+ throw new RemoteException("Failed to Get Netd Instance");
+ }
+ return netd;
+ }
+
+ boolean isNetdAlive() {
+ synchronized (mLock) {
+ try {
+ final INetd netd = getNetdInstance();
+ if (netd == null) {
+ return false;
+ }
+ return netd.isAlive();
+ } catch (RemoteException re) {
+ return false;
+ }
+ }
+ }
+
+ @Override
+ /** Get a new SPI and maintain the reservation in the system server */
+ public Bundle reserveSecurityParameterIndex(
+ int direction, String remoteAddress, int requestedSpi, IBinder binder)
+ throws RemoteException {
+ int resourceId = mNextResourceId.getAndIncrement();
+
+ int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
+ String localAddress = "";
+ Bundle retBundle = new Bundle(3);
+ try {
+ spi =
+ getNetdInstance()
+ .ipSecAllocateSpi(
+ resourceId,
+ direction,
+ localAddress,
+ remoteAddress,
+ requestedSpi);
+ Log.d(TAG, "Allocated SPI " + spi);
+ retBundle.putInt(KEY_STATUS, IpSecManager.Status.OK);
+ retBundle.putInt(KEY_RESOURCE_ID, resourceId);
+ retBundle.putInt(KEY_SPI, spi);
+ synchronized (mSpiRecords) {
+ mSpiRecords.put(
+ resourceId,
+ new SpiRecord(
+ resourceId, direction, localAddress, remoteAddress, spi, binder));
+ }
+ } catch (ServiceSpecificException e) {
+ // TODO: Add appropriate checks when other ServiceSpecificException types are supported
+ retBundle.putInt(KEY_STATUS, IpSecManager.Status.SPI_UNAVAILABLE);
+ retBundle.putInt(KEY_RESOURCE_ID, resourceId);
+ retBundle.putInt(KEY_SPI, spi);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return retBundle;
+ }
+
+ /** Release a previously allocated SPI that has been registered with the system server */
+ @Override
+ public void releaseSecurityParameterIndex(int resourceId) throws RemoteException {}
+
+ /**
+ * Open a socket via the system server and bind it to the specified port (random if port=0).
+ * This will return a PFD to the user that represent a bound UDP socket. The system server will
+ * cache the socket and a record of its owner so that it can and must be freed when no longer
+ * needed.
+ */
+ @Override
+ public Bundle openUdpEncapsulationSocket(int port, IBinder binder) throws RemoteException {
+ return null;
+ }
+
+ /** close a socket that has been been allocated by and registered with the system server */
+ @Override
+ public void closeUdpEncapsulationSocket(ParcelFileDescriptor socket) {}
+
+ /**
+ * Create a transport mode transform, which represent two security associations (one in each
+ * direction) in the kernel. The transform will be cached by the system server and must be freed
+ * when no longer needed. It is possible to free one, deleting the SA from underneath sockets
+ * that are using it, which will result in all of those sockets becoming unable to send or
+ * receive data.
+ */
+ @Override
+ public Bundle createTransportModeTransform(IpSecConfig c, IBinder binder)
+ throws RemoteException {
+ // TODO: Basic input validation here since it's coming over the Binder
+ int resourceId = mNextResourceId.getAndIncrement();
+ for (int direction : DIRECTIONS) {
+ IpSecAlgorithm auth = c.getAuthentication(direction);
+ IpSecAlgorithm crypt = c.getEncryption(direction);
+ try {
+ int result =
+ getNetdInstance()
+ .ipSecAddSecurityAssociation(
+ resourceId,
+ c.getMode(),
+ direction,
+ (c.getLocalAddress() != null)
+ ? c.getLocalAddress().getHostAddress()
+ : "",
+ (c.getRemoteAddress() != null)
+ ? c.getRemoteAddress().getHostAddress()
+ : "",
+ (c.getNetwork() != null)
+ ? c.getNetwork().getNetworkHandle()
+ : 0,
+ c.getSpi(direction),
+ (auth != null) ? auth.getName() : "",
+ (auth != null) ? auth.getKey() : null,
+ (auth != null) ? auth.getTruncationLengthBits() : 0,
+ (crypt != null) ? crypt.getName() : "",
+ (crypt != null) ? crypt.getKey() : null,
+ (crypt != null) ? crypt.getTruncationLengthBits() : 0,
+ c.getEncapType(),
+ c.getEncapLocalPort(),
+ c.getEncapRemotePort());
+ if (result != c.getSpi(direction)) {
+ // TODO: cleanup the first SA if creation of second SA fails
+ Bundle retBundle = new Bundle(2);
+ retBundle.putInt(KEY_STATUS, IpSecManager.Status.SPI_UNAVAILABLE);
+ retBundle.putInt(KEY_RESOURCE_ID, INVALID_RESOURCE_ID);
+ return retBundle;
+ }
+ } catch (ServiceSpecificException e) {
+ // FIXME: get the error code and throw is at an IOException from Errno Exception
+ }
+ }
+ synchronized (mTransformRecords) {
+ mTransformRecords.put(resourceId, new TransformRecord(c, resourceId, binder));
+ }
+
+ Bundle retBundle = new Bundle(2);
+ retBundle.putInt(KEY_STATUS, IpSecManager.Status.OK);
+ retBundle.putInt(KEY_RESOURCE_ID, resourceId);
+ return retBundle;
+ }
+
+ /**
+ * Delete a transport mode transform that was previously allocated by + registered with the
+ * system server. If this is called on an inactive (or non-existent) transform, it will not
+ * return an error. It's safe to de-allocate transforms that may have already been deleted for
+ * other reasons.
+ */
+ @Override
+ public void deleteTransportModeTransform(int resourceId) throws RemoteException {
+ synchronized (mTransformRecords) {
+ TransformRecord record;
+ // We want to non-destructively get so that we can check credentials before removing
+ // this from the records.
+ record = mTransformRecords.get(resourceId);
+
+ if (record == null) {
+ throw new IllegalArgumentException(
+ "Transform " + resourceId + " is not available to be deleted");
+ }
+
+ if (record.pid != Binder.getCallingPid() || record.uid != Binder.getCallingUid()) {
+ throw new SecurityException("Only the owner of an IpSec Transform may delete it!");
+ }
+
+ // TODO: if releaseResources() throws RemoteException, we can try again to clean up on
+ // binder death. Need to make sure that path is actually functional.
+ record.releaseResources();
+ mTransformRecords.remove(resourceId);
+ record.nullifyRecord();
+ }
+ }
+
+ /**
+ * Apply an active transport mode transform to a socket, which will apply the IPsec security
+ * association as a correspondent policy to the provided socket
+ */
+ @Override
+ public void applyTransportModeTransform(ParcelFileDescriptor socket, int resourceId)
+ throws RemoteException {
+
+ synchronized (mTransformRecords) {
+ TransformRecord info;
+ // FIXME: this code should be factored out into a security check + getter
+ info = mTransformRecords.get(resourceId);
+
+ if (info == null) {
+ throw new IllegalArgumentException("Transform " + resourceId + " is not active");
+ }
+
+ // TODO: make this a function.
+ if (info.pid != getCallingPid() || info.uid != getCallingUid()) {
+ throw new SecurityException("Only the owner of an IpSec Transform may apply it!");
+ }
+
+ IpSecConfig c = info.getConfig();
+ try {
+ for (int direction : DIRECTIONS) {
+ getNetdInstance()
+ .ipSecApplyTransportModeTransform(
+ socket.getFileDescriptor(),
+ resourceId,
+ direction,
+ (c.getLocalAddress() != null)
+ ? c.getLocalAddress().getHostAddress()
+ : "",
+ (c.getRemoteAddress() != null)
+ ? c.getRemoteAddress().getHostAddress()
+ : "",
+ c.getSpi(direction));
+ }
+ } catch (ServiceSpecificException e) {
+ // FIXME: get the error code and throw is at an IOException from Errno Exception
+ }
+ }
+ }
+ /**
+ * Remove a transport mode transform from a socket, applying the default (empty) policy. This
+ * will ensure that NO IPsec policy is applied to the socket (would be the equivalent of
+ * applying a policy that performs no IPsec). Today the resourceId parameter is passed but not
+ * used: reserved for future improved input validation.
+ */
+ @Override
+ public void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId)
+ throws RemoteException {
+ try {
+ getNetdInstance().ipSecRemoveTransportModeTransform(socket.getFileDescriptor());
+ } catch (ServiceSpecificException e) {
+ // FIXME: get the error code and throw is at an IOException from Errno Exception
+ }
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mContext.enforceCallingOrSelfPermission(DUMP, TAG);
+
+ pw.println("IpSecService Log:");
+ pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead"));
+ pw.println();
+ }
+}
diff --git a/services/core/java/com/android/server/SensorNotificationService.java b/services/core/java/com/android/server/SensorNotificationService.java
index 0610464..7f5befa 100644
--- a/services/core/java/com/android/server/SensorNotificationService.java
+++ b/services/core/java/com/android/server/SensorNotificationService.java
@@ -20,25 +20,46 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.hardware.GeomagneticField;
import android.hardware.Sensor;
+import android.hardware.SensorAdditionalInfo;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
-public class SensorNotificationService extends SystemService implements SensorEventListener {
- //TODO: set DBG to false or remove Slog before release
- private static final boolean DBG = true;
+public class SensorNotificationService extends SystemService
+ implements SensorEventListener, LocationListener {
+ private static final boolean DBG = false;
private static final String TAG = "SensorNotificationService";
- private Context mContext;
+ private static final long MINUTE_IN_MS = 60 * 1000;
+ private static final long KM_IN_M = 1000;
+
+ private static final long LOCATION_MIN_TIME = 30 * MINUTE_IN_MS;
+ private static final long LOCATION_MIN_DISTANCE = 100 * KM_IN_M;
+
+ private static final String PROPERTY_USE_MOCKED_LOCATION =
+ "sensor.notification.use_mocked"; // max key length is 32
+
+ private static final long MILLIS_2010_1_1 = 1262358000000l;
+
+ private Context mContext;
private SensorManager mSensorManager;
+ private LocationManager mLocationManager;
private Sensor mMetaSensor;
+ // for rate limiting
+ private long mLocalGeomagneticFieldUpdateTime = -LOCATION_MIN_TIME;
+
public SensorNotificationService(Context context) {
super(context);
mContext = context;
@@ -50,7 +71,6 @@
public void onBootPhase(int phase) {
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
- // start
mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
mMetaSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_DYNAMIC_SENSOR_META);
if (mMetaSensor == null) {
@@ -60,13 +80,28 @@
SensorManager.SENSOR_DELAY_FASTEST);
}
}
+
+ if (phase == PHASE_BOOT_COMPLETED) {
+ // LocationManagerService is initialized after PHASE_THIRD_PARTY_APPS_CAN_START
+ mLocationManager =
+ (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+ if (mLocationManager == null) {
+ if (DBG) Slog.d(TAG, "Cannot obtain location service.");
+ } else {
+ mLocationManager.requestLocationUpdates(
+ LocationManager.PASSIVE_PROVIDER,
+ LOCATION_MIN_TIME,
+ LOCATION_MIN_DISTANCE,
+ this);
+ }
+ }
}
private void broadcastDynamicSensorChanged() {
Intent i = new Intent(Intent.ACTION_DYNAMIC_SENSOR_CHANGED);
i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); // avoid waking up manifest receivers
mContext.sendBroadcastAsUser(i, UserHandle.ALL);
- if (DBG) Slog.d(TAG, "DYNS sent dynamic sensor broadcast");
+ if (DBG) Slog.d(TAG, "dynamic sensor broadcast sent");
}
@Override
@@ -77,8 +112,62 @@
}
@Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ public void onLocationChanged(Location location) {
+ if (DBG) Slog.d(TAG, String.format(
+ "Location is (%f, %f), h %f, acc %f, mocked %b",
+ location.getLatitude(), location.getLongitude(),
+ location.getAltitude(), location.getAccuracy(),
+ location.isFromMockProvider()));
+ // lat long == 0 usually means invalid location
+ if (location.getLatitude() == 0 && location.getLongitude() == 0) {
+ return;
+ }
+
+ // update too often, ignore
+ if (SystemClock.elapsedRealtime() - mLocalGeomagneticFieldUpdateTime < 10 * MINUTE_IN_MS) {
+ return;
+ }
+
+ long time = System.currentTimeMillis();
+ // Mocked location should not be used. Except in test, only use mocked location
+ // Wrong system clock also gives bad values so ignore as well.
+ if (useMockedLocation() == location.isFromMockProvider() || time < MILLIS_2010_1_1) {
+ return;
+ }
+
+ GeomagneticField field = new GeomagneticField(
+ (float) location.getLatitude(), (float) location.getLongitude(),
+ (float) location.getAltitude(), time);
+ if (DBG) Slog.d(TAG, String.format(
+ "Nominal mag field, norm %fuT, decline %f deg, incline %f deg",
+ field.getFieldStrength() / 1000, field.getDeclination(), field.getInclination()));
+
+ try {
+ SensorAdditionalInfo info = SensorAdditionalInfo.createLocalGeomagneticField(
+ field.getFieldStrength() / 1000, // convert from nT to uT
+ (float)(field.getDeclination() * Math.PI / 180), // from degree to rad
+ (float)(field.getInclination() * Math.PI / 180)); // from degree to rad
+ if (info != null) {
+ mSensorManager.setOperationParameter(info);
+ mLocalGeomagneticFieldUpdateTime = SystemClock.elapsedRealtime();
+ }
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Invalid local geomagnetic field, ignore.");
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {}
+ @Override
+ public void onProviderEnabled(String provider) {}
+ @Override
+ public void onProviderDisabled(String provider) {}
+
+ private boolean useMockedLocation() {
+ return "false".equals(System.getProperty(PROPERTY_USE_MOCKED_LOCATION, "false"));
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 7c1a609..dd4d906 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -32,37 +32,39 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.telephony.CellLocation;
-import android.telephony.Rlog;
-import android.telephony.TelephonyManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
import android.telephony.CellInfo;
-import android.telephony.VoLteServiceState;
+import android.telephony.CellLocation;
import android.telephony.DisconnectCause;
+import android.telephony.PhoneStateListener;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
import android.telephony.PreciseDisconnectCause;
+import android.telephony.Rlog;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.VoLteServiceState;
import android.text.TextUtils;
-import android.text.format.Time;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
+import android.util.LocalLog;
import com.android.internal.app.IBatteryStats;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
-import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.telephony.IPhoneStateListener;
+import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.telephony.PhoneConstantConversions;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.am.BatteryStatsService;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
/**
* Since phone process can be restarted, this class provides a centralized place
* that applications can register and be called back from.
@@ -159,8 +161,6 @@
private String[] mDataConnectionReason;
- private String[] mDataConnectionApn;
-
private ArrayList<String>[] mConnectedApns;
private LinkProperties[] mDataConnectionLinkProperties;
@@ -191,6 +191,8 @@
private boolean mCarrierNetworkChangeState = false;
+ private final LocalLog mLocalLog = new LocalLog(100);
+
private PreciseDataConnectionState mPreciseDataConnectionState =
new PreciseDataConnectionState();
@@ -310,7 +312,6 @@
mMessageWaiting = new boolean[numPhones];
mDataConnectionPossible = new boolean[numPhones];
mDataConnectionReason = new String[numPhones];
- mDataConnectionApn = new String[numPhones];
mCallForwarding = new boolean[numPhones];
mCellLocation = new Bundle[numPhones];
mDataConnectionLinkProperties = new LinkProperties[numPhones];
@@ -329,7 +330,6 @@
mCallForwarding[i] = false;
mDataConnectionPossible[i] = false;
mDataConnectionReason[i] = "";
- mDataConnectionApn[i] = "";
mCellLocation[i] = new Bundle();
mCellInfo.add(i, null);
mConnectedApns[i] = new ArrayList<String>();
@@ -536,7 +536,6 @@
if (DBG) {
log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
}
- if (VDBG) toStringLogSSC("listen");
if (notifyNow && validatePhoneId(phoneId)) {
if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
try {
@@ -780,14 +779,14 @@
}
synchronized (mRecords) {
+ String str = "notifyServiceStateForSubscriber: subId=" + subId + " phoneId=" + phoneId
+ + " state=" + state;
if (VDBG) {
- log("notifyServiceStateForSubscriber: subId=" + subId + " phoneId=" + phoneId
- + " state=" + state);
+ log(str);
}
+ mLocalLog.log(str);
if (validatePhoneId(phoneId)) {
mServiceState[phoneId] = state;
- logServiceStateChanged("notifyServiceStateForSubscriber", subId, phoneId, state);
- if (VDBG) toStringLogSSC("notifyServiceStateForSubscriber");
for (Record r : mRecords) {
if (VDBG) {
@@ -885,7 +884,6 @@
if (VDBG) {
log("notifySignalStrengthForPhoneId: subId=" + subId
+" phoneId=" + phoneId + " signalStrength=" + signalStrength);
- toStringLogSSC("notifySignalStrengthForPhoneId");
}
synchronized (mRecords) {
@@ -1137,18 +1135,20 @@
modified = true;
}
if (modified) {
- if (DBG) {
- log("onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
- + ", " + mDataConnectionNetworkType[phoneId] + ")");
- }
+ String str = "onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
+ + ", " + mDataConnectionNetworkType[phoneId] + ")";
+ log(str);
+ mLocalLog.log(str);
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) &&
idMatch(r.subId, subId, phoneId)) {
try {
- log("Notify data connection state changed on sub: " +
- subId);
- r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+ if (DBG) {
+ log("Notify data connection state changed on sub: " + subId);
+ }
+ r.callback.onDataConnectionStateChanged(
+ mDataConnectionState[phoneId],
mDataConnectionNetworkType[phoneId]);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
@@ -1163,7 +1163,8 @@
if (r.matchPhoneStateListenerEvent(
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) {
try {
- r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
+ r.callback.onPreciseDataConnectionStateChanged(
+ mPreciseDataConnectionState);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -1391,36 +1392,58 @@
}
@Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+
synchronized (mRecords) {
final int recordCount = mRecords.size();
pw.println("last known state:");
+ pw.increaseIndent();
for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
- pw.println(" Phone Id=" + i);
- pw.println(" mCallState=" + mCallState[i]);
- pw.println(" mCallIncomingNumber=" + mCallIncomingNumber[i]);
- pw.println(" mServiceState=" + mServiceState[i]);
- pw.println(" mVoiceActivationState= " + mVoiceActivationState[i]);
- pw.println(" mDataActivationState= " + mDataActivationState[i]);
- pw.println(" mSignalStrength=" + mSignalStrength[i]);
- pw.println(" mMessageWaiting=" + mMessageWaiting[i]);
- pw.println(" mCallForwarding=" + mCallForwarding[i]);
- pw.println(" mDataActivity=" + mDataActivity[i]);
- pw.println(" mDataConnectionState=" + mDataConnectionState[i]);
- pw.println(" mDataConnectionPossible=" + mDataConnectionPossible[i]);
- pw.println(" mDataConnectionReason=" + mDataConnectionReason[i]);
- pw.println(" mDataConnectionApn=" + mDataConnectionApn[i]);
- pw.println(" mDataConnectionLinkProperties=" + mDataConnectionLinkProperties[i]);
- pw.println(" mDataConnectionNetworkCapabilities=" +
+ pw.println("Phone Id=" + i);
+ pw.increaseIndent();
+ pw.println("mCallState=" + mCallState[i]);
+ pw.println("mCallIncomingNumber=" + mCallIncomingNumber[i]);
+ pw.println("mServiceState=" + mServiceState[i]);
+ pw.println("mVoiceActivationState= " + mVoiceActivationState[i]);
+ pw.println("mDataActivationState= " + mDataActivationState[i]);
+ pw.println("mSignalStrength=" + mSignalStrength[i]);
+ pw.println("mMessageWaiting=" + mMessageWaiting[i]);
+ pw.println("mCallForwarding=" + mCallForwarding[i]);
+ pw.println("mDataActivity=" + mDataActivity[i]);
+ pw.println("mDataConnectionState=" + mDataConnectionState[i]);
+ pw.println("mDataConnectionPossible=" + mDataConnectionPossible[i]);
+ pw.println("mDataConnectionReason=" + mDataConnectionReason[i]);
+ pw.println("mDataConnectionLinkProperties=" + mDataConnectionLinkProperties[i]);
+ pw.println("mDataConnectionNetworkCapabilities=" +
mDataConnectionNetworkCapabilities[i]);
- pw.println(" mCellLocation=" + mCellLocation[i]);
- pw.println(" mCellInfo=" + mCellInfo.get(i));
+ pw.println("mCellLocation=" + mCellLocation[i]);
+ pw.println("mCellInfo=" + mCellInfo.get(i));
+ pw.decreaseIndent();
}
+ pw.println("mConnectedApns=" + Arrays.toString(mConnectedApns));
+ pw.println("mPreciseDataConnectionState=" + mPreciseDataConnectionState);
+ pw.println("mPreciseCallState=" + mPreciseCallState);
+ pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState);
+ pw.println("mRingingCallState=" + mRingingCallState);
+ pw.println("mForegroundCallState=" + mForegroundCallState);
+ pw.println("mBackgroundCallState=" + mBackgroundCallState);
+ pw.println("mVoLteServiceState=" + mVoLteServiceState);
+
+ pw.decreaseIndent();
+
+ pw.println("local logs:");
+ pw.increaseIndent();
+ mLocalLog.dump(fd, pw, args);
+ pw.decreaseIndent();
pw.println("registrations: count=" + recordCount);
+ pw.increaseIndent();
for (Record r : mRecords) {
- pw.println(" " + r);
+ pw.println(r);
}
+ pw.decreaseIndent();
}
}
@@ -1705,63 +1728,6 @@
Rlog.d(TAG, s);
}
- private static class LogSSC {
- private Time mTime;
- private String mS;
- private int mSubId;
- private int mPhoneId;
- private ServiceState mState;
-
- public void set(Time t, String s, int subId, int phoneId, ServiceState state) {
- mTime = t; mS = s; mSubId = subId; mPhoneId = phoneId; mState = state;
- }
-
- @Override
- public String toString() {
- return mS + " Time " + mTime.toString() + " mSubId " + mSubId + " mPhoneId "
- + mPhoneId + " mState " + mState;
- }
- }
-
- private LogSSC logSSC [] = new LogSSC[10];
- private int next = 0;
-
- private void logServiceStateChanged(String s, int subId, int phoneId, ServiceState state) {
- if (logSSC == null || logSSC.length == 0) {
- return;
- }
- if (logSSC[next] == null) {
- logSSC[next] = new LogSSC();
- }
- Time t = new Time();
- t.setToNow();
- logSSC[next].set(t, s, subId, phoneId, state);
- if (++next >= logSSC.length) {
- next = 0;
- }
- }
-
- private void toStringLogSSC(String prompt) {
- if (logSSC == null || logSSC.length == 0 || (next == 0 && logSSC[next] == null)) {
- log(prompt + ": logSSC is empty");
- } else {
- // There is at least one element
- log(prompt + ": logSSC.length=" + logSSC.length + " next=" + next);
- int i = next;
- if (logSSC[i] == null) {
- // logSSC is not full so back to the beginning
- i = 0;
- }
- do {
- log(logSSC[i].toString());
- if (++i >= logSSC.length) {
- i = 0;
- }
- } while (i != next);
- log(prompt + ": ----------------");
- }
- }
-
boolean idMatch(int rSubId, int subId, int phoneId) {
if(subId < 0) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index e5b2eca..983c975 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1021,32 +1021,24 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- Slog.d(TAG, "begin setBatteryStateLocked");
- try {
- synchronized (mStats) {
- final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
- if (mStats.isOnBattery() == onBattery) {
- // The battery state has not changed, so we don't need to sync external
- // stats immediately.
- mStats.setBatteryStateLocked(status, health, plugType, level, temp,
- volt,
- chargeUAh, chargeFullUAh);
- return;
- }
+ synchronized (mStats) {
+ final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
+ if (mStats.isOnBattery() == onBattery) {
+ // The battery state has not changed, so we don't need to sync external
+ // stats immediately.
+ mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
+ chargeUAh, chargeFullUAh);
+ return;
}
- } finally {
- Slog.d(TAG, "end setBatteryStateLocked");
}
// Sync external stats first as the battery has changed states. If we don't sync
// immediately here, we may not collect the relevant data later.
updateExternalStatsSync("battery-state", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
- Slog.d(TAG, "begin setBatteryStateLocked");
synchronized (mStats) {
mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
chargeUAh, chargeFullUAh);
}
- Slog.d(TAG, "end setBatteryStateLocked");
}
});
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fe40efb..f62f115 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5753,20 +5753,23 @@
synchronized (mPackages) {
final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
for (int n = 0; n < count; n++) {
- ResolveInfo info = resolvedActivities.get(n);
- String packageName = info.activityInfo.packageName;
- PackageSetting ps = mSettings.mPackages.get(packageName);
+ final ResolveInfo info = resolvedActivities.get(n);
+ final String packageName = info.activityInfo.packageName;
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
- // Try to get the status from User settings first
- long packedStatus = getDomainVerificationStatusLPr(ps, userId);
- int status = (int) (packedStatus >> 32);
- if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS
+ // only check domain verification status if the app is not a browser
+ if (!info.handleAllWebDataURI) {
+ // Try to get the status from User settings first
+ final long packedStatus = getDomainVerificationStatusLPr(ps, userId);
+ final int status = (int) (packedStatus >> 32);
+ if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS
|| status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK) {
- if (DEBUG_EPHEMERAL) {
- Slog.v(TAG, "DENY ephemeral apps;"
- + " pkg: " + packageName + ", status: " + status);
+ if (DEBUG_EPHEMERAL) {
+ Slog.v(TAG, "DENY instant app;"
+ + " pkg: " + packageName + ", status: " + status);
+ }
+ return false;
}
- return false;
}
if (ps.getInstantApp(userId)) {
if (DEBUG_EPHEMERAL) {
diff --git a/services/core/java/com/android/server/vr/CompatibilityDisplay.java b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
index ae1d50f..772fc26 100644
--- a/services/core/java/com/android/server/vr/CompatibilityDisplay.java
+++ b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
@@ -95,20 +95,15 @@
* Creates and Destroys the virtual display depending on the current state of VrMode.
*/
private void updateVirtualDisplay() {
- boolean createVirtualDisplay = "true".equals(SystemProperties.get("vr_virtualdisplay"));
if (DEBUG) {
- Log.i(TAG, "isVrMode: " + mIsVrModeEnabled + ", createVD: " + createVirtualDisplay +
- ", override: " + mIsVrModeOverrideEnabled);
+ Log.i(TAG, "isVrMode: " + mIsVrModeEnabled + ", override: " + mIsVrModeOverrideEnabled);
}
- if (mIsVrModeEnabled || (createVirtualDisplay && mIsVrModeOverrideEnabled)) {
+ if (mIsVrModeEnabled || mIsVrModeOverrideEnabled) {
// TODO: Consider not creating the display until ActivityManager needs one on
// which to display a 2D application.
- // TODO: STOPSHIP Remove createVirtualDisplay conditional before launching.
- if (createVirtualDisplay) {
- startVirtualDisplay();
- startImageReader();
- }
+ startVirtualDisplay();
+ startImageReader();
} else {
// Stop virtual display to test exit condition
stopVirtualDisplay();
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 1decf4e..a8664a5 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -505,6 +505,13 @@
getController().removeStartingWindow();
}
+ // If this window was animating, then we need to ensure that the app transition notifies
+ // that animations have completed in WMS.handleAnimatingStoppedAndTransitionLocked(), so
+ // add to that list now
+ if (mAppAnimator.animating) {
+ mService.mNoAnimationNotifyOnTransitionFinished.add(token);
+ }
+
final TaskStack stack = getTask().mStack;
if (delayed && !isEmpty()) {
// set the token aside because it has an active animation to be finished
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 9f0ed21..7b8057ca 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -61,17 +61,21 @@
extends WindowManagerInternal.AppTransitionListener implements Runnable {
public void onAppTransitionCancelledLocked() {
+ if (DEBUG) Slog.d(TAG, "onAppTransitionCancelledLocked:"
+ + " mFinishAnimationAfterTransition=" + mFinishAnimationAfterTransition);
animationFinished();
}
public void onAppTransitionFinishedLocked(IBinder token) {
+ if (DEBUG) Slog.d(TAG, "onAppTransitionFinishedLocked:"
+ + " mFinishAnimationAfterTransition=" + mFinishAnimationAfterTransition);
animationFinished();
}
private void animationFinished() {
if (mFinishAnimationAfterTransition) {
mHandler.removeCallbacks(this);
- // This might end up calling into activity manager which will be bad since we have the
- // window manager lock held at this point. Post a message to take care of the processing
- // so we don't deadlock.
+ // This might end up calling into activity manager which will be bad since we have
+ // the window manager lock held at this point. Post a message to take care of the
+ // processing so we don't deadlock.
mHandler.post(this);
}
}
@@ -195,6 +199,7 @@
if (!mTarget.setPinnedStackSize(mTmpRect, mTmpTaskBounds)) {
// Whoops, the target doesn't feel like animating anymore. Let's immediately finish
// any further animation.
+ if (DEBUG) Slog.d(TAG, "animateUpdate: cancelled");
animation.cancel();
}
}
@@ -203,7 +208,9 @@
public void onAnimationEnd(Animator animation) {
if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget
+ " mMoveToFullScreen=" + mMoveToFullScreen
- + " mSkipAnimationEnd=" + mSkipAnimationEnd);
+ + " mSkipAnimationEnd=" + mSkipAnimationEnd
+ + " mFinishAnimationAfterTransition=" + mFinishAnimationAfterTransition
+ + " mAppTransitionIsRunning=" + mAppTransition.isRunning());
// There could be another animation running. For example in the
// move to fullscreen case, recents will also be closing while the
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 3cb96a1..ee2d5de 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -441,6 +441,8 @@
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
appAnimator.clearThumbnail();
appAnimator.setNullAnimation();
+ // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
+ // animating?
wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
wtoken.updateReportedVisibilityLocked();
// Force the allDrawn flag, because we want to start
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a5eac46..63af2da 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -668,6 +668,7 @@
VibratorService vibrator = null;
IStorageManager storageManager = null;
NetworkManagementService networkManagement = null;
+ IpSecService ipSecService = null;
NetworkStatsService networkStats = null;
NetworkPolicyManagerService networkPolicy = null;
ConnectivityService connectivity = null;
@@ -1015,6 +1016,15 @@
reportWtf("starting NetworkManagement Service", e);
}
traceEnd();
+
+ traceBeginAndSlog("StartIpSecService");
+ try {
+ ipSecService = IpSecService.create(context);
+ ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService);
+ } catch (Throwable e) {
+ reportWtf("starting IpSec Service", e);
+ }
+ traceEnd();
}
if (!disableNonCoreServices && !disableTextServices) {
@@ -1628,6 +1638,7 @@
final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
final MediaRouterService mediaRouterF = mediaRouter;
final MmsServiceBroker mmsServiceF = mmsService;
+ final IpSecService ipSecServiceF = ipSecService;
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
@@ -1691,6 +1702,13 @@
.networkScoreAndNetworkManagementServiceReady();
}
traceEnd();
+ traceBeginAndSlog("MakeIpSecServiceReady");
+ try {
+ if (ipSecServiceF != null) ipSecServiceF.systemReady();
+ } catch (Throwable e) {
+ reportWtf("making IpSec Service ready", e);
+ }
+ traceEnd();
traceBeginAndSlog("MakeNetworkStatsServiceReady");
try {
if (networkStatsF != null) networkStatsF.systemReady();
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 590bce1..61a9294 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -23,7 +23,6 @@
import android.net.apf.ApfCapabilities;
import android.net.apf.ApfFilter;
import android.net.DhcpResults;
-import android.net.INetd;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -35,12 +34,10 @@
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpManagerEvent;
import android.net.util.MultinetworkPolicyTracker;
-import android.net.util.NetdService;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.LocalLog;
@@ -1030,16 +1027,14 @@
private boolean startIPv6() {
// Set privacy extensions.
- final String PREFER_TEMPADDRS = "2";
try {
- NetdService.run((INetd netd) -> {
- netd.setProcSysNet(
- INetd.IPV6, INetd.CONF, mInterfaceName, "use_tempaddr",
- PREFER_TEMPADDRS);
- });
+ mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
mNwService.enableIpv6(mInterfaceName);
- } catch (IllegalStateException|RemoteException|ServiceSpecificException e) {
- logError("Unable to change interface settings: %s", e);
+ } catch (RemoteException re) {
+ logError("Unable to change interface settings: %s", re);
+ return false;
+ } catch (IllegalStateException ie) {
+ logError("Unable to change interface settings: %s", ie);
return false;
}