Merge "Track texture memory globally"
diff --git a/Android.mk b/Android.mk
index b95ab2e..e4f40af 100644
--- a/Android.mk
+++ b/Android.mk
@@ -341,6 +341,7 @@
media/java/android/media/IAudioRoutesObserver.aidl \
media/java/android/media/IMediaHTTPConnection.aidl \
media/java/android/media/IMediaHTTPService.aidl \
+ media/java/android/media/IMediaResourceMonitor.aidl \
media/java/android/media/IMediaRouterClient.aidl \
media/java/android/media/IMediaRouterService.aidl \
media/java/android/media/IMediaScannerListener.aidl \
@@ -408,6 +409,7 @@
telephony/java/com/android/internal/telephony/ISms.aidl \
telephony/java/com/android/internal/telephony/ISub.aidl \
telephony/java/com/android/internal/telephony/ITelephony.aidl \
+ telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl \
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
wifi/java/android/net/wifi/IWifiManager.aidl \
@@ -422,7 +424,9 @@
core/java/android/service/quicksettings/IQSTileService.aidl \
# FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
-LOCAL_AIDL_INCLUDES += $(FRAMEWORKS_BASE_JAVA_SRC_DIRS)
+LOCAL_AIDL_INCLUDES += \
+ $(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \
+ frameworks/native/aidl/binder
LOCAL_INTERMEDIATE_SOURCES := \
$(framework_res_source_path)/android/R.java \
@@ -522,7 +526,6 @@
frameworks/base/core/java/android/os/ParcelUuid.aidl \
frameworks/base/core/java/android/os/ParcelFileDescriptor.aidl \
frameworks/base/core/java/android/os/ResultReceiver.aidl \
- frameworks/base/core/java/android/os/PersistableBundle.aidl \
frameworks/base/core/java/android/os/WorkSource.aidl \
frameworks/base/core/java/android/os/DropBoxManager.aidl \
frameworks/base/core/java/android/os/Bundle.aidl \
@@ -630,6 +633,7 @@
frameworks/base/core/java/android/bluetooth/BluetoothDevice.aidl \
frameworks/base/core/java/android/database/CursorWindow.aidl \
frameworks/base/core/java/android/service/quicksettings/Tile.aidl \
+ frameworks/native/aidl/binder/android/os/PersistableBundle.aidl \
gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/framework.aidl
$(gen): PRIVATE_SRC_FILES := $(aidl_files)
diff --git a/api/current.txt b/api/current.txt
index 629d832..05c40d1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -524,6 +524,7 @@
field public static final int expandableListViewStyle = 16842863; // 0x101006f
field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
field public static final int exported = 16842768; // 0x1010010
+ field public static final int externalService = 16844047; // 0x101050f
field public static final int extraTension = 16843371; // 0x101026b
field public static final int extractNativeLibs = 16844010; // 0x10104ea
field public static final int factor = 16843219; // 0x10101d3
@@ -2750,15 +2751,12 @@
method public android.os.Bundle addAccountFromCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
method public abstract android.os.Bundle confirmCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
method public abstract android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, java.lang.String);
- method public android.os.Bundle finishSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
method public android.os.Bundle getAccountCredentialsForCloning(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
method public android.os.Bundle getAccountRemovalAllowed(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
method public abstract android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
method public abstract java.lang.String getAuthTokenLabel(java.lang.String);
method public final android.os.IBinder getIBinder();
method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
- method public android.os.Bundle startAddAccountSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
- method public android.os.Bundle startUpdateCredentialsSession(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
}
@@ -2796,7 +2794,6 @@
method public void clearPassword(android.accounts.Account);
method public android.accounts.AccountManagerFuture<android.os.Bundle> confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(java.lang.String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
- method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public static android.accounts.AccountManager get(android.content.Context);
method public android.accounts.Account[] getAccounts();
method public android.accounts.Account[] getAccountsByType(java.lang.String);
@@ -2824,8 +2821,6 @@
method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
method public void setPassword(android.accounts.Account, java.lang.String);
method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
- method public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
- method public android.accounts.AccountManagerFuture<android.os.Bundle> startUpdateCredentialsSession(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
field public static final java.lang.String ACTION_AUTHENTICATOR_INTENT = "android.accounts.AccountAuthenticator";
field public static final java.lang.String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
@@ -2842,8 +2837,6 @@
field public static final java.lang.String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
field public static final java.lang.String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
field public static final java.lang.String KEY_ACCOUNT_NAME = "authAccount";
- field public static final java.lang.String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
- field public static final java.lang.String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
field public static final java.lang.String KEY_ACCOUNT_TYPE = "accountType";
field public static final java.lang.String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
field public static final java.lang.String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
@@ -3505,6 +3498,7 @@
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public void onProvideAssistContent(android.app.assist.AssistContent);
method public void onProvideAssistData(android.os.Bundle);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public android.net.Uri onProvideReferrer();
method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method protected void onRestart();
@@ -4189,6 +4183,7 @@
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPrepareOptionsMenu(android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public void onRestoreInstanceState(android.os.Bundle);
method public android.os.Bundle onSaveInstanceState();
method public boolean onSearchRequested(android.view.SearchEvent);
@@ -5786,6 +5781,7 @@
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
+ method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
method public boolean getAutoTimeRequired();
@@ -5850,6 +5846,7 @@
method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
method public boolean resetPassword(java.lang.String, int);
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
+ method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String);
@@ -22557,7 +22554,7 @@
method public int[] getObjectHandles(int, int, int);
method public android.mtp.MtpObjectInfo getObjectInfo(int);
method public long getParent(int);
- method public int getPartialObject(int, int, int, byte[]) throws java.io.IOException;
+ method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
method public long getStorageId(int);
method public int[] getStorageIds();
method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -29381,6 +29378,22 @@
field public static final java.lang.String _ID = "_id";
}
+ public class BlockedNumberContract {
+ method public static boolean isBlocked(android.content.Context, java.lang.String);
+ field public static final java.lang.String AUTHORITY = "com.android.blockednumber";
+ field public static final android.net.Uri AUTHORITY_URI;
+ }
+
+ public static class BlockedNumberContract.BlockedNumbers {
+ field public static final java.lang.String COLUMN_E164_NUMBER = "e164_number";
+ field public static final java.lang.String COLUMN_ID = "_id";
+ field public static final java.lang.String COLUMN_ORIGINAL_NUMBER = "original_number";
+ field public static final java.lang.String COLUMN_STRIPPED_NUMBER = "stripped_number";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_numbers";
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
public class Browser {
ctor public Browser();
method public static final void sendString(android.content.Context, java.lang.String);
@@ -33502,6 +33515,7 @@
method public boolean onMenuOpened(int, android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public boolean onSearchRequested(android.view.SearchEvent);
method public boolean onSearchRequested();
method public void onWakeUp();
@@ -33723,17 +33737,24 @@
method public java.lang.CharSequence getContentDescription();
method public android.graphics.drawable.Icon getIcon();
method public java.lang.CharSequence getLabel();
+ method public int getState();
method public void setContentDescription(java.lang.CharSequence);
method public void setIcon(android.graphics.drawable.Icon);
method public void setLabel(java.lang.CharSequence);
+ method public void setState(int);
method public void updateTile();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.quicksettings.Tile> CREATOR;
+ field public static final int STATE_ACTIVE = 2; // 0x2
+ field public static final int STATE_INACTIVE = 1; // 0x1
+ field public static final int STATE_UNAVAILABLE = 0; // 0x0
}
public class TileService extends android.app.Service {
ctor public TileService();
method public final android.service.quicksettings.Tile getQsTile();
+ method public final boolean isLocked();
+ method public final boolean isSecure();
method public android.os.IBinder onBind(android.content.Intent);
method public void onClick();
method public void onStartListening();
@@ -33742,6 +33763,8 @@
method public void onTileRemoved();
method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
method public final void showDialog(android.app.Dialog);
+ method public final void startActivityAndCollapse(android.content.Intent);
+ method public final void unlockAndRun(java.lang.Runnable);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
field public static final int TILE_MODE_ACTIVE = 2; // 0x2
field public static final int TILE_MODE_PASSIVE = 1; // 0x1
@@ -38206,7 +38229,8 @@
ctor public SuggestionSpan(android.os.Parcel);
method public int describeContents();
method public int getFlags();
- method public java.lang.String getLocale();
+ method public deprecated java.lang.String getLocale();
+ method public java.util.Locale getLocaleObject();
method public int getSpanTypeId();
method public java.lang.String[] getSuggestions();
method public void setFlags(int);
@@ -40390,6 +40414,27 @@
method public void startTracking(android.view.KeyEvent, java.lang.Object);
}
+ public final class KeyboardShortcutGroup implements android.os.Parcelable {
+ ctor public KeyboardShortcutGroup(java.lang.CharSequence, java.util.List<android.view.KeyboardShortcutInfo>);
+ ctor public KeyboardShortcutGroup(java.lang.CharSequence);
+ method public void addItem(android.view.KeyboardShortcutInfo);
+ method public int describeContents();
+ method public java.util.List<android.view.KeyboardShortcutInfo> getItems();
+ method public java.lang.CharSequence getLabel();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutGroup> CREATOR;
+ }
+
+ public final class KeyboardShortcutInfo implements android.os.Parcelable {
+ ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int);
+ method public int describeContents();
+ method public char getBaseCharacter();
+ method public java.lang.CharSequence getLabel();
+ method public int getModifiers();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutInfo> CREATOR;
+ }
+
public abstract class LayoutInflater {
ctor protected LayoutInflater(android.content.Context);
ctor protected LayoutInflater(android.view.LayoutInflater, android.content.Context);
@@ -42391,6 +42436,7 @@
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
+ method public abstract void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public abstract boolean onSearchRequested();
method public abstract boolean onSearchRequested(android.view.SearchEvent);
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
diff --git a/api/system-current.txt b/api/system-current.txt
index 6a36ce0..fb47833 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -619,6 +619,7 @@
field public static final int expandableListViewStyle = 16842863; // 0x101006f
field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
field public static final int exported = 16842768; // 0x1010010
+ field public static final int externalService = 16844047; // 0x101050f
field public static final int extraTension = 16843371; // 0x101026b
field public static final int extractNativeLibs = 16844010; // 0x10104ea
field public static final int factor = 16843219; // 0x10101d3
@@ -3611,6 +3612,7 @@
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public void onProvideAssistContent(android.app.assist.AssistContent);
method public void onProvideAssistData(android.os.Bundle);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public android.net.Uri onProvideReferrer();
method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method protected void onRestart();
@@ -4310,6 +4312,7 @@
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPrepareOptionsMenu(android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public void onRestoreInstanceState(android.os.Bundle);
method public android.os.Bundle onSaveInstanceState();
method public boolean onSearchRequested(android.view.SearchEvent);
@@ -5912,6 +5915,7 @@
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
+ method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
method public boolean getAutoTimeRequired();
@@ -5985,6 +5989,7 @@
method public boolean resetPassword(java.lang.String, int);
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
method public deprecated boolean setActiveProfileOwner(android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException;
+ method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String);
@@ -24104,7 +24109,7 @@
method public int[] getObjectHandles(int, int, int);
method public android.mtp.MtpObjectInfo getObjectInfo(int);
method public long getParent(int);
- method public int getPartialObject(int, int, int, byte[]) throws java.io.IOException;
+ method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
method public long getStorageId(int);
method public int[] getStorageIds();
method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -31386,6 +31391,22 @@
field public static final java.lang.String _ID = "_id";
}
+ public class BlockedNumberContract {
+ method public static boolean isBlocked(android.content.Context, java.lang.String);
+ field public static final java.lang.String AUTHORITY = "com.android.blockednumber";
+ field public static final android.net.Uri AUTHORITY_URI;
+ }
+
+ public static class BlockedNumberContract.BlockedNumbers {
+ field public static final java.lang.String COLUMN_E164_NUMBER = "e164_number";
+ field public static final java.lang.String COLUMN_ID = "_id";
+ field public static final java.lang.String COLUMN_ORIGINAL_NUMBER = "original_number";
+ field public static final java.lang.String COLUMN_STRIPPED_NUMBER = "stripped_number";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_numbers";
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
public class Browser {
ctor public Browser();
method public static final void sendString(android.content.Context, java.lang.String);
@@ -35640,6 +35661,7 @@
method public boolean onMenuOpened(int, android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public boolean onSearchRequested(android.view.SearchEvent);
method public boolean onSearchRequested();
method public void onWakeUp();
@@ -35893,17 +35915,24 @@
method public java.lang.CharSequence getContentDescription();
method public android.graphics.drawable.Icon getIcon();
method public java.lang.CharSequence getLabel();
+ method public int getState();
method public void setContentDescription(java.lang.CharSequence);
method public void setIcon(android.graphics.drawable.Icon);
method public void setLabel(java.lang.CharSequence);
+ method public void setState(int);
method public void updateTile();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.quicksettings.Tile> CREATOR;
+ field public static final int STATE_ACTIVE = 2; // 0x2
+ field public static final int STATE_INACTIVE = 1; // 0x1
+ field public static final int STATE_UNAVAILABLE = 0; // 0x0
}
public class TileService extends android.app.Service {
ctor public TileService();
method public final android.service.quicksettings.Tile getQsTile();
+ method public final boolean isLocked();
+ method public final boolean isSecure();
method public android.os.IBinder onBind(android.content.Intent);
method public void onClick();
method public void onStartListening();
@@ -35913,6 +35942,8 @@
method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
method public final void setStatusIcon(android.graphics.drawable.Icon, java.lang.String);
method public final void showDialog(android.app.Dialog);
+ method public final void startActivityAndCollapse(android.content.Intent);
+ method public final void unlockAndRun(java.lang.Runnable);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
field public static final int TILE_MODE_ACTIVE = 2; // 0x2
field public static final int TILE_MODE_PASSIVE = 1; // 0x1
@@ -40557,7 +40588,8 @@
ctor public SuggestionSpan(android.os.Parcel);
method public int describeContents();
method public int getFlags();
- method public java.lang.String getLocale();
+ method public deprecated java.lang.String getLocale();
+ method public java.util.Locale getLocaleObject();
method public int getSpanTypeId();
method public java.lang.String[] getSuggestions();
method public void setFlags(int);
@@ -42741,6 +42773,27 @@
method public void startTracking(android.view.KeyEvent, java.lang.Object);
}
+ public final class KeyboardShortcutGroup implements android.os.Parcelable {
+ ctor public KeyboardShortcutGroup(java.lang.CharSequence, java.util.List<android.view.KeyboardShortcutInfo>);
+ ctor public KeyboardShortcutGroup(java.lang.CharSequence);
+ method public void addItem(android.view.KeyboardShortcutInfo);
+ method public int describeContents();
+ method public java.util.List<android.view.KeyboardShortcutInfo> getItems();
+ method public java.lang.CharSequence getLabel();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutGroup> CREATOR;
+ }
+
+ public final class KeyboardShortcutInfo implements android.os.Parcelable {
+ ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int);
+ method public int describeContents();
+ method public char getBaseCharacter();
+ method public java.lang.CharSequence getLabel();
+ method public int getModifiers();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutInfo> CREATOR;
+ }
+
public abstract class LayoutInflater {
ctor protected LayoutInflater(android.content.Context);
ctor protected LayoutInflater(android.view.LayoutInflater, android.content.Context);
@@ -44743,6 +44796,7 @@
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
+ method public abstract void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public abstract boolean onSearchRequested();
method public abstract boolean onSearchRequested(android.view.SearchEvent);
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
diff --git a/api/test-current.txt b/api/test-current.txt
index 21b101f..3fb9b5f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -524,6 +524,7 @@
field public static final int expandableListViewStyle = 16842863; // 0x101006f
field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
field public static final int exported = 16842768; // 0x1010010
+ field public static final int externalService = 16844047; // 0x101050f
field public static final int extraTension = 16843371; // 0x101026b
field public static final int extractNativeLibs = 16844010; // 0x10104ea
field public static final int factor = 16843219; // 0x10101d3
@@ -2750,15 +2751,12 @@
method public android.os.Bundle addAccountFromCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
method public abstract android.os.Bundle confirmCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
method public abstract android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, java.lang.String);
- method public android.os.Bundle finishSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
method public android.os.Bundle getAccountCredentialsForCloning(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
method public android.os.Bundle getAccountRemovalAllowed(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
method public abstract android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
method public abstract java.lang.String getAuthTokenLabel(java.lang.String);
method public final android.os.IBinder getIBinder();
method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
- method public android.os.Bundle startAddAccountSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
- method public android.os.Bundle startUpdateCredentialsSession(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
}
@@ -2796,7 +2794,6 @@
method public void clearPassword(android.accounts.Account);
method public android.accounts.AccountManagerFuture<android.os.Bundle> confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(java.lang.String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
- method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public static android.accounts.AccountManager get(android.content.Context);
method public android.accounts.Account[] getAccounts();
method public android.accounts.Account[] getAccountsByType(java.lang.String);
@@ -2824,8 +2821,6 @@
method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
method public void setPassword(android.accounts.Account, java.lang.String);
method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
- method public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
- method public android.accounts.AccountManagerFuture<android.os.Bundle> startUpdateCredentialsSession(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
field public static final java.lang.String ACTION_AUTHENTICATOR_INTENT = "android.accounts.AccountAuthenticator";
field public static final java.lang.String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
@@ -2842,8 +2837,6 @@
field public static final java.lang.String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
field public static final java.lang.String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
field public static final java.lang.String KEY_ACCOUNT_NAME = "authAccount";
- field public static final java.lang.String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
- field public static final java.lang.String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
field public static final java.lang.String KEY_ACCOUNT_TYPE = "accountType";
field public static final java.lang.String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
field public static final java.lang.String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
@@ -3505,6 +3498,7 @@
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public void onProvideAssistContent(android.app.assist.AssistContent);
method public void onProvideAssistData(android.os.Bundle);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public android.net.Uri onProvideReferrer();
method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method protected void onRestart();
@@ -4189,6 +4183,7 @@
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPrepareOptionsMenu(android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public void onRestoreInstanceState(android.os.Bundle);
method public android.os.Bundle onSaveInstanceState();
method public boolean onSearchRequested(android.view.SearchEvent);
@@ -5788,6 +5783,7 @@
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
+ method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
method public boolean getAutoTimeRequired();
@@ -5852,6 +5848,7 @@
method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
method public boolean resetPassword(java.lang.String, int);
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
+ method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String);
@@ -22565,7 +22562,7 @@
method public int[] getObjectHandles(int, int, int);
method public android.mtp.MtpObjectInfo getObjectInfo(int);
method public long getParent(int);
- method public int getPartialObject(int, int, int, byte[]) throws java.io.IOException;
+ method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
method public long getStorageId(int);
method public int[] getStorageIds();
method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -29393,6 +29390,22 @@
field public static final java.lang.String _ID = "_id";
}
+ public class BlockedNumberContract {
+ method public static boolean isBlocked(android.content.Context, java.lang.String);
+ field public static final java.lang.String AUTHORITY = "com.android.blockednumber";
+ field public static final android.net.Uri AUTHORITY_URI;
+ }
+
+ public static class BlockedNumberContract.BlockedNumbers {
+ field public static final java.lang.String COLUMN_E164_NUMBER = "e164_number";
+ field public static final java.lang.String COLUMN_ID = "_id";
+ field public static final java.lang.String COLUMN_ORIGINAL_NUMBER = "original_number";
+ field public static final java.lang.String COLUMN_STRIPPED_NUMBER = "stripped_number";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_numbers";
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
public class Browser {
ctor public Browser();
method public static final void sendString(android.content.Context, java.lang.String);
@@ -33516,6 +33529,7 @@
method public boolean onMenuOpened(int, android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public boolean onSearchRequested(android.view.SearchEvent);
method public boolean onSearchRequested();
method public void onWakeUp();
@@ -33737,17 +33751,24 @@
method public java.lang.CharSequence getContentDescription();
method public android.graphics.drawable.Icon getIcon();
method public java.lang.CharSequence getLabel();
+ method public int getState();
method public void setContentDescription(java.lang.CharSequence);
method public void setIcon(android.graphics.drawable.Icon);
method public void setLabel(java.lang.CharSequence);
+ method public void setState(int);
method public void updateTile();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.quicksettings.Tile> CREATOR;
+ field public static final int STATE_ACTIVE = 2; // 0x2
+ field public static final int STATE_INACTIVE = 1; // 0x1
+ field public static final int STATE_UNAVAILABLE = 0; // 0x0
}
public class TileService extends android.app.Service {
ctor public TileService();
method public final android.service.quicksettings.Tile getQsTile();
+ method public final boolean isLocked();
+ method public final boolean isSecure();
method public android.os.IBinder onBind(android.content.Intent);
method public void onClick();
method public void onStartListening();
@@ -33756,6 +33777,8 @@
method public void onTileRemoved();
method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
method public final void showDialog(android.app.Dialog);
+ method public final void startActivityAndCollapse(android.content.Intent);
+ method public final void unlockAndRun(java.lang.Runnable);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
field public static final int TILE_MODE_ACTIVE = 2; // 0x2
field public static final int TILE_MODE_PASSIVE = 1; // 0x1
@@ -38222,7 +38245,8 @@
ctor public SuggestionSpan(android.os.Parcel);
method public int describeContents();
method public int getFlags();
- method public java.lang.String getLocale();
+ method public deprecated java.lang.String getLocale();
+ method public java.util.Locale getLocaleObject();
method public int getSpanTypeId();
method public java.lang.String[] getSuggestions();
method public void setFlags(int);
@@ -40406,6 +40430,27 @@
method public void startTracking(android.view.KeyEvent, java.lang.Object);
}
+ public final class KeyboardShortcutGroup implements android.os.Parcelable {
+ ctor public KeyboardShortcutGroup(java.lang.CharSequence, java.util.List<android.view.KeyboardShortcutInfo>);
+ ctor public KeyboardShortcutGroup(java.lang.CharSequence);
+ method public void addItem(android.view.KeyboardShortcutInfo);
+ method public int describeContents();
+ method public java.util.List<android.view.KeyboardShortcutInfo> getItems();
+ method public java.lang.CharSequence getLabel();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutGroup> CREATOR;
+ }
+
+ public final class KeyboardShortcutInfo implements android.os.Parcelable {
+ ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int);
+ method public int describeContents();
+ method public char getBaseCharacter();
+ method public java.lang.CharSequence getLabel();
+ method public int getModifiers();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutInfo> CREATOR;
+ }
+
public abstract class LayoutInflater {
ctor protected LayoutInflater(android.content.Context);
ctor protected LayoutInflater(android.view.LayoutInflater, android.content.Context);
@@ -42407,6 +42452,7 @@
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
+ method public abstract void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public abstract boolean onSearchRequested();
method public abstract boolean onSearchRequested(android.view.SearchEvent);
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index a312e3f..690e674 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -25,6 +25,7 @@
import android.content.Context;
import android.content.Intent;
import android.Manifest;
+import android.annotation.SystemApi;
import android.util.Log;
import java.util.Arrays;
@@ -762,7 +763,9 @@
* @throws NetworkErrorException if the authenticator could not honor the
* request due to a network error
* @see #finishSession(AccountAuthenticatorResponse, String, Bundle)
+ * @hide
*/
+ @SystemApi
public Bundle startAddAccountSession(
final AccountAuthenticatorResponse response,
final String accountType,
@@ -818,7 +821,9 @@
* @throws NetworkErrorException if the authenticator could not honor the
* request due to a network error
* @see #finishSession(AccountAuthenticatorResponse, String, Bundle)
+ * @hide
*/
+ @SystemApi
public Bundle startUpdateCredentialsSession(
final AccountAuthenticatorResponse response,
final Account account,
@@ -870,7 +875,9 @@
* </ul>
* @throws NetworkErrorException
* @see #startAddAccountSession and #startUpdateCredentialsSession
+ * @hide
*/
+ @SystemApi
public Bundle finishSession(
final AccountAuthenticatorResponse response,
final String accountType,
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index ada1ac2..2449ee5 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.Size;
+import android.annotation.SystemApi;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -244,14 +245,18 @@
* Bundle key used for a {@link Bundle} in result from
* {@link #startAddAccountSession} and friends which returns session data
* for installing an account later.
+ * @hide
*/
+ @SystemApi
public static final String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
/**
* Bundle key used for the {@link String} account status token in result
* from {@link #startAddAccountSession} and friends which returns
* information about a particular account.
+ * @hide
*/
+ @SystemApi
public static final String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
public static final String ACTION_AUTHENTICATOR_INTENT =
@@ -2667,7 +2672,9 @@
* trouble
* </ul>
* @see #finishSession
+ * @hide
*/
+ @SystemApi
public AccountManagerFuture<Bundle> startAddAccountSession(
final String accountType,
final String authTokenType,
@@ -2749,7 +2756,9 @@
* trouble
* </ul>
* @see #finishSession
+ * @hide
*/
+ @SystemApi
public AccountManagerFuture<Bundle> startUpdateCredentialsSession(
final Account account,
final String authTokenType,
@@ -2818,7 +2827,9 @@
* trouble
* </ul>
* @see #startAddAccountSession and #startUpdateCredentialsSession
+ * @hide
*/
+ @SystemApi
public AccountManagerFuture<Bundle> finishSession(
final Bundle sessionBundle,
final Activity activity,
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 7f9a5d3..e721de9 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -17,6 +17,7 @@
package android.animation;
import android.annotation.CallSuper;
+import android.annotation.IntDef;
import android.os.Looper;
import android.os.Trace;
import android.util.AndroidRuntimeException;
@@ -25,6 +26,8 @@
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashMap;
@@ -234,6 +237,11 @@
* Public constants
*/
+ /** @hide */
+ @IntDef({RESTART, REVERSE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RepeatMode {}
+
/**
* When the animation reaches the end and <code>repeatCount</code> is INFINITE
* or a positive value, the animation restarts from the beginning.
@@ -807,7 +815,7 @@
*
* @param value {@link #RESTART} or {@link #REVERSE}
*/
- public void setRepeatMode(int value) {
+ public void setRepeatMode(@RepeatMode int value) {
mRepeatMode = value;
}
@@ -816,6 +824,7 @@
*
* @return either one of {@link #REVERSE} or {@link #RESTART}
*/
+ @RepeatMode
public int getRepeatMode() {
return mRepeatMode;
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 34527c26..e312596 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -62,6 +62,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.net.Uri;
@@ -71,6 +72,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcelable;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.StrictMode;
import android.os.UserHandle;
@@ -78,23 +80,28 @@
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
+import android.transition.Scene;
+import android.transition.TransitionManager;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SuperNotCalledException;
import android.view.ActionMode;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
+import android.view.KeyboardShortcutInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
-import com.android.internal.policy.PhoneWindow;
import android.view.SearchEvent;
import android.view.View;
import android.view.View.OnCreateContextMenuListener;
@@ -103,10 +110,17 @@
import android.view.ViewManager;
import android.view.ViewRootImpl;
import android.view.Window;
+import android.view.Window.WindowControllerCallback;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView;
+import android.widget.Toolbar;
+
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.ToolbarActionBar;
+import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.policy.PhoneWindow;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -116,6 +130,8 @@
import java.util.HashMap;
import java.util.List;
+import static java.lang.Character.MIN_VALUE;
+
/**
* An activity is a single, focused thing that the user can do. Almost all
* activities interact with the user, so the Activity class takes care of
@@ -1594,6 +1610,30 @@
public void onProvideAssistContent(AssistContent outContent) {
}
+ @Override
+ public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
+ if (menu == null) {
+ return;
+ }
+ KeyboardShortcutGroup group = null;
+ int menuSize = menu.size();
+ for (int i = 0; i < menuSize; ++i) {
+ final MenuItem item = menu.getItem(i);
+ final CharSequence title = item.getTitle();
+ final char alphaShortcut = item.getAlphabeticShortcut();
+ if (title != null && alphaShortcut != MIN_VALUE) {
+ if (group == null) {
+ group = new KeyboardShortcutGroup(null /* no label */);
+ }
+ group.addItem(new KeyboardShortcutInfo(
+ title, alphaShortcut, KeyEvent.META_CTRL_ON));
+ }
+ }
+ if (group != null) {
+ data.add(group);
+ }
+ }
+
/**
* Ask to have the current assistant shown to the user. This only works if the calling
* activity is the current foreground activity. It is the same as calling
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 624131e..94b4e7f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2842,6 +2842,14 @@
reply.writeNoException();
return true;
}
+ case IS_APP_FOREGROUND_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final int userHandle = data.readInt();
+ final boolean isForeground = isAppForeground(userHandle);
+ reply.writeNoException();
+ reply.writeInt(isForeground ? 1 : 0);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -6639,5 +6647,18 @@
reply.recycle();
}
+ @Override
+ public boolean isAppForeground(int uid) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(uid);
+ mRemote.transact(IS_APP_FOREGROUND_TRANSACTION, data, reply, 0);
+ final boolean isForeground = reply.readInt() == 1 ? true : false;
+ data.recycle();
+ reply.recycle();
+ return isForeground;
+ };
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index e28fb20..af840d0 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -894,7 +894,9 @@
final View decor = getDecor();
if (decor != null) {
final ViewRootImpl viewRoot = decor.getViewRootImpl();
- viewRoot.setPausedForTransition(false);
+ if (viewRoot != null) {
+ viewRoot.setPausedForTransition(false);
+ }
}
onTransitionsComplete();
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 6e8e2c4..79461b4 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -21,9 +21,8 @@
import android.annotation.IdRes;
import android.annotation.LayoutRes;
import android.annotation.NonNull;
-import android.annotation.StringRes;
-
import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.annotation.StyleRes;
import android.content.ComponentName;
import android.content.Context;
@@ -44,11 +43,11 @@
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
-import com.android.internal.policy.PhoneWindow;
import android.view.SearchEvent;
import android.view.View;
import android.view.View.OnCreateContextMenuListener;
@@ -60,8 +59,10 @@
import com.android.internal.R;
import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.policy.PhoneWindow;
import java.lang.ref.WeakReference;
+import java.util.List;
/**
* Base class for Dialogs.
@@ -1081,6 +1082,13 @@
}
/**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
+ }
+
+ /**
* @return The activity associated with this dialog, or null if there is no associated activity.
*/
private ComponentName getAssociatedActivity() {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 1ae91a6..10885f2 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -589,6 +589,8 @@
public void setVrMode(IBinder token, boolean enabled) throws RemoteException;
+ public boolean isAppForeground(int uid) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -960,4 +962,5 @@
int SET_VR_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 359;
int GET_GRANTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 360;
int CLEAR_GRANTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 361;
+ int IS_APP_FOREGROUND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 362;
}
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 13e27e2..bd10267 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -28,6 +28,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.view.IWindowManager;
import android.view.InputEvent;
import android.view.SurfaceControl;
@@ -167,9 +168,10 @@
throwIfShutdownLocked();
throwIfNotConnectedLocked();
}
+ int callingUserId = UserHandle.getCallingUserId();
final long identity = Binder.clearCallingIdentity();
try {
- IBinder token = mAccessibilityManager.getWindowToken(windowId);
+ IBinder token = mAccessibilityManager.getWindowToken(windowId, callingUserId);
if (token == null) {
return false;
}
@@ -186,9 +188,10 @@
throwIfShutdownLocked();
throwIfNotConnectedLocked();
}
+ int callingUserId = UserHandle.getCallingUserId();
final long identity = Binder.clearCallingIdentity();
try {
- IBinder token = mAccessibilityManager.getWindowToken(windowId);
+ IBinder token = mAccessibilityManager.getWindowToken(windowId, callingUserId);
if (token == null) {
return null;
}
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 44164158..56b4249 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -16,12 +16,16 @@
package android.app;
+import android.annotation.IntDef;
import android.content.Context;
import android.content.res.Configuration;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* This class provides access to the system uimode services. These services
* allow applications to control UI modes of the device.
@@ -92,18 +96,26 @@
* when the user exits desk mode.
*/
public static String ACTION_EXIT_DESK_MODE = "android.app.action.EXIT_DESK_MODE";
-
- /** Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
+
+ /** @hide */
+ @IntDef({MODE_NIGHT_AUTO, MODE_NIGHT_NO, MODE_NIGHT_YES})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NightMode {}
+
+ /**
+ * Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
* automatically switch night mode on and off based on the time.
*/
public static final int MODE_NIGHT_AUTO = Configuration.UI_MODE_NIGHT_UNDEFINED >> 4;
- /** Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
+ /**
+ * Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
* never run in night mode.
*/
public static final int MODE_NIGHT_NO = Configuration.UI_MODE_NIGHT_NO >> 4;
- /** Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
+ /**
+ * Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
* always run in night mode.
*/
public static final int MODE_NIGHT_YES = Configuration.UI_MODE_NIGHT_YES >> 4;
@@ -195,20 +207,28 @@
}
/**
- * Sets the night mode. Changes to the night mode are only effective when
- * the car or desk mode is enabled on a device.
- *
- * <p>The mode can be one of:
+ * Sets the night mode.
+ * <p>
+ * The mode can be one of:
* <ul>
- * <li><em>{@link #MODE_NIGHT_NO}<em> - sets the device into notnight
- * mode.</li>
- * <li><em>{@link #MODE_NIGHT_YES}</em> - sets the device into night mode.
- * </li>
- * <li><em>{@link #MODE_NIGHT_AUTO}</em> - automatic night/notnight switching
- * depending on the location and certain other sensors.</li>
+ * <li><em>{@link #MODE_NIGHT_NO}<em> sets the device into
+ * {@code notnight} mode</li>
+ * <li><em>{@link #MODE_NIGHT_YES}</em> sets the device into
+ * {@code night} mode</li>
+ * <li><em>{@link #MODE_NIGHT_AUTO}</em> automatically switches between
+ * {@code night} and {@code notnight} based on the device's current
+ * location and certain other sensors</li>
* </ul>
+ * <p>
+ * <strong>Note:</strong> On API 22 and below, changes to the night mode
+ * are only effective when the {@link Configuration#UI_MODE_TYPE_CAR car}
+ * or {@link Configuration#UI_MODE_TYPE_DESK desk} mode is enabled on a
+ * device. Starting in API 23, changes to night mode are always effective.
+ *
+ * @param mode the night mode to set
+ * @see #getNightMode()
*/
- public void setNightMode(int mode) {
+ public void setNightMode(@NightMode int mode) {
if (mService != null) {
try {
mService.setNightMode(mode);
@@ -219,11 +239,20 @@
}
/**
- * @return the currently configured night mode. May be one of
- * {@link #MODE_NIGHT_NO}, {@link #MODE_NIGHT_YES},
- * {@link #MODE_NIGHT_AUTO}, or -1 on error.
+ * Returns the currently configured night mode.
+ * <p>
+ * May be one of:
+ * <ul>
+ * <li>{@link #MODE_NIGHT_NO}</li>
+ * <li>{@link #MODE_NIGHT_YES}</li>
+ * <li>{@link #MODE_NIGHT_AUTO}</li>
+ * <li>{@code -1} on error</li>
+ * </ul>
+ *
+ * @return the current night mode, or {@code -1} on error
+ * @see #setNightMode(int)
*/
- public int getNightMode() {
+ public @NightMode int getNightMode() {
if (mService != null) {
try {
return mService.getNightMode();
@@ -250,9 +279,13 @@
}
/**
- * @return If Night mode is locked or not. When Night mode is locked, changing Night mode
- * is only allowed to privileged system components and normal application's call
- * to change Night mode using {@link #setNightMode(int)} will silently fail.
+ * Returns whether night mode is locked or not.
+ * <p>
+ * When night mode is locked, only privileged system components may change
+ * night mode and calls from non-privileged applications to change night
+ * mode will fail silently.
+ *
+ * @return {@code true} if night mode is locked or {@code false} otherwise
*/
public boolean isNightModeLocked() {
if (mService != null) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index bebc8cf..c7f11e2 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2451,6 +2451,53 @@
}
/**
+ * Called by a device or profile owner to configure an always-on VPN connection through a
+ * specific application for the current user.
+ * This connection is automatically granted and persisted after a reboot.
+ *
+ * <p>The designated package should declare a {@link android.net.VpnService} in its
+ * manifest guarded by {@link android.Manifest.permission#BIND_VPN_SERVICE},
+ * otherwise the call will fail.
+ *
+ * @param vpnPackage The package name for an installed VPN app on the device, or {@code null}
+ * to remove an existing always-on VPN configuration.
+ *
+ * @return {@code true} if the package is set as always-on VPN controller;
+ * {@code false} otherwise.
+ */
+ public boolean setAlwaysOnVpnPackage(@NonNull ComponentName admin,
+ @Nullable String vpnPackage) {
+ if (mService != null) {
+ try {
+ return mService.setAlwaysOnVpnPackage(admin, vpnPackage);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Called by a device or profile owner to read the name of the package administering an
+ * always-on VPN connection for the current user.
+ * If there is no such package, or the always-on VPN is provided by the system instead
+ * of by an application, {@code null} will be returned.
+ *
+ * @return Package name of VPN controller responsible for always-on VPN,
+ * or {@code null} if none is set.
+ */
+ public String getAlwaysOnVpnPackage(@NonNull ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getAlwaysOnVpnPackage(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return null;
+ }
+
+ /**
* Called by an application that is administering the device to disable all cameras
* on the device, for this user. After setting this, no applications running as this user
* will be able to access any cameras on the device.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 995ce00..7771440 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -144,6 +144,9 @@
void setCertInstallerPackage(in ComponentName who, String installerPackage);
String getCertInstallerPackage(in ComponentName who);
+ boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage);
+ String getAlwaysOnVpnPackage(in ComponentName who);
+
void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 84f6f3d..e9d83eb 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -329,6 +329,15 @@
public static final int BIND_NOT_VISIBLE = 0x40000000;
/**
+ * Flag for {@link #bindService}: The service being bound is an
+ * {@link android.R.attr#isolatedProcess isolated},
+ * {@link android.R.attr#externalService external} service. This binds the service into the
+ * calling application's package, rather than the package in which the service is declared.
+ * @hide
+ */
+ public static final int BIND_EXTERNAL_SERVICE = 0x80000000;
+
+ /**
* Returns an AssetManager instance for the application's package.
* <p>
* <strong>Note:</strong> Implementations of this method should return
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 35cd2be..e7f886d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3034,6 +3034,24 @@
public static final String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON";
/**
+ * Broadcast Action: Sent when media resource is granted.
+ * <p>
+ * {@link #EXTRA_PACKAGES} specifies the packages on the process holding the media resource
+ * granted.
+ * </p>
+ * <p class="note">
+ * This is a protected intent that can only be sent by the system.
+ * </p>
+ * <p class="note">
+ * This requires {@link android.Manifest.permission#RECEIVE_MEDIA_RESOURCE_USAGE} permission.
+ * </p>
+ *
+ * @hide
+ */
+ public static final String ACTION_MEDIA_RESOURCE_GRANTED =
+ "android.intent.action.MEDIA_RESOURCE_GRANTED";
+
+ /**
* Activity Action: Allow the user to select and return one or more existing
* documents. When invoked, the system will display the various
* {@link DocumentsProvider} instances installed on the device, letting the
@@ -4077,6 +4095,34 @@
* Optional boolean extra indicating whether quiet mode has been switched on or off.
*/
public static final String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
+
+ /**
+ * Used as an int extra field in {@link #ACTION_MEDIA_RESOURCE_GRANTED}
+ * intents to specify the resource type granted. Possible values are
+ * {@link #EXTRA_MEDIA_RESOURCE_TYPE_VIDEO_CODEC} or
+ * {@link #EXTRA_MEDIA_RESOURCE_TYPE_AUDIO_CODEC}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_MEDIA_RESOURCE_TYPE =
+ "android.intent.extra.MEDIA_RESOURCE_TYPE";
+
+ /**
+ * Used as an int value for {@link #EXTRA_MEDIA_RESOURCE_TYPE}
+ * to represent that a video codec is allowed to use.
+ *
+ * @hide
+ */
+ public static final int EXTRA_MEDIA_RESOURCE_TYPE_VIDEO_CODEC = 0;
+
+ /**
+ * Used as an int value for {@link #EXTRA_MEDIA_RESOURCE_TYPE}
+ * to represent that a audio codec is allowed to use.
+ *
+ * @hide
+ */
+ public static final int EXTRA_MEDIA_RESOURCE_TYPE_AUDIO_CODEC = 1;
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index a0df610..6d360d7 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3886,6 +3886,11 @@
s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
}
if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestService_externalService,
+ false)) {
+ s.info.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE;
+ }
+ if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestService_singleUser,
false)) {
s.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 74e5c2a..eecf0de 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -49,6 +49,14 @@
public static final int FLAG_ISOLATED_PROCESS = 0x0002;
/**
+ * Bit in {@link #flags}: If set, the service can be bound and run in the
+ * calling application's package, rather than the package in which it is
+ * declared. Set from {@link android.R.attr#externalService} attribute.
+ * @hide
+ */
+ public static final int FLAG_EXTERNAL_SERVICE = 0x0004;
+
+ /**
* Bit in {@link #flags}: If set, a single instance of the service will
* run for all users on the device. Set from the
* {@link android.R.attr#singleUser} attribute.
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 6e02df1..c3a4954 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -89,7 +89,6 @@
new SparseArray<CaptureCallbackHolder>();
private int mRepeatingRequestId = REQUEST_ID_NONE;
- private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
// Map stream IDs to input/output configurations
private SimpleEntry<Integer, InputConfiguration> mConfiguredInput =
new SimpleEntry<>(REQUEST_ID_NONE, null);
@@ -916,11 +915,6 @@
int requestId = mRepeatingRequestId;
mRepeatingRequestId = REQUEST_ID_NONE;
- // Queue for deletion after in-flight requests finish
- if (mCaptureCallbackMap.get(requestId) != null) {
- mRepeatingRequestIdDeletedList.add(requestId);
- }
-
try {
LongParcelable lastFrameNumberRef = new LongParcelable();
mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 176e923..c4f0847 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -17,6 +17,7 @@
import static com.android.internal.util.Preconditions.checkNotNull;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
@@ -686,6 +687,47 @@
}
/**
+ * Configures an always-on VPN connection through a specific application.
+ * This connection is automatically granted and persisted after a reboot.
+ *
+ * <p>The designated package should declare a {@link VpnService} in its
+ * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
+ * otherwise the call will fail.
+ *
+ * @param userId The identifier of the user to set an always-on VPN for.
+ * @param vpnPackage The package name for an installed VPN app on the device, or {@code null}
+ * to remove an existing always-on VPN configuration.
+
+ * @return {@code true} if the package is set as always-on VPN controller;
+ * {@code false} otherwise.
+ * @hide
+ */
+ public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage) {
+ try {
+ return mService.setAlwaysOnVpnPackage(userId, vpnPackage);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the package name of the currently set always-on VPN application.
+ * If there is no always-on VPN set, or the VPN is provided by the system instead
+ * of by an app, {@code null} will be returned.
+ *
+ * @return Package name of VPN controller responsible for always-on VPN,
+ * or {@code null} if none is set.
+ * @hide
+ */
+ public String getAlwaysOnVpnPackageForUser(int userId) {
+ try {
+ return mService.getAlwaysOnVpnPackage(userId);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
* Returns details about the currently active default data network
* for a given uid. This is for internal use only to avoid spying
* other apps.
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index ef91137..569468e 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -117,6 +117,8 @@
VpnInfo[] getAllVpnInfo();
boolean updateLockdownVpn();
+ boolean setAlwaysOnVpnPackage(int userId, String packageName);
+ String getAlwaysOnVpnPackage(int userId);
int checkMobileProvisioning(int suggestedTimeOutMs);
diff --git a/core/java/android/os/PersistableBundle.aidl b/core/java/android/os/PersistableBundle.aidl
deleted file mode 100644
index 94e8607..0000000
--- a/core/java/android/os/PersistableBundle.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-**
-** Copyright 2014, 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.os;
-
-parcelable PersistableBundle cpp_header "binder/PersistableBundle.h";
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
new file mode 100644
index 0000000..03e0e11
--- /dev/null
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2016 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.provider;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * Constants and methods to access blocked phone numbers for incoming calls and texts.
+ *
+ * TODO javadoc
+ * - Proper javadoc tagging.
+ * - Code sample?
+ * - Describe who can access it.
+ */
+public class BlockedNumberContract {
+ private BlockedNumberContract() {
+ }
+
+ /** The authority for the contacts provider */
+ public static final String AUTHORITY = "com.android.blockednumber";
+
+ /** A content:// style uri to the authority for the contacts provider */
+ public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+
+ /**
+ * TODO javadoc
+ *
+ * Constants to interact with the blocked phone number list.
+ */
+ public static class BlockedNumbers {
+ private BlockedNumbers() {
+ }
+
+ /**
+ * TODO javadoc
+ *
+ * Content URI for the blocked numbers.
+ *
+ * Supported operations
+ * blocked
+ * - query
+ * - delete
+ * - insert
+ *
+ * blocked/ID
+ * - query (selection is not supported)
+ * - delete (selection is not supported)
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
+ "blocked");
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} itself providing a directory of blocked phone
+ * numbers.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_numbers";
+
+ /**
+ * The MIME type of a blocked phone number under {@link #CONTENT_URI}.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number";
+
+ /**
+ * Auto-generated ID field which monotonically increases.
+ * <p>TYPE: long</p>
+ */
+ public static final String COLUMN_ID = "_id";
+
+ /**
+ * Phone number to block.
+ * <p>Must be specified in {@code insert}.
+ * <p>TYPE: String</p>
+ */
+ public static final String COLUMN_ORIGINAL_NUMBER = "original_number";
+
+ /**
+ * Phone number to block. The system generates it from {@link #COLUMN_ORIGINAL_NUMBER}
+ * by removing all formatting characters.
+ * <p>Must NOT be specified in {@code insert}.
+ * <p>TYPE: String</p>
+ */
+ public static final String COLUMN_STRIPPED_NUMBER = "stripped_number";
+
+ /**
+ * Phone number to block. The system generates it from {@link #COLUMN_ORIGINAL_NUMBER}
+ * by removing all formatting characters.
+ * <p>Optional in {@code insert}. When not specified, the system tries to generate it
+ * assuming the current country. (Which will still be null if the number is not valid.)
+ * <p>TYPE: String</p>
+ */
+ public static final String COLUMN_E164_NUMBER = "e164_number";
+
+ /** @hide */
+ public static final String COLUMN_INDEX_STRIPPED = "index_stripped";
+
+ /** @hide */
+ public static final String COLUMN_INDEX_E164 = "index_e164";
+ }
+
+ /** @hide */
+ public static final String METHOD_IS_BLOCKED = "is_blocked";
+
+ /** @hide */
+ public static final String RES_NUMBER_IS_BLOCKED = "blocked";
+
+ /**
+ * Returns whether a given number is in the blocked list.
+ *
+ * TODO This should probably catch IllegalArgumentException to guard against the case where
+ * the provider is encrypted or the user is not running.
+ * (See addEntryAndRemoveExpiredEntries() in
+ * http://ag/#/c/844426/3/core/java/android/provider/CallLog.java)
+ */
+ public static boolean isBlocked(Context context, String phoneNumber) {
+ final Bundle res = context.getContentResolver().call(AUTHORITY_URI,
+ METHOD_IS_BLOCKED, phoneNumber, null);
+ return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
+ }
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a6485e4..d23a92f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4429,6 +4429,13 @@
public static final String HTTP_PROXY = Global.HTTP_PROXY;
/**
+ * Package designated as always-on VPN provider.
+ *
+ * @hide
+ */
+ public static final String ALWAYS_ON_VPN_APP = "always_on_vpn_app";
+
+ /**
* Whether applications can be installed for this user via the system's
* {@link Intent#ACTION_INSTALL_PACKAGE} mechanism.
*
@@ -7456,10 +7463,12 @@
* The following keys are supported:
*
* <pre>
- * idle_duration (long)
+ * idle_duration2 (long)
* wallclock_threshold (long)
* parole_interval (long)
* parole_duration (long)
+ *
+ * idle_duration (long) // This is deprecated and used to circumvent b/26355386.
* </pre>
*
* <p>
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index bb46e83..816ecde 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -15,9 +15,6 @@
*/
package android.service.dreams;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
import android.annotation.IdRes;
import android.annotation.LayoutRes;
import android.annotation.Nullable;
@@ -33,27 +30,32 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.MathUtils;
import android.util.Slog;
import android.view.ActionMode;
import android.view.Display;
import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
-import com.android.internal.policy.PhoneWindow;
import android.view.SearchEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
-import android.util.MathUtils;
+import com.android.internal.policy.PhoneWindow;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.DumpUtils.Dump;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
/**
* Extend this class to implement a custom dream (available to the user as a "Daydream").
*
@@ -365,6 +367,11 @@
@Override
public void onActionModeFinished(ActionMode mode) {
}
+
+ /** {@inheritDoc} */
+ @Override
+ public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
+ }
// end Window.Callback methods
// begin public api
diff --git a/core/java/android/service/quicksettings/IQSService.aidl b/core/java/android/service/quicksettings/IQSService.aidl
index 9991d41..4bfc9489 100644
--- a/core/java/android/service/quicksettings/IQSService.aidl
+++ b/core/java/android/service/quicksettings/IQSService.aidl
@@ -27,5 +27,9 @@
void updateStatusIcon(in Tile tile, in Icon icon,
String contentDescription);
void onShowDialog(in Tile tile);
+ void onStartActivity(in Tile tile);
void setTileMode(in ComponentName component, int mode);
+ boolean isLocked();
+ boolean isSecure();
+ void startUnlockAndRun(in Tile tile);
}
diff --git a/core/java/android/service/quicksettings/IQSTileService.aidl b/core/java/android/service/quicksettings/IQSTileService.aidl
index 4997f75..bfde8702 100644
--- a/core/java/android/service/quicksettings/IQSTileService.aidl
+++ b/core/java/android/service/quicksettings/IQSTileService.aidl
@@ -29,4 +29,5 @@
void onStartListening();
void onStopListening();
void onClick(IBinder wtoken);
+ void onUnlockComplete();
}
diff --git a/core/java/android/service/quicksettings/Tile.java b/core/java/android/service/quicksettings/Tile.java
index 6104913..85f1955 100644
--- a/core/java/android/service/quicksettings/Tile.java
+++ b/core/java/android/service/quicksettings/Tile.java
@@ -36,10 +36,37 @@
private static final String TAG = "Tile";
+ /**
+ * This is the default state of any tile, until updated by the {@link TileService}.
+ * <p>
+ * An unavailable state indicates that for some reason this tile is not currently
+ * available to the user for some reason, and will have no click action. The tile's
+ * icon will be tinted differently to reflect this state.
+ */
+ public static final int STATE_UNAVAILABLE = 0;
+
+ /**
+ * This represents a tile that is currently in a disabled state but is still interactable.
+ *
+ * A disabled state indicates that the tile is not currently active (e.g. wifi disconnected or
+ * bluetooth disabled), but is still interactable by the user to modify this state. Tiles
+ * that have boolean states should use this to represent one of their states. The tile's
+ * icon will be tinted differently to reflect this state, but still be distinct from unavailable.
+ */
+ public static final int STATE_INACTIVE = 1;
+
+ /**
+ * This represents a tile that is currently active. (e.g. wifi is connected, bluetooth is on,
+ * cast is casting).
+ */
+ public static final int STATE_ACTIVE = 2;
+
private ComponentName mComponentName;
private Icon mIcon;
private CharSequence mLabel;
private CharSequence mContentDescription;
+ // Default to active until clients of the new API can update.
+ private int mState = STATE_ACTIVE;
private IQSService mService;
@@ -79,6 +106,29 @@
}
/**
+ * The current state of the tile.
+ *
+ * @see #STATE_UNAVAILABLE
+ * @see #STATE_INACTIVE
+ * @see #STATE_ACTIVE
+ */
+ public int getState() {
+ return mState;
+ }
+
+ /**
+ * Sets the current state for the tile.
+ *
+ * Does not take effect until {@link #updateTile()} is called.
+ *
+ * @param state One of {@link #STATE_UNAVAILABLE}, {@link #STATE_INACTIVE},
+ * {@link #STATE_ACTIVE}
+ */
+ public void setState(int state) {
+ mState = state;
+ }
+
+ /**
* Gets the current icon for the tile.
*/
public Icon getIcon() {
@@ -165,6 +215,7 @@
} else {
dest.writeByte((byte) 0);
}
+ dest.writeInt(mState);
TextUtils.writeToParcel(mLabel, dest, flags);
TextUtils.writeToParcel(mContentDescription, dest, flags);
}
@@ -180,6 +231,7 @@
} else {
mIcon = null;
}
+ mState = source.readInt();
mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
}
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 6b12193..c02465b 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -118,6 +118,7 @@
private Tile mTile;
private IBinder mToken;
private IQSService mService;
+ private Runnable mUnlockRunnable;
@Override
public void onDestroy() {
@@ -199,6 +200,8 @@
* This will collapse the Quick Settings panel and show the dialog.
*
* @param dialog Dialog to show.
+ *
+ * @see #isLocked()
*/
public final void showDialog(Dialog dialog) {
dialog.getWindow().getAttributes().token = mToken;
@@ -211,6 +214,67 @@
}
/**
+ * Prompts the user to unlock the device before executing the Runnable.
+ * <p>
+ * The user will be prompted for their current security method if applicable
+ * and if successful, runnable will be executed. The Runnable will not be
+ * executed if the user fails to unlock the device or cancels the operation.
+ */
+ public final void unlockAndRun(Runnable runnable) {
+ mUnlockRunnable = runnable;
+ try {
+ mService.startUnlockAndRun(mTile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Checks if the device is in a secure state.
+ *
+ * TileServices should detect when the device is secure and change their behavior
+ * accordingly.
+ *
+ * @return true if the device is secure.
+ */
+ public final boolean isSecure() {
+ try {
+ return mService.isSecure();
+ } catch (RemoteException e) {
+ return true;
+ }
+ }
+
+ /**
+ * Checks if the lock screen is showing.
+ *
+ * When a device is locked, then {@link #showDialog} will not present a dialog, as it will
+ * be under the lock screen. If the behavior of the Tile is safe to do while locked,
+ * then the user should use {@link #startActivity} to launch an activity on top of the lock
+ * screen, otherwise the tile should use {@link #unlockAndRun(Runnable)} to give the
+ * user their security challenge.
+ *
+ * @return true if the device is locked.
+ */
+ public final boolean isLocked() {
+ try {
+ return mService.isLocked();
+ } catch (RemoteException e) {
+ return true;
+ }
+ }
+
+ /**
+ * Start an activity while collapsing the panel.
+ */
+ public final void startActivityAndCollapse(Intent intent) {
+ startActivity(intent);
+ try {
+ mService.onStartActivity(mTile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Gets the {@link Tile} for this service.
* <p/>
* This tile may be used to get or set the current state for this
@@ -258,6 +322,11 @@
public void onClick(IBinder wtoken) throws RemoteException {
mHandler.obtainMessage(H.MSG_TILE_CLICKED, wtoken).sendToTarget();
}
+
+ @Override
+ public void onUnlockComplete() throws RemoteException{
+ mHandler.sendEmptyMessage(H.MSG_UNLOCK_COMPLETE);
+ }
};
}
@@ -269,6 +338,7 @@
private static final int MSG_TILE_REMOVED = 5;
private static final int MSG_TILE_CLICKED = 6;
private static final int MSG_SET_SERVICE = 7;
+ private static final int MSG_UNLOCK_COMPLETE = 8;
public H(Looper looper) {
super(looper);
@@ -323,6 +393,11 @@
mToken = (IBinder) msg.obj;
TileService.this.onClick();
break;
+ case MSG_UNLOCK_COMPLETE:
+ if (mUnlockRunnable != null) {
+ mUnlockRunnable.run();
+ }
+ break;
}
}
}
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 6b449f9..1b00db2 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -16,6 +16,8 @@
package android.text.style;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
@@ -84,7 +86,15 @@
private int mFlags;
private final String[] mSuggestions;
- private final String mLocaleString;
+ /**
+ * Kept for compatibility for apps that rely on invalid locale strings e.g.
+ * {@code new Locale(" an ", " i n v a l i d ", "data")}, which cannot be handled by
+ * {@link #mLanguageTag}.
+ */
+ @NonNull
+ private final String mLocaleStringForCompatibility;
+ @NonNull
+ private final String mLanguageTag;
private final String mNotificationTargetClassName;
private final String mNotificationTargetPackageName;
private final int mHashCode;
@@ -130,14 +140,18 @@
final int N = Math.min(SUGGESTIONS_MAX_SIZE, suggestions.length);
mSuggestions = Arrays.copyOf(suggestions, N);
mFlags = flags;
+ final Locale sourceLocale;
if (locale != null) {
- mLocaleString = locale.toString();
+ sourceLocale = locale;
} else if (context != null) {
- mLocaleString = context.getResources().getConfiguration().locale.toString();
+ // TODO: Consider to context.getResources().getResolvedLocale() instead.
+ sourceLocale = context.getResources().getConfiguration().locale;
} else {
Log.e("SuggestionSpan", "No locale or context specified in SuggestionSpan constructor");
- mLocaleString = "";
+ sourceLocale = null;
}
+ mLocaleStringForCompatibility = sourceLocale == null ? "" : sourceLocale.toString();
+ mLanguageTag = sourceLocale == null ? "" : sourceLocale.toLanguageTag();
if (context != null) {
mNotificationTargetPackageName = context.getPackageName();
@@ -150,7 +164,8 @@
} else {
mNotificationTargetClassName = "";
}
- mHashCode = hashCodeInternal(mSuggestions, mLocaleString, mNotificationTargetClassName);
+ mHashCode = hashCodeInternal(mSuggestions, mLanguageTag, mLocaleStringForCompatibility,
+ mNotificationTargetClassName);
initStyle(context);
}
@@ -194,7 +209,8 @@
public SuggestionSpan(Parcel src) {
mSuggestions = src.readStringArray();
mFlags = src.readInt();
- mLocaleString = src.readString();
+ mLocaleStringForCompatibility = src.readString();
+ mLanguageTag = src.readString();
mNotificationTargetClassName = src.readString();
mNotificationTargetPackageName = src.readString();
mHashCode = src.readInt();
@@ -214,10 +230,29 @@
}
/**
- * @return the locale of the suggestions
+ * @deprecated use {@link #getLocaleObject()} instead.
+ * @return the locale of the suggestions. An empty string is returned if no locale is specified.
*/
+ @NonNull
+ @Deprecated
public String getLocale() {
- return mLocaleString;
+ return mLocaleStringForCompatibility;
+ }
+
+ /**
+ * Returns a well-formed BCP 47 language tag representation of the suggestions, as a
+ * {@link Locale} object.
+ *
+ * <p><b>Caveat</b>: The returned object is guaranteed to be a a well-formed BCP 47 language tag
+ * representation. For example, this method can return an empty locale rather than returning a
+ * malformed data when this object is initialized with an malformed {@link Locale} object, e.g.
+ * {@code new Locale(" a ", " b c d ", " "}.</p>
+ *
+ * @return the locale of the suggestions. {@code null} is returned if no locale is specified.
+ */
+ @Nullable
+ public Locale getLocaleObject() {
+ return mLanguageTag.isEmpty() ? null : Locale.forLanguageTag(mLanguageTag);
}
/**
@@ -255,7 +290,8 @@
public void writeToParcelInternal(Parcel dest, int flags) {
dest.writeStringArray(mSuggestions);
dest.writeInt(mFlags);
- dest.writeString(mLocaleString);
+ dest.writeString(mLocaleStringForCompatibility);
+ dest.writeString(mLanguageTag);
dest.writeString(mNotificationTargetClassName);
dest.writeString(mNotificationTargetPackageName);
dest.writeInt(mHashCode);
@@ -290,10 +326,10 @@
return mHashCode;
}
- private static int hashCodeInternal(String[] suggestions, String locale,
- String notificationTargetClassName) {
+ private static int hashCodeInternal(String[] suggestions, @NonNull String languageTag,
+ @NonNull String localeStringForCompatibility, String notificationTargetClassName) {
return Arrays.hashCode(new Object[] {Long.valueOf(SystemClock.uptimeMillis()), suggestions,
- locale, notificationTargetClassName});
+ languageTag, localeStringForCompatibility, notificationTargetClassName});
}
public static final Parcelable.Creator<SuggestionSpan> CREATOR =
diff --git a/core/java/android/transition/SidePropagation.java b/core/java/android/transition/SidePropagation.java
index b10f6a0..817541c 100644
--- a/core/java/android/transition/SidePropagation.java
+++ b/core/java/android/transition/SidePropagation.java
@@ -16,6 +16,7 @@
package android.transition;
import android.graphics.Rect;
+import android.transition.Slide.GravityFlag;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@@ -45,7 +46,7 @@
* {@link Gravity#LEFT}, {@link Gravity#TOP}, {@link Gravity#RIGHT},
* {@link Gravity#BOTTOM}, {@link Gravity#START}, or {@link Gravity#END}.
*/
- public void setSide(int side) {
+ public void setSide(@GravityFlag int side) {
mSide = side;
}
diff --git a/core/java/android/transition/Slide.java b/core/java/android/transition/Slide.java
index 9063b43..9af65e4 100644
--- a/core/java/android/transition/Slide.java
+++ b/core/java/android/transition/Slide.java
@@ -17,6 +17,7 @@
import android.animation.Animator;
import android.animation.TimeInterpolator;
+import android.annotation.IntDef;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -27,6 +28,9 @@
import android.view.animation.DecelerateInterpolator;
import com.android.internal.R;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* This transition tracks changes to the visibility of target views in the
* start and end scenes and moves views in or out from one of the edges of the
@@ -42,7 +46,12 @@
private static final TimeInterpolator sAccelerate = new AccelerateInterpolator();
private static final String PROPNAME_SCREEN_POSITION = "android:slide:screenPosition";
private CalculateSlide mSlideCalculator = sCalculateBottom;
- private int mSlideEdge = Gravity.BOTTOM;
+ private @GravityFlag int mSlideEdge = Gravity.BOTTOM;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({Gravity.LEFT, Gravity.TOP, Gravity.RIGHT, Gravity.BOTTOM, Gravity.START, Gravity.END})
+ public @interface GravityFlag {}
private interface CalculateSlide {
@@ -176,7 +185,7 @@
* {@link android.view.Gravity#START}, {@link android.view.Gravity#END}.
* @attr ref android.R.styleable#Slide_slideEdge
*/
- public void setSlideEdge(int slideEdge) {
+ public void setSlideEdge(@GravityFlag int slideEdge) {
switch (slideEdge) {
case Gravity.LEFT:
mSlideCalculator = sCalculateLeft;
@@ -214,6 +223,7 @@
* {@link android.view.Gravity#START}, {@link android.view.Gravity#END}.
* @attr ref android.R.styleable#Slide_slideEdge
*/
+ @GravityFlag
public int getSlideEdge() {
return mSlideEdge;
}
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index e711812..eb95a02 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -16,17 +16,21 @@
package android.transition;
-import com.android.internal.R;
-
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.Animator.AnimatorPauseListener;
+import android.annotation.IntDef;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* This transition tracks changes to the visibility of target views in the
* start and end scenes. Visibility is determined not just by the
@@ -46,6 +50,11 @@
private static final String PROPNAME_PARENT = "android:visibility:parent";
private static final String PROPNAME_SCREEN_LOCATION = "android:visibility:screenLocation";
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag=true, value={MODE_IN, MODE_OUT})
+ @interface VisibilityMode {}
+
/**
* Mode used in {@link #setMode(int)} to make the transition
* operate on targets that are appearing. Maybe be combined with
@@ -99,7 +108,7 @@
* {@link #MODE_IN} and {@link #MODE_OUT}.
* @attr ref android.R.styleable#VisibilityTransition_transitionVisibilityMode
*/
- public void setMode(int mode) {
+ public void setMode(@VisibilityMode int mode) {
if ((mode & ~(MODE_IN | MODE_OUT)) != 0) {
throw new IllegalArgumentException("Only MODE_IN and MODE_OUT flags are allowed");
}
@@ -113,6 +122,7 @@
* {@link #MODE_IN} and {@link #MODE_OUT}.
* @attr ref android.R.styleable#VisibilityTransition_transitionVisibilityMode
*/
+ @VisibilityMode
public int getMode() {
return mMode;
}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 9e478c1..9231394 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -25,6 +25,8 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
+import com.android.internal.os.IResultReceiver;
+
/**
* API back to a client window that the Window Manager uses to inform it of
* interesting things happening.
@@ -83,4 +85,9 @@
* Called for non-application windows when the enter animation has completed.
*/
void dispatchWindowShown();
+
+ /**
+ * Called when Keyboard Shortcuts are requested for the window.
+ */
+ void requestAppKeyboardShortcuts(IResultReceiver receiver);
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 84d312d..b045c17 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -17,6 +17,7 @@
package android.view;
import com.android.internal.app.IAssistScreenshotReceiver;
+import com.android.internal.os.IResultReceiver;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -370,4 +371,11 @@
* @param alpha The translucency of the dim layer, between 0 and 1.
*/
void setResizeDimLayer(boolean visible, int targetStackId, float alpha);
+
+ /**
+ * Requests Keyboard Shortcuts from the displayed window.
+ *
+ * @param receiver The receiver to deliver the results to.
+ */
+ void requestAppKeyboardShortcuts(IResultReceiver receiver);
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index f037958..51e1f4b 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1856,6 +1856,9 @@
case KeyEvent.KEYCODE_MENU:
case KeyEvent.KEYCODE_WAKEUP:
case KeyEvent.KEYCODE_PAIRING:
+ case KeyEvent.KEYCODE_STEM_1:
+ case KeyEvent.KEYCODE_STEM_2:
+ case KeyEvent.KEYCODE_STEM_3:
return true;
}
return false;
diff --git a/core/java/android/view/KeyboardShortcutGroup.java b/core/java/android/view/KeyboardShortcutGroup.java
new file mode 100644
index 0000000..013255b
--- /dev/null
+++ b/core/java/android/view/KeyboardShortcutGroup.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+/**
+ * A group of {@link KeyboardShortcutInfo}.
+ */
+public final class KeyboardShortcutGroup implements Parcelable {
+ private final CharSequence mLabel;
+ private final List<KeyboardShortcutInfo> mItems;
+
+ /**
+ * @param label The title to be used for this group, or null if there is none.
+ * @param items The set of items to be included.
+ */
+ public KeyboardShortcutGroup(@Nullable CharSequence label,
+ @NonNull List<KeyboardShortcutInfo> items) {
+ mLabel = label;
+ mItems = new ArrayList<>(checkNotNull(items));
+ }
+
+ /**
+ * @param label The title to be used for this group, or null if there is none.
+ */
+ public KeyboardShortcutGroup(@Nullable CharSequence label) {
+ this(label, Collections.<KeyboardShortcutInfo>emptyList());
+ }
+
+ private KeyboardShortcutGroup(Parcel source) {
+ mItems = new ArrayList<>();
+ mLabel = source.readCharSequence();
+ source.readTypedList(mItems, KeyboardShortcutInfo.CREATOR);
+ }
+
+ /**
+ * Returns the label to be used to describe this group.
+ */
+ public CharSequence getLabel() {
+ return mLabel;
+ }
+
+ /**
+ * Returns the list of items included in this group.
+ */
+ public List<KeyboardShortcutInfo> getItems() {
+ return mItems;
+ }
+
+ /**
+ * Adds an item to the existing list.
+ *
+ * @param item The item to be added.
+ */
+ public void addItem(KeyboardShortcutInfo item) {
+ mItems.add(item);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeCharSequence(mLabel);
+ dest.writeTypedList(mItems);
+ }
+
+ public static final Creator<KeyboardShortcutGroup> CREATOR =
+ new Creator<KeyboardShortcutGroup>() {
+ public KeyboardShortcutGroup createFromParcel(Parcel source) {
+ return new KeyboardShortcutGroup(source);
+ }
+ public KeyboardShortcutGroup[] newArray(int size) {
+ return new KeyboardShortcutGroup[size];
+ }
+ };
+}
\ No newline at end of file
diff --git a/core/java/android/view/KeyboardShortcutInfo.java b/core/java/android/view/KeyboardShortcutInfo.java
new file mode 100644
index 0000000..2c9006d
--- /dev/null
+++ b/core/java/android/view/KeyboardShortcutInfo.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view;
+
+import android.annotation.Nullable;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+import static java.lang.Character.MIN_VALUE;
+
+/**
+ * Information about a Keyboard Shortcut.
+ */
+public final class KeyboardShortcutInfo implements Parcelable {
+ private final CharSequence mLabel;
+ private final Icon mIcon;
+ private final char mBaseCharacter;
+ private final int mModifiers;
+
+ /**
+ * @param label The label that identifies the action performed by this shortcut.
+ * @param icon An icon that identifies the action performed by this shortcut.
+ * @param baseCharacter The character that triggers the shortcut.
+ * @param modifiers The set of modifiers that, combined with the key, trigger the shortcut.
+ * These should be a combination of {@link KeyEvent#META_CTRL_ON},
+ * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_META_ON} and
+ * {@link KeyEvent#META_ALT_ON}.
+ *
+ * @hide
+ */
+ public KeyboardShortcutInfo(
+ @Nullable CharSequence label, @Nullable Icon icon, char baseCharacter, int modifiers) {
+ mLabel = label;
+ mIcon = icon;
+ checkArgument(baseCharacter != MIN_VALUE);
+ mBaseCharacter = baseCharacter;
+ mModifiers = modifiers;
+ }
+
+ /**
+ * Convenience constructor for shortcuts with a label and no icon.
+ *
+ * @param label The label that identifies the action performed by this shortcut.
+ * @param baseCharacter The character that triggers the shortcut.
+ * @param modifiers The set of modifiers that, combined with the key, trigger the shortcut.
+ * These should be a combination of {@link KeyEvent#META_CTRL_ON},
+ * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_META_ON} and
+ * {@link KeyEvent#META_ALT_ON}.
+ */
+ public KeyboardShortcutInfo(CharSequence label, char baseCharacter, int modifiers) {
+ mLabel = label;
+ checkArgument(baseCharacter != MIN_VALUE);
+ mBaseCharacter = baseCharacter;
+ mModifiers = modifiers;
+ mIcon = null;
+ }
+
+ private KeyboardShortcutInfo(Parcel source) {
+ mLabel = source.readCharSequence();
+ mIcon = (Icon) source.readParcelable(null);
+ mBaseCharacter = (char) source.readInt();
+ mModifiers = source.readInt();
+ }
+
+ /**
+ * Returns the label to be used to describe this shortcut.
+ */
+ @Nullable
+ public CharSequence getLabel() {
+ return mLabel;
+ }
+
+ /**
+ * Returns the icon to be used to describe this shortcut.
+ *
+ * @hide
+ */
+ @Nullable
+ public Icon getIcon() {
+ return mIcon;
+ }
+
+ /**
+ * Returns the base character that, combined with the modifiers, triggers this shortcut.
+ */
+ public char getBaseCharacter() {
+ return mBaseCharacter;
+ }
+
+ /**
+ * Returns the set of modifiers that, combined with the key, trigger this shortcut.
+ */
+ public int getModifiers() {
+ return mModifiers;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeCharSequence(mLabel);
+ dest.writeParcelable(mIcon, 0);
+ dest.writeInt(mBaseCharacter);
+ dest.writeInt(mModifiers);
+ }
+
+ public static final Creator<KeyboardShortcutInfo> CREATOR =
+ new Creator<KeyboardShortcutInfo>() {
+ public KeyboardShortcutInfo createFromParcel(Parcel source) {
+ return new KeyboardShortcutInfo(source);
+ }
+ public KeyboardShortcutInfo[] newArray(int size) {
+ return new KeyboardShortcutInfo[size];
+ }
+ };
+}
\ No newline at end of file
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 68f1ac3..0316506 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -79,10 +79,11 @@
import android.util.SuperNotCalledException;
import android.util.TypedValue;
import android.view.ContextMenu.ContextMenuInfo;
-import android.view.AccessibilityIterators.TextSegmentIterator;
import android.view.AccessibilityIterators.CharacterTextSegmentIterator;
-import android.view.AccessibilityIterators.WordTextSegmentIterator;
import android.view.AccessibilityIterators.ParagraphTextSegmentIterator;
+import android.view.AccessibilityIterators.TextSegmentIterator;
+import android.view.AccessibilityIterators.WordTextSegmentIterator;
+import android.view.ViewGroup.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityEventSource;
import android.view.accessibility.AccessibilityManager;
@@ -3592,9 +3593,6 @@
private int[] mDrawableState = null;
- /** Whether draw() is currently being called. */
- private boolean mInDraw = false;
-
ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND;
/**
@@ -16473,8 +16471,6 @@
*/
@CallSuper
public void draw(Canvas canvas) {
- mInDraw = true;
-
final int privateFlags = mPrivateFlags;
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
@@ -16519,7 +16515,6 @@
onDrawForeground(canvas);
// we're done...
- mInDraw = false;
return;
}
@@ -16667,8 +16662,6 @@
// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);
-
- mInDraw = false;
}
/**
@@ -17113,8 +17106,7 @@
*/
@Override
public void invalidateDrawable(@NonNull Drawable drawable) {
- // Don't invalidate if a drawable changes during drawing.
- if (verifyDrawable(drawable) && !mInDraw) {
+ if (verifyDrawable(drawable)) {
final Rect dirty = drawable.getDirtyBounds();
final int scrollX = mScrollX;
final int scrollY = mScrollY;
@@ -21715,6 +21707,13 @@
}
/**
+ * @hide
+ */
+ public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data) {
+ // Do nothing.
+ }
+
+ /**
* Interface definition for a callback to be invoked when a hardware key event is
* dispatched to this view. The callback will be invoked before the key event is
* given to the view. This is only useful for hardware keyboards; a software input
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3eb2e37..a14f0dc 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -79,6 +79,7 @@
import android.widget.Scroller;
import com.android.internal.R;
+import com.android.internal.os.IResultReceiver;
import com.android.internal.os.SomeArgs;
import com.android.internal.policy.PhoneFallbackEventHandler;
import com.android.internal.view.BaseSurfaceHolder;
@@ -3235,6 +3236,7 @@
private final static int MSG_WINDOW_MOVED = 23;
private final static int MSG_SYNTHESIZE_INPUT_EVENT = 24;
private final static int MSG_DISPATCH_WINDOW_SHOWN = 25;
+ private final static int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
final class ViewRootHandler extends Handler {
@Override
@@ -3511,7 +3513,11 @@
} break;
case MSG_DISPATCH_WINDOW_SHOWN: {
handleDispatchWindowShown();
- }
+ } break;
+ case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
+ IResultReceiver receiver = (IResultReceiver) msg.obj;
+ handleRequestKeyboardShortcuts(receiver);
+ } break;
}
}
}
@@ -5404,6 +5410,19 @@
mAttachInfo.mTreeObserver.dispatchOnWindowShown();
}
+ public void handleRequestKeyboardShortcuts(IResultReceiver receiver) {
+ Bundle data = new Bundle();
+ ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
+ if (mView != null) {
+ mView.requestKeyboardShortcuts(list);
+ }
+ data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
+ try {
+ receiver.send(0, data);
+ } catch (RemoteException e) {
+ }
+ }
+
public void getLastTouchPoint(Point outLocation) {
outLocation.x = (int) mLastTouchPoint.x;
outLocation.y = (int) mLastTouchPoint.y;
@@ -6333,6 +6352,10 @@
}
}
+ public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver) {
+ mHandler.obtainMessage(MSG_REQUEST_KEYBOARD_SHORTCUTS, receiver).sendToTarget();
+ }
+
/**
* Post a callback to send a
* {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
@@ -6906,6 +6929,14 @@
viewAncestor.dispatchWindowShown();
}
}
+
+ @Override
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
+ ViewRootImpl viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.dispatchRequestKeyboardShortcuts(receiver);
+ }
+ }
}
public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 0b06d15..d89369b 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -42,6 +42,8 @@
import android.transition.TransitionManager;
import android.view.accessibility.AccessibilityEvent;
+import java.util.List;
+
/**
* Abstract base class for a top-level window look and behavior policy. An
* instance of this class should be used as the top-level view added to the
@@ -556,6 +558,15 @@
* @param mode The mode that was just finished.
*/
public void onActionModeFinished(ActionMode mode);
+
+ /**
+ * Called when Keyboard Shortcuts are requested for the current window.
+ *
+ * @param data The data list to populate with shortcuts.
+ * @param menu The current menu, which may be null.
+ */
+ public void onProvideKeyboardShortcuts(
+ List<KeyboardShortcutGroup> data, @Nullable Menu menu);
}
/** @hide */
diff --git a/core/java/android/view/WindowCallbackWrapper.java b/core/java/android/view/WindowCallbackWrapper.java
index 8ce1f8c..bed74e9 100644
--- a/core/java/android/view/WindowCallbackWrapper.java
+++ b/core/java/android/view/WindowCallbackWrapper.java
@@ -19,6 +19,8 @@
import android.view.accessibility.AccessibilityEvent;
+import java.util.List;
+
/**
* A simple decorator stub for Window.Callback that passes through any calls
* to the wrapped instance as a base implementation. Call super.foo() to call into
@@ -150,5 +152,10 @@
public void onActionModeFinished(ActionMode mode) {
mWrapped.onActionModeFinished(mode);
}
+
+ @Override
+ public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
+ mWrapped.onProvideKeyboardShortcuts(data, menu);
+ }
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 251f4c8..772eeec 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -29,6 +29,8 @@
import android.text.TextUtils;
import android.util.Log;
+import java.util.List;
+
/**
* The interface that apps use to talk to the window manager.
@@ -118,6 +120,34 @@
*/
public void removeViewImmediate(View view);
+ /**
+ * Used to asynchronously request Keyboard Shortcuts from the focused window.
+ *
+ * @hide
+ */
+ public interface KeyboardShortcutsReceiver {
+ /**
+ * Callback used when the focused window keyboard shortcuts are ready to be displayed.
+ *
+ * @param result The keyboard shortcuts to be displayed.
+ */
+ void onKeyboardShortcutsReceived(List<KeyboardShortcutGroup> result);
+ }
+
+ /**
+ * @hide
+ */
+ public static final String PARCEL_KEY_SHORTCUTS_ARRAY = "shortcuts_array";
+
+ /**
+ * Request for keyboard shortcuts to be retrieved asynchronously.
+ *
+ * @param receiver The callback to be triggered when the result is ready.
+ *
+ * @hide
+ */
+ public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver);
+
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
/**
* X position for this window. With the default gravity it is ignored.
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 98e9f54c..6e11671 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -17,7 +17,15 @@
package android.view;
import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Bundle;
import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.R;
+
+import java.util.List;
/**
* Provides low-level communication with the system window manager for
@@ -117,6 +125,23 @@
}
@Override
+ public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver) {
+ IResultReceiver resultReceiver = new IResultReceiver.Stub() {
+ @Override
+ public void send(int resultCode, Bundle resultData) throws RemoteException {
+ List<KeyboardShortcutGroup> result =
+ resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY);
+ receiver.onKeyboardShortcutsReceived(result);
+ }
+ };
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .requestAppKeyboardShortcuts(resultReceiver);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
public Display getDefaultDisplay() {
return mDisplay;
}
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index b6570cc..9e79057 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -58,5 +58,5 @@
void temporaryEnableAccessibilityStateUntilKeyguardRemoved(in ComponentName service,
boolean touchExplorationEnabled);
- IBinder getWindowToken(int windowId);
+ IBinder getWindowToken(int windowId, int userId);
}
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index e0dbe2f..1536c29 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -850,7 +850,7 @@
normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
}
- final boolean expired = normalizedTime >= 1.0f;
+ final boolean expired = normalizedTime >= 1.0f || isCanceled();
mMore = !expired;
if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
@@ -875,7 +875,7 @@
}
if (expired) {
- if (mRepeatCount == mRepeated) {
+ if (mRepeatCount == mRepeated || isCanceled()) {
if (!mEnded) {
mEnded = true;
guard.close();
@@ -905,6 +905,10 @@
return mMore;
}
+ private boolean isCanceled() {
+ return mStartTime == Long.MIN_VALUE;
+ }
+
private void fireAnimationStart() {
if (mListener != null) {
if (mListenerHandler == null) mListener.onAnimationStart(this);
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index 48d1d2b..ac8d578 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -59,7 +59,6 @@
*/
public class ActionMenuPresenter extends BaseMenuPresenter
implements ActionProvider.SubUiVisibilityListener {
- private static final String TAG = "ActionMenuPresenter";
private static final int ITEM_ANIMATION_DURATION = 150;
private static final boolean ACTIONBAR_ANIMATIONS_ENABLED = false;
@@ -87,20 +86,16 @@
private OpenOverflowRunnable mPostedOpenRunnable;
private ActionMenuPopupCallback mPopupCallback;
- private final boolean mShowCascadingMenus;
-
final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
int mOpenSubMenuId;
// These collections are used to store pre- and post-layout information for menu items,
// which is used to determine appropriate animations to run for changed items.
- private SparseArray<MenuItemLayoutInfo> mPreLayoutItems =
- new SparseArray<MenuItemLayoutInfo>();
- private SparseArray<MenuItemLayoutInfo> mPostLayoutItems =
- new SparseArray<MenuItemLayoutInfo>();
+ private SparseArray<MenuItemLayoutInfo> mPreLayoutItems = new SparseArray<>();
+ private SparseArray<MenuItemLayoutInfo> mPostLayoutItems = new SparseArray<>();
// The list of currently running animations on menu items.
- private List<ItemAnimationInfo> mRunningItemAnimations = new ArrayList<ItemAnimationInfo>();
+ private List<ItemAnimationInfo> mRunningItemAnimations = new ArrayList<>();
private ViewTreeObserver.OnPreDrawListener mItemAnimationPreDrawListener =
new ViewTreeObserver.OnPreDrawListener() {
@Override
@@ -130,9 +125,6 @@
public ActionMenuPresenter(Context context) {
super(context, com.android.internal.R.layout.action_menu_layout,
com.android.internal.R.layout.action_menu_item_layout);
-
- mShowCascadingMenus = context.getResources().getBoolean(
- com.android.internal.R.bool.config_enableCascadingSubmenus);
}
@Override
@@ -845,8 +837,6 @@
}
private class OverflowMenuButton extends ImageButton implements ActionMenuView.ActionMenuChildView {
- private final float[] mTempPts = new float[2];
-
public OverflowMenuButton(Context context) {
super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle);
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index 2aaa356..cde7604 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -16,8 +16,11 @@
package android.widget;
+import android.annotation.AttrRes;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.StyleRes;
import android.annotation.Widget;
import android.content.Context;
@@ -37,9 +40,13 @@
import java.util.TimeZone;
/**
- * This class is a calendar widget for displaying and selecting dates. The range
- * of dates supported by this calendar is configurable. A user can select a date
- * by taping on it and can scroll and fling the calendar to a desired date.
+ * This class is a calendar widget for displaying and selecting dates. The
+ * range of dates supported by this calendar is configurable.
+ * <p>
+ * The exact appearance and interaction model of this widget may vary between
+ * OS versions and themes (e.g. Holo versus Material), but in general a user
+ * can select a date by tapping on it and can scroll or fling the calendar to a
+ * desired date.
*
* @attr ref android.R.styleable#CalendarView_showWeekNumber
* @attr ref android.R.styleable#CalendarView_firstDayOfWeek
@@ -77,22 +84,24 @@
* @param month The month that was set [0-11].
* @param dayOfMonth The day of the month that was set.
*/
- public void onSelectedDayChange(CalendarView view, int year, int month, int dayOfMonth);
+ void onSelectedDayChange(@NonNull CalendarView view, int year, int month, int dayOfMonth);
}
- public CalendarView(Context context) {
+ public CalendarView(@NonNull Context context) {
this(context, null);
}
- public CalendarView(Context context, AttributeSet attrs) {
+ public CalendarView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, R.attr.calendarViewStyle);
}
- public CalendarView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public CalendarView(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
- public CalendarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public CalendarView(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
final TypedArray a = context.obtainStyledAttributes(
@@ -322,7 +331,7 @@
*
* @attr ref android.R.styleable#CalendarView_weekDayTextAppearance
*/
- public void setWeekDayTextAppearance(int resourceId) {
+ public void setWeekDayTextAppearance(@StyleRes int resourceId) {
mDelegate.setWeekDayTextAppearance(resourceId);
}
@@ -333,7 +342,7 @@
*
* @attr ref android.R.styleable#CalendarView_weekDayTextAppearance
*/
- public int getWeekDayTextAppearance() {
+ public @StyleRes int getWeekDayTextAppearance() {
return mDelegate.getWeekDayTextAppearance();
}
@@ -344,7 +353,7 @@
*
* @attr ref android.R.styleable#CalendarView_dateTextAppearance
*/
- public void setDateTextAppearance(int resourceId) {
+ public void setDateTextAppearance(@StyleRes int resourceId) {
mDelegate.setDateTextAppearance(resourceId);
}
@@ -355,7 +364,7 @@
*
* @attr ref android.R.styleable#CalendarView_dateTextAppearance
*/
- public int getDateTextAppearance() {
+ public @StyleRes int getDateTextAppearance() {
return mDelegate.getDateTextAppearance();
}
@@ -552,36 +561,29 @@
int getShownWeekCount();
void setSelectedWeekBackgroundColor(@ColorInt int color);
- @ColorInt
- int getSelectedWeekBackgroundColor();
+ @ColorInt int getSelectedWeekBackgroundColor();
void setFocusedMonthDateColor(@ColorInt int color);
- @ColorInt
- int getFocusedMonthDateColor();
+ @ColorInt int getFocusedMonthDateColor();
void setUnfocusedMonthDateColor(@ColorInt int color);
- @ColorInt
- int getUnfocusedMonthDateColor();
+ @ColorInt int getUnfocusedMonthDateColor();
void setWeekNumberColor(@ColorInt int color);
- @ColorInt
- int getWeekNumberColor();
+ @ColorInt int getWeekNumberColor();
void setWeekSeparatorLineColor(@ColorInt int color);
- @ColorInt
- int getWeekSeparatorLineColor();
+ @ColorInt int getWeekSeparatorLineColor();
void setSelectedDateVerticalBar(@DrawableRes int resourceId);
void setSelectedDateVerticalBar(Drawable drawable);
Drawable getSelectedDateVerticalBar();
void setWeekDayTextAppearance(@StyleRes int resourceId);
- @StyleRes
- int getWeekDayTextAppearance();
+ @StyleRes int getWeekDayTextAppearance();
void setDateTextAppearance(@StyleRes int resourceId);
- @StyleRes
- int getDateTextAppearance();
+ @StyleRes int getDateTextAppearance();
void setMinDate(long minDate);
long getMinDate();
diff --git a/core/java/android/widget/ForwardingListener.java b/core/java/android/widget/ForwardingListener.java
index 7ddeff9..b383e1c 100644
--- a/core/java/android/widget/ForwardingListener.java
+++ b/core/java/android/widget/ForwardingListener.java
@@ -53,12 +53,6 @@
/** Whether this listener is currently forwarding touch events. */
private boolean mForwarding;
- /**
- * Whether forwarding was initiated by a long-press. If so, we won't
- * force the window to dismiss when the touch stream ends.
- */
- private boolean mWasLongPress;
-
/** The id of the first pointer down in the current event stream. */
private int mActivePointerId;
@@ -172,7 +166,6 @@
switch (actionMasked) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = srcEvent.getPointerId(0);
- mWasLongPress = false;
if (mDisallowIntercept == null) {
mDisallowIntercept = new DisallowIntercept();
@@ -243,7 +236,6 @@
e.recycle();
mForwarding = true;
- mWasLongPress = true;
}
/**
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index b95bc28..595adc2 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -16,18 +16,20 @@
package android.widget;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
+import com.android.internal.R;
+import com.android.internal.view.menu.ShowableListMenu;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
-import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.IntProperty;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
@@ -38,13 +40,7 @@
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.WindowManager;
-import android.view.animation.AccelerateDecelerateInterpolator;
-
-import com.android.internal.R;
-import com.android.internal.view.menu.ShowableListMenu;
-import com.android.internal.widget.AutoScrollHelper.AbsListViewAutoScroller;
-
-import java.util.Locale;
+import android.widget.AdapterView.OnItemSelectedListener;
/**
* A ListPopupWindow anchors itself to a host view and displays a
@@ -109,8 +105,6 @@
private boolean mModal;
- private int mLayoutDirection;
-
PopupWindow mPopup;
/**
@@ -174,7 +168,7 @@
*
* @param context Context used for contained views.
*/
- public ListPopupWindow(Context context) {
+ public ListPopupWindow(@NonNull Context context) {
this(context, null, com.android.internal.R.attr.listPopupWindowStyle, 0);
}
@@ -185,7 +179,7 @@
* @param context Context used for contained views.
* @param attrs Attributes from inflating parent views used to style the popup.
*/
- public ListPopupWindow(Context context, AttributeSet attrs) {
+ public ListPopupWindow(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.listPopupWindowStyle, 0);
}
@@ -197,7 +191,8 @@
* @param attrs Attributes from inflating parent views used to style the popup.
* @param defStyleAttr Default style attribute to use for popup content.
*/
- public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+ public ListPopupWindow(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
@@ -210,7 +205,8 @@
* @param defStyleAttr Style attribute to read for default styling of popup content.
* @param defStyleRes Style resource ID to use for default styling of popup content.
*/
- public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public ListPopupWindow(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
mContext = context;
mHandler = new Handler(context.getMainLooper());
@@ -227,9 +223,6 @@
mPopup = new PopupWindow(context, attrs, defStyleAttr, defStyleRes);
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
- // Set the default layout direction to match the default locale one
- final Locale locale = mContext.getResources().getConfiguration().locale;
- mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(locale);
}
/**
@@ -238,7 +231,7 @@
*
* @param adapter The adapter to use to create this window's content.
*/
- public void setAdapter(ListAdapter adapter) {
+ public void setAdapter(@Nullable ListAdapter adapter) {
if (mObserver == null) {
mObserver = new PopupDataSetObserver();
} else if (mAdapter != null) {
@@ -371,7 +364,7 @@
/**
* @return The background drawable for the popup window.
*/
- public Drawable getBackground() {
+ public @Nullable Drawable getBackground() {
return mPopup.getBackground();
}
@@ -380,7 +373,7 @@
*
* @param d A drawable to set as the background.
*/
- public void setBackgroundDrawable(Drawable d) {
+ public void setBackgroundDrawable(@Nullable Drawable d) {
mPopup.setBackgroundDrawable(d);
}
@@ -389,7 +382,7 @@
*
* @param animationStyle Animation style to use.
*/
- public void setAnimationStyle(int animationStyle) {
+ public void setAnimationStyle(@StyleRes int animationStyle) {
mPopup.setAnimationStyle(animationStyle);
}
@@ -399,7 +392,7 @@
*
* @return Animation style that will be used.
*/
- public int getAnimationStyle() {
+ public @StyleRes int getAnimationStyle() {
return mPopup.getAnimationStyle();
}
@@ -408,7 +401,7 @@
*
* @return The popup's anchor view
*/
- public View getAnchorView() {
+ public @Nullable View getAnchorView() {
return mDropDownAnchorView;
}
@@ -418,7 +411,7 @@
*
* @param anchor The view to use as an anchor.
*/
- public void setAnchorView(View anchor) {
+ public void setAnchorView(@Nullable View anchor) {
mDropDownAnchorView = anchor;
}
@@ -537,7 +530,7 @@
*
* @see ListView#setOnItemClickListener(android.widget.AdapterView.OnItemClickListener)
*/
- public void setOnItemClickListener(AdapterView.OnItemClickListener clickListener) {
+ public void setOnItemClickListener(@Nullable AdapterView.OnItemClickListener clickListener) {
mItemClickListener = clickListener;
}
@@ -546,9 +539,9 @@
*
* @param selectedListener Listener to register.
*
- * @see ListView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)
+ * @see ListView#setOnItemSelectedListener(OnItemSelectedListener)
*/
- public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener selectedListener) {
+ public void setOnItemSelectedListener(@Nullable OnItemSelectedListener selectedListener) {
mItemSelectedListener = selectedListener;
}
@@ -558,7 +551,7 @@
*
* @param prompt View to use as an informational prompt.
*/
- public void setPromptView(View prompt) {
+ public void setPromptView(@Nullable View prompt) {
boolean showing = isShowing();
if (showing) {
removePromptView();
@@ -686,7 +679,7 @@
*
* @param listener Listener that will be notified when the popup is dismissed.
*/
- public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
+ public void setOnDismissListener(@Nullable PopupWindow.OnDismissListener listener) {
mPopup.setOnDismissListener(listener);
}
@@ -795,7 +788,7 @@
/**
* @return The currently selected item or null if the popup is not showing.
*/
- public Object getSelectedItem() {
+ public @Nullable Object getSelectedItem() {
if (!isShowing()) {
return null;
}
@@ -834,7 +827,7 @@
*
* @see ListView#getSelectedView()
*/
- public View getSelectedView() {
+ public @Nullable View getSelectedView() {
if (!isShowing()) {
return null;
}
@@ -846,11 +839,11 @@
* Only valid when {@link #isShowing()} == {@code true}.
*/
@Override
- public ListView getListView() {
+ public @Nullable ListView getListView() {
return mDropDownList;
}
- DropDownListView createDropDownListView(Context context, boolean hijackFocus) {
+ @NonNull DropDownListView createDropDownListView(Context context, boolean hijackFocus) {
return new DropDownListView(context, hijackFocus);
}
@@ -874,7 +867,7 @@
*
* @see #setModal(boolean)
*/
- public boolean onKeyDown(int keyCode, KeyEvent event) {
+ public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
// when the drop down is shown, we drive it directly
if (isShowing()) {
// the key events are forwarded to the list in the drop down view
@@ -969,7 +962,7 @@
*
* @see #setModal(boolean)
*/
- public boolean onKeyUp(int keyCode, KeyEvent event) {
+ public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
if (isShowing() && mDropDownList.getSelectedItemPosition() >= 0) {
boolean consumed = mDropDownList.onKeyUp(keyCode, event);
if (consumed && KeyEvent.isConfirmKey(keyCode)) {
@@ -993,7 +986,7 @@
*
* @see #setModal(boolean)
*/
- public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+ public boolean onKeyPreIme(int keyCode, @NonNull KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && isShowing()) {
// special case for the back key, we do not even try to send it
// to the drop down list but instead, consume it immediately
@@ -1159,7 +1152,6 @@
mPopup.setContentView(dropDownView);
} else {
- dropDownView = (ViewGroup) mPopup.getContentView();
final View view = mPromptView;
if (view != null) {
LinearLayout.LayoutParams hintParams =
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 8e711b0..06daf61 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -1946,6 +1946,9 @@
public void setMenuCallbacks(MenuPresenter.Callback pcb, MenuBuilder.Callback mcb) {
mActionMenuPresenterCallback = pcb;
mMenuBuilderCallback = mcb;
+ if (mMenuView != null) {
+ mMenuView.setMenuCallbacks(pcb, mcb);
+ }
}
/**
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index cea9867..7ae0efb 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -17,6 +17,7 @@
package com.android.internal.policy;
import com.android.internal.R;
+import com.android.internal.policy.PhoneWindow.PanelFeatureState;
import com.android.internal.policy.PhoneWindow.PhoneWindowMenuCallback;
import com.android.internal.view.FloatingActionMode;
import com.android.internal.view.RootViewSurfaceTaker;
@@ -28,6 +29,8 @@
import com.android.internal.widget.DecorCaptionView;
import com.android.internal.widget.FloatingToolbar;
+import java.util.List;
+
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.app.ActivityManager;
@@ -48,6 +51,7 @@
import android.view.Gravity;
import android.view.InputQueue;
import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -85,6 +89,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
/** @hide */
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
@@ -1956,6 +1961,21 @@
res.getConfiguration().screenWidthDp, res.getDisplayMetrics());
}
+ /**
+ * @hide
+ */
+ @Override
+ public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> list) {
+ final PanelFeatureState st = mWindow.getPanelState(FEATURE_OPTIONS_PANEL, false);
+ if (!mWindow.isDestroyed() && st != null && mWindow.getCallback() != null) {
+ try {
+ mWindow.getCallback().onProvideKeyboardShortcuts(list, st.menu);
+ } catch (AbstractMethodError e) {
+ // We run into this if the app is using supportlib.
+ }
+ }
+ }
+
private static class ColorViewState {
View view = null;
int targetVisibility = View.INVISIBLE;
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index e79f1b8..fdf5f84 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -62,6 +62,7 @@
private final SnapTarget mDismissStartTarget;
private final SnapTarget mDismissEndTarget;
+ private final SnapTarget mMiddleTarget;
public DividerSnapAlgorithm(Resources res, float minFlingVelocityPxPerSecond,
int displayWidth, int displayHeight, int dividerSize, boolean isHorizontalDivision,
@@ -80,6 +81,7 @@
mLastSplitTarget = mTargets.get(mTargets.size() - 2);
mDismissStartTarget = mTargets.get(0);
mDismissEndTarget = mTargets.get(mTargets.size() - 1);
+ mMiddleTarget = mTargets.get(mTargets.size() / 2);
}
public SnapTarget calculateSnapTarget(int position, float velocity) {
@@ -215,6 +217,10 @@
SnapTarget.FLAG_NONE));
}
+ public SnapTarget getMiddleTarget() {
+ return mMiddleTarget;
+ }
+
/**
* Represents a snap target for the divider.
*/
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index b692a18..5127408 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -218,6 +218,33 @@
}
/**
+ * Ensures that the argument long value is within the inclusive range.
+ *
+ * @param value a long value
+ * @param lower the lower endpoint of the inclusive range
+ * @param upper the upper endpoint of the inclusive range
+ * @param valueName the name of the argument to use if the check fails
+ *
+ * @return the validated long value
+ *
+ * @throws IllegalArgumentException if {@code value} was not within the range
+ */
+ public static long checkArgumentInRange(long value, long lower, long upper,
+ String valueName) {
+ if (value < lower) {
+ throw new IllegalArgumentException(
+ String.format(
+ "%s is out of range of [%d, %d] (too low)", valueName, lower, upper));
+ } else if (value > upper) {
+ throw new IllegalArgumentException(
+ String.format(
+ "%s is out of range of [%d, %d] (too high)", valueName, lower, upper));
+ }
+
+ return value;
+ }
+
+ /**
* Ensures that the array is not {@code null}, and none of its elements are {@code null}.
*
* @param value an array of boxed objects
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 8699843..aa4b564c 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -25,6 +25,8 @@
import android.view.IWindow;
import android.view.IWindowSession;
+import com.android.internal.os.IResultReceiver;
+
public class BaseIWindow extends IWindow.Stub {
private IWindowSession mSession;
public int mSeq;
@@ -103,4 +105,8 @@
@Override
public void dispatchWindowShown() {
}
+
+ @Override
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
+ }
}
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index c2adc42..a67e43a 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.internal.view.menu;
import android.content.Context;
@@ -7,7 +23,6 @@
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnKeyListener;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
@@ -30,7 +45,7 @@
MenuPresenter, OnKeyListener {
private final Context mContext;
- private final LayoutInflater mInflater;
+
private final MenuBuilder mMenu;
private final MenuAdapter mAdapter;
private final boolean mOverflowOnly;
@@ -79,8 +94,6 @@
private Callback mPresenterCallback;
private ViewTreeObserver mTreeObserver;
- private ViewGroup mMeasureParent;
-
/** Whether the popup has been dismissed. Once dismissed, it cannot be opened again. */
private boolean mWasDismissed;
@@ -99,10 +112,10 @@
public StandardMenuPopup(Context context, MenuBuilder menu, View anchorView, int popupStyleAttr,
int popupStyleRes, boolean overflowOnly) {
mContext = Preconditions.checkNotNull(context);
- mInflater = LayoutInflater.from(context);
mMenu = menu;
mOverflowOnly = overflowOnly;
- mAdapter = new MenuAdapter(menu, mInflater, mOverflowOnly);
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ mAdapter = new MenuAdapter(menu, inflater, mOverflowOnly);
mPopupStyleAttr = popupStyleAttr;
mPopupStyleRes = popupStyleRes;
@@ -155,8 +168,7 @@
mPopup.setDropDownGravity(mDropDownGravity);
if (!mHasContentWidth) {
- mContentWidth = measureIndividualMenuWidth(
- mAdapter, mMeasureParent, mContext, mPopupMaxWidth);
+ mContentWidth = measureIndividualMenuWidth(mAdapter, null, mContext, mPopupMaxWidth);
mHasContentWidth = true;
}
@@ -177,7 +189,9 @@
false);
TextView titleView = (TextView) titleItemView.findViewById(
com.android.internal.R.id.title);
- titleView.setText(mMenu.getHeaderTitle());
+ if (titleView != null) {
+ titleView.setText(mMenu.getHeaderTitle());
+ }
titleItemView.setEnabled(false);
listView.addHeaderView(titleItemView, null, false);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 75077df..b02de0eb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -385,6 +385,7 @@
<protected-broadcast android:name="com.android.server.device_idle.STEP_LIGHT_IDLE_STATE" />
<protected-broadcast android:name="com.android.server.Wifi.action.TOGGLE_PNO" />
<protected-broadcast android:name="intent.action.ACTION_RF_BAND_INFO" />
+ <protected-broadcast android:name="android.intent.action.MEDIA_RESOURCE_GRANTED" />
<protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED" />
<protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL" />
@@ -2828,6 +2829,12 @@
<permission android:name="android.permission.ACCESS_EPHEMERAL_APPS"
android:protectionLevel="signature" />
+ <!-- Allows receiving the usage of media resource e.g. video/audio codec and
+ graphic memory.
+ @hide -->
+ <permission android:name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"
+ android:protectionLevel="signature|privileged" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/core/res/res/drawable/ic_notification_alert.xml b/core/res/res/drawable/ic_notification_alert.xml
new file mode 100644
index 0000000..d17dfc1
--- /dev/null
+++ b/core/res/res/drawable/ic_notification_alert.xml
@@ -0,0 +1,33 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M18.4,2.2L17.0,3.6c2.0,1.4 3.3,3.7 3.5,6.4l2.0,0.0C22.3,6.8 20.8,4.0 18.4,2.2z"
+ android:fillColor="#231F20"/>
+ <path
+ android:pathData="M7.1,3.6L5.7,2.2C3.3,4.0 1.7,6.8 1.5,10.0l2.0,0.0C3.7,7.3 5.0,5.0 7.1,3.6z"
+ android:fillColor="#231F20"/>
+ <path
+ android:pathData="M18.5,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.5,3.5C13.5,2.7 12.8,2.0 12.0,2.0s-1.5,0.7 -1.5,1.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.5,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0l-2.0,-2.0L18.5,10.5zM13.0,16.5l-2.0,0.0l0.0,-2.0l2.0,0.0L13.0,16.5zM13.0,12.5l-2.0,0.0l0.0,-6.0l2.0,0.0L13.0,12.5z"
+ android:fillColor="#231F20"/>
+ <path
+ android:pathData="M12.0,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0L10.0,20.0C10.0,21.1 10.9,22.0 12.0,22.0z"
+ android:fillColor="#231F20"/>
+</vector>
diff --git a/core/res/res/drawable/ic_notification_block.xml b/core/res/res/drawable/ic_notification_block.xml
new file mode 100644
index 0000000..27690740
--- /dev/null
+++ b/core/res/res/drawable/ic_notification_block.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.0,2.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zM4.0,12.0c0.0,-4.42 3.58,-8.0 8.0,-8.0 1.85,0.0 3.5,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4.0,13.85 4.0,12.0zm8.0,8.0c-1.85,0.0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20.0,10.15 20.0,12.0c0.0,4.42 -3.58,8.0 -8.0,8.0z"/>
+</vector>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 36c167e..c945459 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Sluit persoonlike data soos kredietkaartnommers en wagwoorde in."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Beheer vertoonskermvergroting"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Beheer die vertoonskerm se zoemvlak en posisionering."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Voer gebare uit"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan tik, swiep, knyp en ander gebare uitvoer."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"deaktiveer of verander statusbalk"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Laat die program toe om die statusbalk te deaktiveer en stelselikone by te voeg of te verwyder."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"wees die statusbalk"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index ec16add..17b5a29 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"እንደ የክሬዲት ካርድ ቁጥሮች እና የይለፍ ቃላት ያሉ የግል ውሂብ ያካትታል።"</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"የመቆጣጠሪያ ማሳያ እንዲጎላ አደራረግ"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"የማሳያውን የማጉያ ደረጃ እና አቀማመጥ ይቆጣጠሩ።"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"የጣት ምልክቶችን ያከናውኑ"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"መታ ማድረግ፣ ማንሸራተት፣ መቆንጠጥ እና ሌሎች የጣት ምልክቶችን ማከናወን ይችላል።"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"የሁኔቴ አሞሌ አቦዝን ወይም ቀይር"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"የስርዓት አዶዎችን ወደ ሁኔታ አሞሌ ላለማስቻል ወይም ለማከል እና ለማስወገድ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"የሁኔታ አሞሌ መሆን"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 12ef759..efde61f 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -260,6 +260,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"يتضمن بيانات شخصية مثل أرقام بطاقات الائتمان وكلمات المرور."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"التحكم في تكبير الشاشة"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"يمكنك التحكم في مستوى التكبير/التصغير للشاشة وتحديد الموضع."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"تنفيذ إيماءات"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"يمكن النقر والتمرير بسرعة والتصغير وتنفيذ إيماءات أخرى."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"تعطيل شريط الحالة أو تعديله"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"للسماح للتطبيق بتعطيل شريط الحالة أو إضافة رموز نظام وإزالتها."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"العمل كشريط للحالة"</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 7f0e6d7..0e4771e 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Kredit kartı nömrələri və parollar kimi şəxsi məlumatlar daxildir."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ekran böyütməsinə nəzarət edin"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ekran yaxınlaşdırma səviyyəsi və yerləşdirməsinə nəzarət edin."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Jestlər ilə əməliyyat aparın"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Digər jestlərə tıklaya, sürüşdürə və əməliyyat apara bilərsiniz."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"status panelini deaktivləşdir və ya dəyişdir"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Tətbiqə status panelini deaktiv etməyə və ya sistem ikonalarını əlavə etmək və ya silmək imkanı verir."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"status paneli edin"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index ac5ce66..fd9ddec 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -257,6 +257,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Obuhvata lične podatke kao što su brojevi kreditnih kartica i lozinke."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Upravljaj uvećanjem prikaza"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Upravlja nivoom zumiranja prikaza i određivanjem položaja."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Obavljanje pokreta"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Može da dodiruje, lista, skuplja prikaz i obavlja druge pokrete."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"onemogućavanje ili izmena statusne trake"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Dozvoljava aplikaciji da onemogući statusnu traku ili da dodaje i uklanja sistemske ikone."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"funkcionisanje kao statusna traka"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 301e1e3..955727b 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Включва лични данни, като например номера на кредитни карти и пароли."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Управление на увеличението на дисплея"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Управление на нивото на мащаба и позиционирането на дисплея."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Извършване на жестове"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Можете да докосвате, да прекарвате пръст, да събирате пръсти и да извършвате други жестове."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"деактивиране или промяна на лентата на състоянието"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Разрешава на приложението да деактивира лентата на състоянието или да добавя и премахва системни икони."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"изпълняване на ролята на лента на състоянието"</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 9c88d44..6e7a77f 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"ক্রেডিট কার্ডের নম্বর ও পাসওয়ার্ডগুলির মতো ব্যক্তিগত তথ্য অন্তর্ভুক্ত করে৷"</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"প্রদর্শনের বৃহত্তরীকরণ ব্যবস্থা নিয়ন্ত্রণ করুন"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"প্রদর্শনের জুমের স্তর এবং অবস্থান নির্ধারন নিয়ন্ত্রণ করুন৷"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"অঙ্গভঙ্গির কাজগুলি সম্পাদন করুন"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"আলতো চাপ দেওয়া, সোয়াইপ, পিঞ্চ করা এবং অন্যান্য অঙ্গভঙ্গির কাজগুলি সম্পাদন করতে পারবেন৷"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"স্থিতি দন্ড নিষ্ক্রিয় অথবা সংশোধন করে"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"অ্যাপ্লিকেশানকে স্থিতি দন্ড অক্ষম করতে এবং সিস্টেম আইকনগুলি সরাতে দেয়৷"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"স্থিতি দন্ডে থাকুন"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 8554b843..bbe9887 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclou dades personals com ara números de targetes de crèdit i contrasenyes."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controla l\'ampliació de la pantalla"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controla el nivell i el posicionament del zoom de la pantalla."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Utilitza gestos"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Pot tocar, lliscar, pessigar i utilitzar altres gestos."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"desactivar o modificar la barra d\'estat"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permet que l\'aplicació desactivi la barra d\'estat o afegeixi i elimini icones del sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"aparèixer a la barra d\'estat"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 2eca49a..f5763f91 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -258,6 +258,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Sledování zahrnuje osobní údaje, jako jsou například čísla kreditních karet a hesla."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Nastavení zvětšení obsahu obrazovky"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Určuje umístění a úroveň přiblížení displeje."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Provádění gest"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Může provádět gesta klepnutí, přejetí, stažení prstů a další."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"zakázání či změny stavového řádku"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Umožňuje aplikaci zakázat stavový řádek nebo přidat či odebrat systémové ikony."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"vydávání se za stavový řádek"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 2a719b0..3e8a86d 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Dette omfatter personlige data såsom kreditkortnumre og adgangskoder."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrollér skærmforstørrelsen"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrollér skærmens zoomniveau og position."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Udfør bevægelser"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan trykke, stryge, knibe sammen og udføre andre bevægelser."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"deaktiver eller rediger statuslinje"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Tillader, at appen kan deaktivere statusbjælken eller tilføje og fjerne systemikoner."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"vær statusbjælken"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index d116a24..e2fb6ff 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -56,10 +56,10 @@
<string name="badPin" msgid="9015277645546710014">"Die von Ihnen eingegebene alte PIN ist nicht korrekt."</string>
<string name="badPuk" msgid="5487257647081132201">"Der von Ihnen eingegebene PUK ist nicht korrekt."</string>
<string name="mismatchPin" msgid="609379054496863419">"Die von Ihnen eingegebenen PIN-Nummern stimmen nicht überein."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Geben Sie eine PIN ein, die 4 bis 8 Zahlen enthält."</string>
- <string name="invalidPuk" msgid="8761456210898036513">"Geben Sie eine mindestens achtstellige PUK ein."</string>
- <string name="needPuk" msgid="919668385956251611">"Ihre SIM-Karte ist mit einem PUK gesperrt. Geben Sie zum Entsperren den PUK-Code ein."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Geben Sie zum Entsperren der SIM-Karte den PUK2 ein."</string>
+ <string name="invalidPin" msgid="3850018445187475377">"Gib eine PIN ein, die 4 bis 8 Zahlen enthält."</string>
+ <string name="invalidPuk" msgid="8761456210898036513">"Gib eine mindestens achtstellige PUK ein."</string>
+ <string name="needPuk" msgid="919668385956251611">"Deine SIM-Karte ist mit einem PUK gesperrt. Gib zum Entsperren den PUK-Code ein."</string>
+ <string name="needPuk2" msgid="4526033371987193070">"Gib zum Entsperren der SIM-Karte den PUK2 ein."</string>
<string name="enablePin" msgid="209412020907207950">"Fehler. SIM-/RUIM-Sperre aktivieren."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
<item quantity="other">Sie haben noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche, bevor Ihre SIM-Karte gesperrt wird.</item>
@@ -87,7 +87,7 @@
<string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Beschränkt"</string>
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Nicht beschränkt"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Dienst nicht eingerichtet."</string>
- <string name="CLIRPermanent" msgid="3377371145926835671">"Sie können die Einstellung für die Anrufer-ID nicht ändern."</string>
+ <string name="CLIRPermanent" msgid="3377371145926835671">"Du kannst die Einstellung für die Anrufer-ID nicht ändern."</string>
<string name="RestrictedChangedTitle" msgid="5592189398956187498">"Eingeschränkter Zugriff geändert"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Daten-Dienst ist gesperrt."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Notruf ist gesperrt."</string>
@@ -156,7 +156,7 @@
<string name="httpErrorBadUrl" msgid="3636929722728881972">"Die Seite kann nicht geöffnet werden, weil die URL ungültig ist."</string>
<string name="httpErrorFile" msgid="2170788515052558676">"Auf die Datei konnte nicht zugegriffen werden."</string>
<string name="httpErrorFileNotFound" msgid="6203856612042655084">"Die angeforderte Datei wurde nicht gefunden."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Es werden zurzeit zu viele Anfragen verarbeitet. Versuchen Sie es später erneut."</string>
+ <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Es werden zurzeit zu viele Anfragen verarbeitet. Versuche es später erneut."</string>
<string name="notification_title" msgid="8967710025036163822">"Fehler bei Anmeldung für <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
<string name="contentServiceSync" msgid="8353523060269335667">"Synchronisierung"</string>
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisierung"</string>
@@ -198,7 +198,7 @@
<string name="shutdown_confirm" product="tv" msgid="476672373995075359">"Ihr Fernseher wird ausgeschaltet."</string>
<string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ihre Uhr wird heruntergefahren."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon wird heruntergefahren."</string>
- <string name="shutdown_confirm_question" msgid="2906544768881136183">"Möchten Sie das Gerät herunterfahren?"</string>
+ <string name="shutdown_confirm_question" msgid="2906544768881136183">"Möchtest du das Gerät herunterfahren?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Im abgesicherten Modus starten"</string>
<string name="reboot_safemode_confirm" msgid="55293944502784668">"Möchten Sie im abgesicherten Modus neu starten? Dadurch werden alle Apps von Drittanbietern deaktiviert, die Sie installiert haben. Sie werden jedoch nach einem weiteren Neustart wiederhergestellt."</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"Kürzlich geöffnet"</string>
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Einschließlich personenbezogener Daten wie Kreditkartennummern und Passwörter."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Displayvergrößerung festlegen"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Legt die Zoom-Stufe des Displays und die Zoom-Position auf dem Display fest."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Bewegungen möglich"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Tippen, Wischen, Zusammenziehen und andere Bewegungen möglich."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"Statusleiste deaktivieren oder ändern"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Ermöglicht der App, die Statusleiste zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"Statusleiste darstellen"</string>
@@ -650,11 +652,11 @@
<string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Passwort zum Entsperren eingeben"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"PIN zum Entsperren eingeben"</string>
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Falscher PIN-Code"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Drücken Sie zum Entsperren die Menütaste und dann auf \"0\"."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Drücke zum Entsperren die Menütaste und dann auf \"0\"."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Notrufnummer"</string>
<string name="lockscreen_carrier_default" msgid="6169005837238288522">"Kein Dienst"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Display gesperrt"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Drücken Sie die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Drücke die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Zum Entsperren die Menütaste drücken"</string>
<string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Muster zum Entsperren zeichnen"</string>
<string name="lockscreen_emergency_call" msgid="5298642613417801888">"Notfall"</string>
@@ -667,10 +669,10 @@
<string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Keine SIM-Karte im Tablet"</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"Keine SIM-Karte im Fernseher"</string>
<string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Keine SIM-Karte im Telefon"</string>
- <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Legen Sie eine SIM-Karte ein."</string>
- <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-Karte fehlt oder ist nicht lesbar. Bitte legen Sie eine SIM-Karte ein."</string>
+ <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Lege eine SIM-Karte ein."</string>
+ <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-Karte fehlt oder ist nicht lesbar. Bitte lege eine SIM-Karte ein."</string>
<string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM-Karte unbrauchbar"</string>
- <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Ihre SIM-Karte wurde dauerhaft deaktiviert.\n Wenden Sie sich an Ihren Mobilfunkanbieter, um eine andere SIM-Karte zu erhalten."</string>
+ <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Deine SIM-Karte wurde dauerhaft deaktiviert.\n Wende dich an deinen Mobilfunkanbieter, um eine andere SIM-Karte zu erhalten."</string>
<string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Vorheriger Titel"</string>
<string name="lockscreen_transport_next_description" msgid="573285210424377338">"Nächster Titel"</string>
<string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"Pausieren"</string>
@@ -681,22 +683,22 @@
<string name="emergency_calls_only" msgid="6733978304386365407">"Nur Notrufe"</string>
<string name="lockscreen_network_locked_message" msgid="143389224986028501">"Netzwerk gesperrt"</string>
<string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"PUK-Sperre auf SIM"</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Weitere Informationen erhalten Sie im Nutzerhandbuch oder beim Kundendienst."</string>
+ <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Weitere Informationen erhältst du im Nutzerhandbuch oder beim Kundendienst."</string>
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"PIN eingeben"</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-Karte wird entsperrt..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. \n\nBitte versuchen Sie es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
- <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nBitte versuchen Sie es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
- <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nBitte versuchen Sie es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe Ihrer Google-Anmeldeinformationen zu entsperren.\n\n Bitte versuchen Sie es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. \n\nBitte versuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
+ <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Du hast dein Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nBitte versuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
+ <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Du hast dein Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nBitte versuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Tablet mithilfe deiner Google-Anmeldeinformationen zu entsperren.\n\n Bitte versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Wenn Sie es noch <xliff:g id="NUMBER_1">%2$d</xliff:g>-mal falsch eingeben, werden Sie aufgefordert, Ihren Fernseher mithilfe Ihrer Google-Anmeldeinformationen zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe Ihrer Google-Anmeldeinformationen zu entsperren.\n\nBitte versuchen Sie es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Sie haben <xliff:g id="NUMBER_0">%1$d</xliff:g> Mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Tablet auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Telefon mithilfe deiner Google-Anmeldeinformationen zu entsperren.\n\nBitte versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g> Mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Tablet auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Sie haben <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, den Fernseher zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird der Fernseher auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Sie haben <xliff:g id="NUMBER_0">%1$d</xliff:g> Mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Telefon auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
- <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Tablet wird nun auf die Werkseinstellungen zurückgesetzt."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g> Mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Telefon auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Tablet wird nun auf die Werkseinstellungen zurückgesetzt."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, den Fernseher zu entsperren. Der Fernseher wird nun auf die Werkseinstellungen zurückgesetzt."</string>
- <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Telefon wird nun auf die Werkseinstellungen zurückgesetzt."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Versuchen Sie es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Telefon wird nun auf die Werkseinstellungen zurückgesetzt."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Versuche es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Muster vergessen?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Kontoentsperrung"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Zu viele Schemaversuche"</string>
@@ -786,11 +788,11 @@
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"Ermöglicht der App, Nachrichten zu Ihrem Mailbox-Posteingang hinzuzufügen"</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Geolokalisierungsberechtigungen des Browsers ändern"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Ermöglicht der App, die Geolokalisierungsberechtigungen des Browsers zu ändern. Schädliche Apps können so Standortinformationen an beliebige Websites senden."</string>
- <string name="save_password_message" msgid="767344687139195790">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
+ <string name="save_password_message" msgid="767344687139195790">"Möchtest du, dass der Browser dieses Passwort speichert?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nicht jetzt"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Speichern"</string>
<string name="save_password_never" msgid="8274330296785855105">"Nie"</string>
- <string name="open_permission_deny" msgid="7374036708316629800">"Sie sind nicht zum Öffnen dieser Seite berechtigt."</string>
+ <string name="open_permission_deny" msgid="7374036708316629800">"Du bist nicht zum Öffnen dieser Seite berechtigt."</string>
<string name="text_copied" msgid="4985729524670131385">"Text in Zwischenablage kopiert."</string>
<string name="more_item_label" msgid="4650918923083320495">"Mehr"</string>
<string name="prepend_shortcut_label" msgid="2572214461676015642">"Menü+"</string>
@@ -903,10 +905,10 @@
<string name="aerr_process" msgid="4507058997035697579">"Der Prozess \"<xliff:g id="PROCESS">%1$s</xliff:g>\" wurde beendet."</string>
<string name="aerr_process_silence" msgid="4226685530196000222">"Silence stürzt bei <xliff:g id="PROCESS">%1$s</xliff:g> bis zum Neustart ab."</string>
<string name="anr_title" msgid="4351948481459135709"></string>
- <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> reagiert nicht.\n\nMöchten Sie die App schließen?"</string>
- <string name="anr_activity_process" msgid="5776209883299089767">"Aktivität \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\" reagiert nicht.\n\nMöchten Sie sie beenden?"</string>
- <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> reagiert nicht. Möchten Sie die App schließen?"</string>
- <string name="anr_process" msgid="6513209874880517125">"Prozess \"<xliff:g id="PROCESS">%1$s</xliff:g>\" reagiert nicht.\n\nMöchten Sie ihn beenden?"</string>
+ <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> reagiert nicht.\n\nMöchtest du die App schließen?"</string>
+ <string name="anr_activity_process" msgid="5776209883299089767">"Aktivität \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\" reagiert nicht.\n\nMöchtest du sie beenden?"</string>
+ <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> reagiert nicht. Möchtest du die App schließen?"</string>
+ <string name="anr_process" msgid="6513209874880517125">"Prozess \"<xliff:g id="PROCESS">%1$s</xliff:g>\" reagiert nicht.\n\nMöchtest du ihn beenden?"</string>
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Bericht"</string>
<string name="wait" msgid="7147118217226317732">"Warten"</string>
@@ -1094,7 +1096,7 @@
<string name="dial_number_using" msgid="5789176425167573586">"Nummer\nmit <xliff:g id="NUMBER">%s</xliff:g> wählen"</string>
<string name="create_contact_using" msgid="4947405226788104538">"Neuer Kontakt\nmit <xliff:g id="NUMBER">%s</xliff:g> erstellen"</string>
<string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Die folgenden Apps benötigen die Berechtigung zum aktuellen und zukünftigen Zugriff auf Ihr Konto."</string>
- <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Möchten Sie diese Anfrage zulassen?"</string>
+ <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Möchtest du diese Anfrage zulassen?"</string>
<string name="grant_permissions_header_text" msgid="6874497408201826708">"Zugriffsanforderung"</string>
<string name="allow" msgid="7225948811296386551">"Zulassen"</string>
<string name="deny" msgid="2081879885755434506">"Ablehnen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 8116b16..3e277c3 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Περιλαμβάνει προσωπικά δεδομένα, όπως είναι οι αριθμοί πιστωτικών καρτών και οι κωδικοί πρόσβασης."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ελέγξτε τη μεγέθυνση της οθόνης"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ελέγξτε το επίπεδο ζουμ και τη θέση της οθόνης."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Εκτέλεση κινήσεων"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Επιτρέπει το πάτημα, την ολίσθηση, το πλησίασμα και άλλες κινήσεις."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"απενεργοποίηση ή τροποποίηση γραμμής κατάστασης"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Επιτρέπει στην εφαρμογή να απενεργοποιεί τη γραμμή κατάστασης ή να προσθέτει και να αφαιρεί εικονίδια συστήματος."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ορισμός ως γραμμής κατάστασης"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 930c310..0edc438 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Includes personal data such as credit card numbers and passwords."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Control display magnification"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Control the display\'s zoom level and positioning."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 930c310..0edc438 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Includes personal data such as credit card numbers and passwords."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Control display magnification"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Control the display\'s zoom level and positioning."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 930c310..0edc438 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Includes personal data such as credit card numbers and passwords."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Control display magnification"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Control the display\'s zoom level and positioning."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 258ef33..bd2f91b 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Incluye datos personales, como números de tarjeta de crédito y contraseñas."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlar la ampliación de pantalla"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controla el posicionamiento y el nivel de zoom de la pantalla."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Usar gestos"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Permite presionar, deslizar, pellizcar y usar otros gestos."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"desactivar o modificar la barra de estado"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que la aplicación inhabilite la barra de estado o que agregue y elimine íconos del sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"aparecer en la barra de estado"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 9848bb6..e73b425 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Incluye datos personales como números de tarjetas de crédito y contraseñas."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controla la ampliación de la pantalla"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controla el posicionamiento y el nivel de zoom de la pantalla."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Realizar gestos"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Puedes tocar y pellizcar la pantalla, deslizar el dedo y hacer otros gestos."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"inhabilitar o modificar la barra de estado"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que la aplicación inhabilite la barra de estado o añada y elimine iconos del sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"aparecer en la barra de estado"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 466bd5d..e6a122c 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Sisaldab isiklikke andmeid, nt krediitkaardi numbreid ja paroole."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ekraani suurenduse juhtimine"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Saate juhtida ekraani suumitaset ja asendit."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Liigutuste tegemine"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Saate puudutada, pühkida, sõrmi kokku-lahku liigutada ja teisi liigutusi teha."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"keela või muuda olekuriba"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Võimaldab rakendusel keelata olekuriba või lisada ja eemaldada süsteemiikoone."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"olekuribana kuvamine"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index cdb8622..31a073b 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Ez da salbuespenik egiten datu pertsonalekin, hala nola, kreditu-txartelen zenbakiekin eta pasahitzekin."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrolatu pantailaren zoom-maila"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolatu pantailaren zoom-maila eta kokapena."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Keinuak egin"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Sakatu, lerratu, atximurkatu eta beste hainbat keinu egin ditzake."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"Desgaitu edo aldatu egoera-barra"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Egoera-barra desgaitzea edo sistema-ikonoak gehitzea edo kentzea baimentzen die aplikazioei."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"Bihurtu egoera-barra"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index b0da5fe..f0271d6 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"اطلاعات شخصی مانند شماره کارت اعتباری و گذرواژهها را لحاظ میکند."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"کنترل درشتنمایی نمایشگر"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"سطح و موقعیت بزرگنمایی نمایشگر را کنترل کنید."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"اجرای اشارهها"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"میتوانید ضربه بزنید، انگشتتان را تند بکشید، انگشتانتان را به هم نزدیک یا از هم دور کنید و اشارههای دیگری اجرا کنید."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"غیرفعال کردن یا تغییر نوار وضعیت"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"به برنامه اجازه میدهد تا نوار وضعیت را غیرفعال کند یا نمادهای سیستم را اضافه یا حذف کند."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"نوار وضعیت باشد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index f7db678..3e0c172 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Sisältää henkilökohtaisia tietoja, kuten luottokortin numeroita ja salasanoja."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Näytön suurentamisen hallinnointi"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Hallinnoi näytön zoomaustasoa ja asettelua."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Eleiden käyttäminen"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Lupa napauttaa, pyyhkäistä, nipistää ja käyttää muita eleitä."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"poista tilapalkki käytöstä tai muokkaa tilapalkkia"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Antaa sovelluksen poistaa tilapalkin käytöstä ja lisätä tai poistaa järjestelmäkuvakkeita."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"sijaita tilapalkissa"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 50aed95..8450e5c 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclut des données personnelles telles que les numéros de cartes de paiement et les mots de passe."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Contrôler l\'agrandissement de l\'écran"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Contrôler le niveau de zoom et le positionnement de l\'écran."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Effectuer des gestes"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Peut toucher, balayer, pincer et effectuer d\'autres gestes."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"désactiver ou modifier la barre d\'état"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permet à l\'application de désactiver la barre d\'état, ou d\'ajouter et de supprimer des icônes système."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"servir de barre d\'état"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 33d2016..84c43fac 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclut des données personnelles telles que les numéros de cartes de paiement et les mots de passe."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Contrôler l\'agrandissement de l\'écran"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Contrôler le niveau de zoom et le positionnement de l\'écran"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Effectuer des gestes"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Permet d\'appuyer sur l\'écran, de le balayer, de le pincer et d\'effectuer d\'autres gestes."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"Désactivation ou modification de la barre d\'état"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permet à l\'application de désactiver la barre d\'état, ou d\'ajouter et de supprimer des icônes système."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"remplacer la barre d\'état"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 7947825..36594e0 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclúe datos persoais como números e contrasinais de tarxetas de crédito."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlar ampliación da pantalla"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o nivel do zoom e o posicionamento da pantalla"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Realizar xestos"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Podes tocar, pasar o dedo, beliscar e realizar outros xestos."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"desactivar ou modificar a barra de estado"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite á aplicación desactivar a barra de estado ou engadir e eliminar as iconas do sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"actuar como a barra de estado"</string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index aa9478b..9d098fc 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"ક્રેડિટ કાર્ડ નંબર્સ અને પાસવર્ડ્સ જેવો વ્યક્તિગત ડેટા શામેલ છે."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"પ્રદર્શન વિસ્તૃતિકરણ નિયંત્રિત કરો"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"પ્રદર્શનનું ઝૂમ સ્તર અને સ્થિતિનિર્ધારણ નિયંત્રિત કરો."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"હાવભાવ કરો"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ટૅપ, સ્વાઇપ, પિંચ કરી અને અન્ય હાવભાવ કરી શકે છે."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"સ્થિતિ બાર અક્ષમ કરો અથવા સંશોધિત કરો"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"એપ્લિકેશનને સ્થિતિ બાર અક્ષમ કરવાની અથવા સિસ્ટમ આયકન્સ ઉમેરવા અને દૂર કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"સ્થિતિ બાર થાઓ"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index d3d1e2c..5741d5c 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"क्रेडिट कार्ड नंबर और पासवर्ड जैसा व्यक्तिगत डेटा शामिल होता है."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"प्रदर्शन आवर्धन नियंत्रित करें"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"प्रदर्शन का ज़ूम स्तर और स्थिति निर्धारण नियंत्रित करें."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"हावभाव निष्पादित करें"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"इस सेवा के द्वारा टैप किया जा सकता है, स्वाइप किया जा सकता है, पिंच किया जा सकता है और अन्य हावभाव निष्पादित किए जा सकते हैं."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"स्थिति बार अक्षम या बदलें"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ऐप्स को स्थिति बार अक्षम करने या सिस्टम आइकन को जोड़ने या निकालने देता है."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"स्थिति बार होने दें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index dc55c57..f635b15 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -257,6 +257,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Uključuje osobne podatke kao što su brojevi kreditnih kartica i zaporke."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrola uvećanja zaslona"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolira razinu zumiranja i položaj zaslona."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Izvođenje pokreta"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Može dodirnuti, prijeći prstom, spojiti prste i izvoditi druge pokrete."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"onemogućavanje ili izmjena trake statusa"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Aplikaciji omogućuje onemogućavanje trake statusa ili dodavanje i uklanjanje sistemskih ikona."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"biti traka statusa"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 3176c65..64a674c 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Beleértve a személyes adatokat, például a hitelkártyaszámokat és jelszavakat."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"A kijelző nagyításának vezérlése"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"A kijelző nagyítási/kicsinyítési szintjének és pozíciójának vezérlése"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Kézmozdulatok végrehajtása"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Koppintás, ujjak gyors csúsztatása és összehúzása, illetve egyéb kézmozdulatok végrehajtása."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"állapotsor kikapcsolása vagy módosítása"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Lehetővé teszi az alkalmazás számára az állapotsor kikapcsolását, illetve rendszerikonok hozzáadását és eltávolítását."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"az állapotsor szerepének átvétele"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index d72ee8d..8d6272a 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Ներառում է անձնական տվյալներ, ինչպիսիք են վարկային քարտերի համարները և գաղտնաբառերը:"</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ցուցասարքի խոշորացման կառավարում"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ցուցասարքի մասշտաբավորման և դիրքավորման կառավարում:"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Կատարել ժեստեր"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Կարող է հպել, թերթել, պտղունցել և կատարել այլ ժեստեր:"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"անջատել կամ փոփոխել կարգավիճակի գոտին"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Թույլ է տալիս հավելվածին անջատել կարգավիճակի գոտին կամ ավելացնել ու հեռացնել համակարգի պատկերակները:"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"լինել կարգավիճակի գոտի"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 024eea4..898f6d1 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Meliputi data pribadi seperti nomor kartu kredit dan sandi."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Mengontrol perbesaran layar"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Mengontrol tingkat zoom dan pemosisian layar."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Melakukan isyarat"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Dapat mengetuk, menggesek, mencubit, dan melakukan isyarat lainnya."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"nonaktifkan atau ubah bilah status"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Mengizinkan apl menonaktifkan bilah status atau menambah dan menghapus ikon sistem."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"jadikan bilah status"</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 240c715..ebcde5d 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Felur í sér persónuleg gögn á borð við kreditkortanúmer og aðgangsorð."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Stilla skjástærð"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Stjórnaðu aðdrætti og afstöðu skjásins."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Nota bendingar"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Getur ýtt, strokið, fært fingur saman og gert ýmsar aðrar bendingar."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"slökkva á eða breyta stöðustiku"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Leyfir forriti að slökkva á stöðustikunni eða bæta við og fjarlægja kerfistákn."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"vera stöðustikan"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index ece503d..d064684 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Sono inclusi dati personali come numeri di carte di credito e password."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlla l\'ingrandimento del display"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlla il livello di zoom e la posizione del display."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Esegui gesti"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Consente di toccare, far scorrere, pizzicare ed eseguire altri gesti."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"disattivare o modificare la barra di stato"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Consente all\'applicazione di disattivare la barra di stato o di aggiungere e rimuovere icone di sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ruolo di barra di stato"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 144afc0..375bdf0 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -258,6 +258,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"כולל נתונים אישיים כמו מספרי כרטיס אשראי וסיסמאות."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"שליטה בהגדלת התצוגה"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"קבע את המרחק מהתצוגה ואת מיקום התצוגה."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ביצוע תנועות"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"יכול להקיש, להחליק, לעשות תנועת צביטה ולבצע תנועות אחרות."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"השבת או שנה את שורת המצב"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"מאפשר לאפליקציה להשבית את שורת המצב או להוסיף ולהסיר סמלי מערכת."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"להיות שורת הסטטוס"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index edfab22..a32a8ed 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"クレジットカードの番号やパスワードなどの個人データが含まれます。"</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"画面の拡大の制御"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"画面のズームレベルと位置を制御します。"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"操作の実行"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"タップ、スワイプ、ピンチ、その他の操作を行えます。"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"ステータスバーの無効化や変更"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ステータスバーの無効化、システムアイコンの追加や削除をアプリに許可します。"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ステータスバーへの表示"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index ffdd31c..f2fc953 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"შეიცავს ისეთ პირად მონაცემებს, როგორიცაა საკრედიტო ბარათის ნომრები და პაროლები."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"ერანის გადიდების მართვა"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ეკრანის მასშტაბირების დონისა და პოზიციის მართვა."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ჟესტების შესრულება"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"შეუძლია შეხება, გადაფურცვლა, მასშტაბირება და სხვა ჟესტების შესრულება."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"სტატუსის ზოლის გათიშვა ან ცვლილება"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"აპს შეეძლება სტატუსების ზოლის გათიშვა და სისტემის ხატულების დამატება/წაშლა."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"სტატუსის ზოლის ჩანაცვლება"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index ff58eaa..ab82fd4 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Кредит карта нөмірі және кілтсөздер сияқты жеке деректерді қоса."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Дисплей ұлғайтуды басқару"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Дисплейдің масштабтау деңгейін және орналастыруды басқару."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Қимылдарды орындау"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Түртуге, жанауға, қысуға және басқа қимылдарды орындауға болады."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"күйін көрсету тақтасын өшіру немесе өзгерту"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Қолданбаға күй жолағын өшіруге немесе жүйелік белгішелерді қосуға және жоюға рұқсат береді."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"күй жолағы болу"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 261212f..ffb3599 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"រួមបញ្ចូលទិន្នន័យផ្ទាល់ខ្លួន ដូចជាលេខកាតឥណទាន និងពាក្យសម្ងាត់។"</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"គ្រប់គ្រងការពង្រីកអេក្រង់"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"គ្រប់គ្រងការកំណត់ទីតាំង និងកម្រិតពង្រីករបស់អេក្រង់"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ធ្វើកាយវិការ"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"អាចប៉ះ អូស ច្បិច និងធ្វើកាយវិការផ្សេងទៀត"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"បិទ ឬកែរបារស្ថានភាព"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ឲ្យកម្មវិធីបិទរបារស្ថានភាព ឬបន្ថែម និងលុបរូបតំណាងប្រព័ន្ធ។"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ធ្វើជារបារស្ថានភាព"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index f083702..ab7ad82 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"ಕ್ರೆಡಿಟ್ ಕಾರ್ಡ್ ಸಂಖ್ಯೆಗಳು ಮತ್ತು ಪಾಸ್ವರ್ಡ್ಗಳಂತಹ ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"ಪ್ರದರ್ಶನದ ವರ್ಧಕವನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ಪ್ರದರ್ಶನದ ಝೂಮ್ ಮಟ್ಟ ಮತ್ತು ಸ್ಥಾನ ನಿರ್ಧಾರವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ಗೆಸ್ಚರ್ಗಳನ್ನು ಮಾಡಿ"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ಟ್ಯಾಪ್ ಮಾಡಬಹುದು, ಸ್ವೈಪ್ ಮಾಡಬಹುದು, ಪಿಂಚ್ ಮಾಡಬಹುದು ಮತ್ತು ಇತರ ಗೆಸ್ಚರ್ಗಳನ್ನು ಮಾಡಬಹುದು."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ ಇಲ್ಲವೇ ಮಾರ್ಪಡಿಸಿ"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಅಥವಾ ಸೇರಿಸಲು ಮತ್ತು ಸಿಸ್ಟಂ ಐಕಾನ್ಗಳನ್ನು ತೆಗೆದುಹಾಕಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಾಗಿರಲು"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index c8f08c7..4c478aa 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"신용카드 번호와 비밀번호 등의 개인 데이터를 포함합니다."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"디스플레이 배율 제어"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"디스플레이의 확대/축소 수준 및 위치를 제어합니다."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"동작 실행"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"탭, 스와이프, 확대/축소 및 기타 동작을 실행할 수 있습니다."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"상태 표시줄 사용 중지 또는 수정"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"앱이 상태 표시줄을 사용중지하거나 시스템 아이콘을 추가 및 제거할 수 있도록 허용합니다."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"상태 표시줄에 위치"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 4d84933..e9b01d1 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Кредиттик карта номурлары жана сырсөздөр сыяктуу өздүк берилиштерди камтыйт."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Дисплейди чоңойтууну башкаруу"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Экрандагы сүрөттүн өлчөмүн өзгөртүү жана жайгаштыруу."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Жаңсоолорду аткаруу"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Таптап, серпип, чымчып жана башка жаңсоолорду аткара алат."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"абал тилкесин өчүрүү же өзгөртүү"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Колдонмого абал тилкесин өчүрүү же тутум сүрөтчөлөрүн кошуу же алып салуу мүмкүнчүлүгүн берет."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"абал тилкесинин милдетин аткаруу"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 12d67bb..cf21944 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"ຮວມທັງຂໍ້ມູນສ່ວນໂຕເຊັ່ນ: ເລກບັດເຄຣດິດ ແລະລະຫັດຜ່ານ."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"ຄວບຄຸມການຂະຫຍາຍຈໍສະແດງຜົນ"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ຄວບຄຸມລະດັບການຊູມ ແລະການວາງຕຳແໜ່ງຂອງຈໍສະແດງຜົນ."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ດຳເນີນທ່າທາງຕ່າງໆ"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ສາມາດແຕະ, ປັດນີ້ວມື, ຢິບນິ້ວມື ແລະ ດຳເນີນທ່າທາງອື່ນ."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"ປິດການນນຳໃຊ້ ຫຼື ແກ້ໄຂແຖບສະຖານະ"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ອະນຸຍາດໃຫ້ແອັບຯປິດການເຮັດວຽກຂອງແຖບສະຖານະ ຫຼືເພີ່ມ ແລະລຶບໄອຄອນລະບົບອອກໄດ້."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ເປັນແຖບສະຖານະ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index e35edd6..f1143fe 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -258,6 +258,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Įtraukiami asmeniniai duomenys, pavyzdžiui, kredito kortelių numeriai ir slaptažodžiai."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ekrano didinimo valdymas"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Valdykite ekrano mastelio keitimo lygį ir pozicijos nustatymą."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Veiksmai gestais"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Galima paliesti, perbraukti, suimti ir atlikti kitus veiksmus gestais."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"išjungti ar keisti būsenos juostą"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Leidžiama programai neleisti būsenos juostos arba pridėti ir pašalinti sistemos piktogramas."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"būti būsenos juosta"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index de02a4f..f8644004 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -257,6 +257,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Ietver personas datus, piemēram, kredītkartes numurus un paroles."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Displeja palielinājuma kontrole"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolējiet displeja tālummaiņas līmeni un pozicionēšanu."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Žestu izpilde"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Atbalsta pieskaršanos, vilkšanu, savilkšanu un citus žestus."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"atspējot vai pārveidot statusa joslu"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Ļauj lietotnei atspējot statusa joslu vai pievienot un noņemt sistēmas ikonas."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"Būt par statusa joslu"</string>
diff --git a/core/res/res/values-mcc310-mnc160/strings.xml b/core/res/res/values-mcc310-mnc160/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- WFC Operator Error Codes -->
+ <string-array name="wfcOperatorErrorCodes" translatable="false">
+ <item>REG09</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as alerts -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as notifications -->
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item>Register with your carrier</item>
+ </string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc200/strings.xml b/core/res/res/values-mcc310-mnc200/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc200/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- WFC Operator Error Codes -->
+ <string-array name="wfcOperatorErrorCodes" translatable="false">
+ <item>REG09</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as alerts -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as notifications -->
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item>Register with your carrier</item>
+ </string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc210/strings.xml b/core/res/res/values-mcc310-mnc210/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc210/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- WFC Operator Error Codes -->
+ <string-array name="wfcOperatorErrorCodes" translatable="false">
+ <item>REG09</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as alerts -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as notifications -->
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item>Register with your carrier</item>
+ </string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc220/strings.xml b/core/res/res/values-mcc310-mnc220/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc220/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- WFC Operator Error Codes -->
+ <string-array name="wfcOperatorErrorCodes" translatable="false">
+ <item>REG09</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as alerts -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as notifications -->
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item>Register with your carrier</item>
+ </string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc230/strings.xml b/core/res/res/values-mcc310-mnc230/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc230/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- WFC Operator Error Codes -->
+ <string-array name="wfcOperatorErrorCodes" translatable="false">
+ <item>REG09</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as alerts -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as notifications -->
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item>Register with your carrier</item>
+ </string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc240/strings.xml b/core/res/res/values-mcc310-mnc240/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc240/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- WFC Operator Error Codes -->
+ <string-array name="wfcOperatorErrorCodes" translatable="false">
+ <item>REG09</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as alerts -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as notifications -->
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item>Register with your carrier</item>
+ </string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc250/strings.xml b/core/res/res/values-mcc310-mnc250/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc250/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- WFC Operator Error Codes -->
+ <string-array name="wfcOperatorErrorCodes" translatable="false">
+ <item>REG09</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as alerts -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as notifications -->
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item>Register with your carrier</item>
+ </string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc270/strings.xml b/core/res/res/values-mcc310-mnc270/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc270/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- WFC Operator Error Codes -->
+ <string-array name="wfcOperatorErrorCodes" translatable="false">
+ <item>REG09</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as alerts -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as notifications -->
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item>Register with your carrier</item>
+ </string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc310/strings.xml b/core/res/res/values-mcc310-mnc310/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc310/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- WFC Operator Error Codes -->
+ <string-array name="wfcOperatorErrorCodes" translatable="false">
+ <item>REG09</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as alerts -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as notifications -->
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item>Register with your carrier</item>
+ </string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc490/strings.xml b/core/res/res/values-mcc310-mnc490/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc490/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- WFC Operator Error Codes -->
+ <string-array name="wfcOperatorErrorCodes" translatable="false">
+ <item>REG09</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as alerts -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as notifications -->
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item>Register with your carrier</item>
+ </string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc660/strings.xml b/core/res/res/values-mcc310-mnc660/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc660/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- WFC Operator Error Codes -->
+ <string-array name="wfcOperatorErrorCodes" translatable="false">
+ <item>REG09</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as alerts -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as notifications -->
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item>Register with your carrier</item>
+ </string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc800/strings.xml b/core/res/res/values-mcc310-mnc800/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc800/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- WFC Operator Error Codes -->
+ <string-array name="wfcOperatorErrorCodes" translatable="false">
+ <item>REG09</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as alerts -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+ </string-array>
+ <!-- WFC Operator Error Messages showed as notifications -->
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item>Register with your carrier</item>
+ </string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 96a29a5..484e5a6 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Опфаќа лични податоци како што се броеви на кредитни картички и лозинки."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Контролирајте го зголемувањето на екранот"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Контролирајте го нивото на зумирање и позиционирање на екранот."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Користете движења"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Може да допрете, повлечете, штипнете и да користите други движења."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"оневозможи или измени статусна лента"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Дозволува апликацијата да ја оневозможи статусната лента или да додава или отстранува системски икони."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"да стане статусна лента"</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index f6869e3..42a9a82 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"ക്രെഡിറ്റ് കാർഡ് നമ്പറുകളും പാസ്വേഡുകളും പോലുള്ള വ്യക്തിഗത ഡാറ്റ ഉൾപ്പെടുന്നു."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"ഡിസ്പ്ലേ മാഗ്നിഫിക്കേഷൻ നിയന്ത്രിക്കുക"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ഡിസ്പ്ലേയുടെ സൂം നിലയും പൊസിഷനിംഗും നിയന്ത്രിക്കുക."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ജെസ്റ്ററുകൾ നിർവഹിക്കുക"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ടാപ്പുചെയ്യാനോ സ്വൈപ്പുചെയ്യാനോ പിഞ്ചുചെയ്യാനോ മറ്റ് ജെസ്റ്ററുകൾ നിർവഹിക്കാനോ കഴിയും."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"സ്റ്റാറ്റസ് ബാർ പ്രവർത്തനരഹിതമാക്കുക അല്ലെങ്കിൽ പരിഷ്ക്കരിക്കുക"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"നില ബാർ പ്രവർത്തരഹിതമാക്കുന്നതിന് അല്ലെങ്കിൽ സിസ്റ്റം ഐക്കണുകൾ ചേർക്കുന്നതിനും നീക്കംചെയ്യുന്നതിനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"സ്റ്റാറ്റസ് ബാർ ആയിരിക്കുക"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index d982ece..91b9ea7 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Кредит картын дугаар болон нууц үг зэрэг хувийн датаг агуулж байна."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Дэлгэцийн өсгөлтийг хянах"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Дэлгэцийн томруулах түвшин болон байршлыг хянах."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Зангах"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Товших, шудрах, жижигрүүлэх болон бусад зангааг хийх боломжтой."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"статус самбарыг идэвхгүй болгох болон өөрчлөх"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Апп нь статус самбарыг идэвхгүй болгох эсвэл систем дүрсийг нэмэх, хасах боломжтой."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"статусын хэсэг болох"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 4087199..0cb37da 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"क्रेडिट कार्ड नंबर आणि संकेतशब्द यासारखा वैयक्तिक डेटा समाविष्ट करते."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"प्रदर्शन विस्तृतीकरण नियंत्रित करा"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"प्रदर्शनाचा झूम स्तर आणि स्थिती निर्धारण नियंत्रित करा."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"जेश्चर करा"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"टॅप, स्वाइप, पिंच आणि इतर जेश्चर करू शकते."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"स्टेटस बार अक्षम करा किंवा सुधारित करा"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"स्टेटस बार अक्षम करण्यासाठी किंवा सिस्टीम चिन्हे जोडण्यासाठी आणि काढण्यासाठी अॅप ला अनुमती देते."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"स्टेटस बार होऊ द्या"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 0923e91..d40c7d1 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Termasuk data peribadi seperti nombor kad kredit dan kata laluan."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kawal pembesaran paparan"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kawal tahap zum dan kedudukan paparan."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Lakukan gerak isyarat"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Boleh ketik, leret, cubit dan laksanakan gerak isyarat lain."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"lumpuhkan atau ubah suai bar status"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Membenarkan apl melumpuhkan bar status atau menambah dan mengalih keluar ikon sistem."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"jadi bar status"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 3ef7e6c..28a4d0f 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"အရေးကြီးသော ကိုယ်ရေးအချက်အလက်များဖြစ်တဲ့ ခရက်ဒစ်ကဒ်နံပါတ်များနှင့် စကားဝှက်များ ပါဝင်ပါတယ်."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"မျက်နှာပြင် ချဲ့ခြင်းကို ထိန်းချုပ်ပါ"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"မျက်နှာပြင် ချဲ့ခြင်းနှင့် နေရာချထားခြင်းကို ထိန်းချုပ်ပါ"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"လက်ဟန်များ အသုံးပြုပါ"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"တို့ခြင်း၊ ပွတ်ဆွဲခြင်း၊ နှင့် အခြား လက်ဟန်များကို အသုံးပြုနိုင်ပါသည်။"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"အခြေအနေပြဘားအား အလုပ်မလုပ်ခိုင်းရန်သို့မဟုတ် မွမ်းမံရန်"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"appအား အခြေအနေပြ ဘားကို ပိတ်ခွင့် သို့မဟတ် စနစ် အိုင်ကွန်များကို ထည့်ခြင်း ဖယ်ရှားခြင်း ပြုလုပ်ခွင့် ပြုသည်။"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"အခြေအနေပြ ဘားဖြစ်ပါစေ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index cd65d85..7e909e4 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Dette omfatter personlige data, som kredittkortnumre og passord."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrollér forstørrelse for skjermen"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrollér zoomenivået og plasseringen for skjermen."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gjøre bevegelser"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan trykke, sveipe, klype og gjøre andre bevegelser."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"deaktivere eller endre statusfeltet"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Lar appen deaktivere statusfeltet eller legge til og fjerne systemikoner."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"vise appen i statusfeltet"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 301094b..15277a2 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"व्यक्तिगत डेटा जस्तै क्रेडिट कार्ड नम्बरहरू र पासवर्डहरू समावेश गर्दछ।"</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"प्रदर्शन आवर्धन नियन्त्रण गर्नुहोस्"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"प्रदर्शनको जुम स्तर र स्थिति नियन्त्रण गर्नुहोस्।"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"इसाराहरू सम्बन्धी कार्य गर्नुहोस्"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ट्याप, स्वाइप गर्न, थिच्न र अन्य इसाराहरू सम्बन्धी कार्य गर्न सकिन्छ"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"स्थिति पट्टिलाई अक्षम वा संशोधित गर्नुहोस्"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"स्थिति पट्टि असक्षम पार्न वा प्रणाली आइकनहरू थप्न र हटाउन अनुप्रयोगलाई अनुमति दिन्छ।"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"वस्तुस्थिति पट्टी हुन दिनुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 1407991..b81b46e 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Omvat persoonlijke gegevens zoals creditcardnummers en wachtwoorden."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Schermvergroting bedienen"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Bedien het zoomniveau en de positionering van het scherm."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gebaren uitvoeren"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan tikken, vegen, samenknijpen en andere gebaren uitvoeren."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"statusbalk uitschakelen of wijzigen"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Hiermee kan de app de statusbalk uitschakelen of systeempictogrammen toevoegen en verwijderen."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"de statusbalk zijn"</string>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 39f20f5..192c181 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"ਇਸ ਵਿੱਚ ਨਿੱਜੀ ਡਾਟਾ ਸ਼ਾਮਲ ਹੈ ਜਿਵੇਂ ਕ੍ਰੈਡਿਟ ਕਾਰਡ ਨੰਬਰ ਅਤੇ ਪਾਸਵਰਡ।"</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"ਡਿਸਪਲੇ ਵੱਡਦਰਸ਼ੀ ਨੂੰ ਨਿਯੰਤ੍ਰਿਤ ਕਰੋ"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ਡਿਸਪਲੇ ਦੇ ਜ਼ੂਮ ਪੱਧਰ ਅਤੇ ਸਥਿਤੀ ਨੂੰ ਨਿਯੰਤ੍ਰਿਤ ਕਰੋ।"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ਸੰਕੇਤ ਕਰਦੀ ਹੈ"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ਟੈਪ ਕਰ ਸਕਦੀ ਹੈ, ਸਵਾਈਪ ਕਰ ਸਕਦੀ ਹੈ, ਪਿੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਅਤੇ ਹੋਰ ਸੰਕੇਤ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"ਸਥਿਤੀ ਬਾਰ ਅਸਮਰੱਥ ਬਣਾਓ ਜਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰੋ"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ਐਪ ਨੂੰ ਸਥਿਤੀ ਬਾਰ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਉਣ ਜਾਂ ਸਿਸਟਮ ਆਈਕਨਾਂ ਨੂੰ ਜੋੜਨ ਅਤੇ ਹਟਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ਸਥਿਤੀ ਪੱਟੀ ਬਣਨ ਦਿਓ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index f3e50b5..38437fa 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -258,6 +258,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Obejmuje informacje osobiste, takie jak numery kart kredytowych i hasła."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Regulowanie powiększenia ekranu"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Regulowanie poziomu i obszaru powiększenia ekranu."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Obsługa gestów"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Obsługuje kliknięcia, przesunięcia, ściągnięcia palców i inne gesty."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"wyłączanie lub zmienianie paska stanu"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Pozwala aplikacji na wyłączanie paska stanu oraz dodawanie i usuwanie ikon systemowych."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"działanie jako pasek stanu"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 89bbbe8..91821a4 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclui dados pessoais, como números de cartão de crédito e senhas."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlar ampliação da tela"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o posicionamento e nível de zoom da tela."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Fazer gestos"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Toque, deslize, faça gestos de pinça e faça outros gestos."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar a barra de status"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que o app desative a barra de status ou adicione e remova ícones do sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ser a barra de status"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index f559dbb..f37d3a6 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclui dados pessoais, como números de cartões de crédito e palavras-passe."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlar a ampliação do ecrã"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o nível de zoom e o posicionamento do ecrã."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Realizar gestos"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"É possível tocar, deslizar rapidamente, juntar os dedos e realizar outros gestos"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar barra de estado"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite à aplicação desativar a barra de estado ou adicionar e remover ícones do sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ser apresentada na barra de estado"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 89bbbe8..91821a4 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclui dados pessoais, como números de cartão de crédito e senhas."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlar ampliação da tela"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o posicionamento e nível de zoom da tela."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Fazer gestos"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Toque, deslize, faça gestos de pinça e faça outros gestos."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar a barra de status"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que o app desative a barra de status ou adicione e remova ícones do sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ser a barra de status"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 4086e69..b235b7a 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -257,6 +257,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Include date personale, cum ar fi numere ale cardurilor de credit sau parole."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlați mărirea pe afișaj"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlați nivelul de zoom și poziționarea afișajului."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Folosiți gesturi"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Se poate atinge, glisa, ciupi și se pot folosi alte gesturi."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"dezactivare sau modificare bare de stare"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite aplicației să dezactiveze bara de stare sau să adauge și să elimine pictograme de sistem."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"să fie bara de stare"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index ee39b83..0c5fb09b 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -258,6 +258,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"В том числе личные данные, например номера кредитных карт и пароли."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Управлять масштабом изображения"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Управлять позиционированием и размером изображения на экране."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Жесты"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Может выполнять жесты нажатия, пролистывания, масштабирования и т. д."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"Отключение/изменение строки состояния"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Приложение сможет отключать строку состояния, а также добавлять и удалять системные значки."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"Замена строки состояния"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 5364c98..17f0f97 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"ණයවරපත් අංක සහ මුරපද වැනි පුද්ගලික දත්ත ඇතුළත් වේ."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"සංදර්ශන විශාලන මට්ටම පාලනය කිරීම"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"සංදර්ශනයේ විශාලන මට්ටම සහ පිහිටීම පාලනය කිරීම."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"අභින සිදු කරන්න"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"තට්ටු කිරීමට, ස්වයිප් කිරීමට, පින්ච් කිරීමට, සහ වෙනත් අභින සිදු කිරීමට හැකිය."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"තත්ව තීරුව අබල කරන්න හෝ වෙනස් කරන්න"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"තත්ව තීරුව අක්රිය කිරීමට හෝ පද්ධති නිරූපක එකතු හෝ ඉවත් කිරීමට යෙදුමට අවසර දේ."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"තත්ත්ව තීරුව බවට පත්වීම"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 90ccd54..d9c79f2 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -258,6 +258,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Sledovanie zahŕňa osobné údaje ako sú čísla kreditných kariet a heslá."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ovládanie priblíženia obrazovky"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ovládajte úroveň priblíženia/oddialenia obrazovky a umiestnenie"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gestá"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Je možné použiť klepnutie, prejdenie, stiahnutie prstami a ďalšie gestá."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"zakázanie alebo zmeny stavového riadka"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Umožňuje aplikácii vypnúť stavový riadok alebo pridať a odstrániť systémové ikony."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"vydávanie sa za stavový riadok"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 4e9b1c5..8e293e1 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -258,6 +258,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Vključuje osebne podatke, kot so številke kreditnih kartic in gesla."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Nadziranje povečave prikaza"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Nadziranje stopnje povečave in položaja prikaza."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Izvajanje potez"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Mogoče je izvajanje dotikov, vlečenja, vlečenja prstov skupaj in drugih potez."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"onemogočanje ali spreminjanje vrstice stanja"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Aplikacijam omogoča onemogočenje vrstice stanja ali dodajanje in odstranjevanje ikon sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"postane vrstica stanja"</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index be9c709..a24e82f 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Përfshi të dhënat personale si numrat e kartave të kreditit si dhe fjalëkalimet."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrollo zmadhimin e ekranit"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrollo nivelin dhe pozicionimin e zmadhimit të ekranit."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Kryen gjeste"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Mund të trokasë, rrëshqasë, bashkojë gishtat dhe kryejë gjeste të tjera."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"çaktivizo ose modifiko shiritin e statusit"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Lejon aplikacionin të çaktivizojë shiritin e statusit dhe të heqë ikonat e sistemit."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"të bëhet shiriti i statusit"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index a3618ab..c706264f 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -257,6 +257,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Обухвата личне податке као што су бројеви кредитних картица и лозинке."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Управљај увећањем приказа"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Управља нивоом зумирања приказа и одређивањем положаја."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Обављање покрета"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Може да додирује, листа, скупља приказ и обавља друге покрете."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"онемогућавање или измена статусне траке"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Дозвољава апликацији да онемогући статусну траку или да додаје и уклања системске иконе."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"функционисање као статусна трака"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index b07dc28..ecc6d4e 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Omfattar personuppgifter som kreditkortsnummer och lösenord."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Styr skärmförstoringen"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Styr skärmens zoomnivå och positionering."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Göra rörelser"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan trycka, svepa, nypa och göra andra rörelser."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"inaktivera eller ändra statusfält"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Tillåter att appen inaktiverar statusfältet eller lägger till och tar bort systemikoner."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"visas i statusfältet"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index cf0063c..d1e6d97 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -258,6 +258,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inajumuisha data binafsi kama vile nambari za kadi ya mkopo na manenosiri."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Dhibiti ukuzaji wa onyesho"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Dhibiti kiwango cha kukuza na nafasi cha onyesho."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Tekeleza ishara"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Unaweza kugonga, kutelezesha kidole, kubana na kutekeleza ishara zingine."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"zima au rekebisha mwambaa hali"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Inaruhusu programu kulemaza upau wa hali au kuongeza na kutoa ikoni za mfumo."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"kuwa sehemu ya arifa"</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index ecefb77..eacc9a9 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"கிரெடிட் கார்டு எண்கள் மற்றும் கடவுச்சொற்கள் போன்ற தனிப்பட்ட தகவலும் உள்ளடங்கும்."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"திரையின் உருப்பெருக்கத்தைக் கட்டுப்படுத்துதல்"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"திரையின் ஜூம் அளவையும் நிலையையும் கட்டுப்படுத்தலாம்."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"சைகைகளைச் செயல்படுத்துதல்"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"தட்டலாம், ஸ்வைப் செய்யலாம், பின்ச் செய்யலாம் மற்றும் பிற சைகைகளைச் செயல்படுத்தலாம்."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"நிலைப் பட்டியை முடக்குதல் அல்லது மாற்றுதல்"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"நிலைப் பட்டியை முடக்க அல்லது முறைமையில் ஐகான்களைச் சேர்க்க மற்றும் அகற்ற பயன்பாட்டை அனுமதிக்கிறது."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"நிலைப் பட்டியில் இருக்கும்"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index b1bccd2..0440134 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"క్రెడిట్ కార్డు నంబర్లు మరియు పాస్వర్డ్ల వంటి వ్యక్తిగత డేటాను కలిగి ఉంటుంది."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"డిస్ప్లే మాగ్నిఫికేషన్ను నియంత్రించండి"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"డిస్ప్లే జూమ్ స్థాయి మరియు స్థానాన్ని నియంత్రిస్తుంది."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"సంజ్ఞలను చేయడం"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"నొక్కగలరు, స్వైప్ చేయగలరు, స్క్రీన్పై రెండు వేళ్లను ఉంచి ఆ వేళ్లను దగ్గరకు లేదా దూరానికి లాగగలరు మరియు ఇతర సంజ్ఞలను చేయగలరు."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"స్థితి బార్ను నిలిపివేయడం లేదా సవరించడం"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"స్థితి బార్ను నిలిపివేయడానికి లేదా సిస్టమ్ చిహ్నాలను జోడించడానికి మరియు తీసివేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"స్థితి పట్టీగా ఉండటం"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 0b8e60d..5d27943 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"รวมถึงข้อมูลส่วนบุคคล เช่น หมายเลขบัตรเครดิตและรหัสผ่าน"</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"ควบคุมการขยายการแสดงผล"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ควบคุมระดับการซูมและการวางตำแหน่งของการแสดงผล"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ทำท่าทางสัมผัส"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"สามารถแตะ เลื่อน บีบ และทำท่าทางสัมผัสอื่นๆ"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"ปิดการใช้งานหรือแก้ไขแถบสถานะ"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"อนุญาตให้แอปพลิเคชันปิดใช้งานแถบสถานะหรือเพิ่มและนำไอคอนระบบออก"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"เป็นแถบสถานะ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 02a3587..479efdf 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"May kasamang personal na data tulad ng mga numero ng credit card at password."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrolin ang pag-magnify ng display"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolin ang antas ng pag-zoom at pagpoposisyon ng display."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Magsagawa ng mga galaw"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"May kakayahang mag-tap, mag-swipe, mag-pinch at magsagawa ng iba pang mga galaw."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"huwag paganahin o baguhin ang status bar"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Pinapayagan ang app na huwag paganahin ang status bar o magdagdag at mag-alis ng mga icon ng system."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"maging status bar"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 283bcebb..b0c6d5a 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Kredi kartı ve şifre gibi kişisel bilgiler içerir."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ekran büyütecini kontrol et"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ekranın yakınlaştırma seviyesini ve konumunu kontrol edin."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Haraketleri yapma"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Hafifçe dokunabilir, hızlıca kaydırabilir, sıkıştırabilir ve diğer hareketleri yapabilirsiniz."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"durum çubuğunu devre dışı bırak veya değiştir"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Uygulamaya, durum çubuğunu devre dışı bırakma ve sistem simgelerini ekleyip kaldırma izni verir."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"durum çubuğunda olma"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index fce4cc3..af1354a 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -258,6 +258,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Включає особисті дані, як-от номери кредитних карток і паролі."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Контролювати збільшення екрана"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Контролювати масштаб і розташування екрана."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Виконання жестів"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Можна торкатися, проводити пальцем, стискати пальці та виконувати інші жести."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"вимикати чи змін. рядок стану"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Дозволяє програмі вимикати рядок стану чи додавати та видаляти піктограми системи."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"відображатися як рядок стану"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 519f42b..82bf7ab 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"اس میں ذاتی ڈیٹا جیسے کریڈٹ کارڈ نمبرز اور پاس ورڈز شامل ہیں۔"</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"ڈسپلے بڑا کرنے کے عمل کو کنٹرول کریں"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ڈسپلے کے زوم کی سطح اور پوزیشن کو کنٹرول کریں۔"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"اشارے انجام دیں"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"تھپتھپانا، سوائپ کرنا، چٹکی بھرنا اور دیگر اشارے انجام دے سکتی ہے"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"اسٹیٹس بار کو غیر فعال یا اس میں ترمیم کریں"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"ایپ کو اسٹیٹس بار غیر فعال کرنے یا سسٹم آئیکنز شامل کرنے اور ہٹانے کی اجازت دیتا ہے۔"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"بطور اسٹیٹس بار کام لیں"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index e90d921..c4be0b9 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Bunga kredit karta raqamlari va parollar kabi shaxsiy ma’lumotlar kiradi."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ekranni kattalashtirishni boshqarish"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ekranni kattalashtirish darajasi va joylashuvini boshqaradi."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Imo-ishoralar bilan boshqarish"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Bosish, surish; jipslashtirish va boshqa imo-ishoralarni amalga oshirish mumkin."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"holat panelini o‘zgartirish yoki o‘chirish"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Ilova holat panelini o‘chirib qo‘yishi hamda tizim ikonkalarini qo‘shishi yoki olib tashlashi mumkin."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"holat qatorida ko‘rinishi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 31e090b..69b0b99 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Bao gồm dữ liệu cá nhân chẳng hạn như số thẻ tín dụng và mật khẩu."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kiểm soát thu phóng màn hình"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kiểm soát vị trí và mức thu phóng của màn hình."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Thực hiện cử chỉ"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Có thể nhấn, vuốt, chụm và thực hiện các cử chỉ khác."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"vô hiệu hóa hoặc sửa đổi thanh trạng thái"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Cho phép ứng dụng vô hiệu hóa thanh trạng thái hoặc thêm và xóa biểu tượng hệ thống."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"trở thành thanh trạng thái"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index c5cd59a..4c7bfd3 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"包含个人数据,例如信用卡号和密码。"</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"控制显示内容放大功能"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"控制显示内容的缩放级别和位置。"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"执行手势"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"可执行点按、滑动、双指张合等手势。"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"停用或修改状态栏"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"允许应用停用状态栏或者增删系统图标。"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"用作状态栏"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 36ba2ad6..d6cacb7 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"包括個人資料,如信用卡號碼和密碼。"</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"控制顯示屏的放大功能"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"控制顯示屏的縮放程度和位置。"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"執行手勢"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"可以輕按、快速滑動和兩指縮放,並執行其他手勢。"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"停用或修改狀態列"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"允許應用程式停用狀態列,並可新增或移除系統圖示。"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"成為狀態列"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 72ea523..a47f73d 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"包括個人資料,如信用卡號碼和密碼。"</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"控管顯示畫面放大功能"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"控管顯示畫面的縮放等級和位置。"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"使用手勢"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"可使用輕按、滑動和雙指撥動等手勢。"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"停用或變更狀態列"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"允許應用程式停用狀態列,並可新增或移除系統圖示。"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"以狀態列顯示"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index bee7eea..b34594f 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -256,6 +256,8 @@
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Kufaka phakathi idatha yomuntu siqu efana nezinombolo zekhadi lesikweletu namaphasiwedi."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Lawula ukulungiswa kwesibonisi"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Lawula ileveli yokusondeza yesibonisi nendawo."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Yenza ukuthinta"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Ingathepha, iswayiphe, incinze, futhi yenze okunye ukuthintwa."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"khubaza noma guqula ibha yomumo"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Ivumela uhlelo lokusebenza ukuthi yenze umudwa ochaza ngesimo ukuthi ungasebenzi noma ukufaka noma ukukhipha izithonjana zohlelo."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"yiba yibha yesimo"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 58a77e8..6eba78a 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1748,6 +1748,10 @@
<attr name="isolatedProcess" format="boolean" />
<attr name="singleUser" />
<attr name="encryptionAware" />
+ <!-- If the service is an {@link android.R.attr#isolatedProcess} service, this permits a
+ client to bind to the service as if it were running it its own package. The service
+ must also be {@link android.R.attr#exported} if this flag is set. -->
+ <attr name="externalService" format="boolean" />
</declare-styleable>
<!-- The <code>receiver</code> tag declares an
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 58c4046..2acb91d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -413,22 +413,26 @@
<!-- Boolean indicating whether or not wifi firmware debugging is enabled -->
<bool translatable="false" name="config_wifi_enable_wifi_firmware_debugging">true</bool>
- <!-- Integer specifying the basic autojoin parameters -->
+ <!-- Integer specifying the basic Quality Network Selection parameters -->
<integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_threshold">-65</integer>
- <integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_factor">5</integer>
+ <integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_factor">40</integer>
<integer translatable="false" name="config_wifi_framework_current_association_hysteresis_high">16</integer>
<integer translatable="false" name="config_wifi_framework_current_association_hysteresis_low">10</integer>
<integer translatable="false" name="config_wifi_framework_5GHz_preference_penalty_threshold">-75</integer>
- <integer translatable="false" name="config_wifi_framework_5GHz_preference_penalty_factor">2</integer>
-
+ <integer translatable="false" name="config_wifi_framework_RSSI_SCORE_OFFSET">85</integer>
+ <integer translatable="false" name="config_wifi_framework_RSSI_SCORE_SLOPE">4</integer>
+ <integer translatable="false" name="config_wifi_framework_SAME_BSSID_AWARD">24</integer>
+ <integer translatable="false" name="config_wifi_framework_LAST_SELECTION_AWARD">480</integer>
+ <integer translatable="false" name="config_wifi_framework_PASSPOINT_SECURITY_AWARD">40</integer>
+ <integer translatable="false" name="config_wifi_framework_SECURITY_AWARD">80</integer>
<!-- Integer parameters of the wifi to cellular handover feature
wifi should not stick to bad networks -->
<integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz">-82</integer>
- <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_5GHz">-72</integer>
- <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_5GHz">-60</integer>
- <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz">-87</integer>
- <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_24GHz">-77</integer>
- <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_24GHz">-65</integer>
+ <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_5GHz">-70</integer>
+ <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_5GHz">-57</integer>
+ <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz">-85</integer>
+ <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_24GHz">-73</integer>
+ <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_24GHz">-60</integer>
<integer translatable="false" name="config_wifi_framework_wifi_score_bad_link_speed_24">6</integer>
<integer translatable="false" name="config_wifi_framework_wifi_score_bad_link_speed_5">12</integer>
<integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_24">24</integer>
@@ -502,7 +506,7 @@
<integer translatable="false" name="config_wifi_framework_network_black_list_min_time_milli">120000</integer>
<!-- Integer indicating RSSI boost given to current network -->
- <integer translatable="false" name="config_wifi_framework_current_network_boost">25</integer>
+ <integer translatable="false" name="config_wifi_framework_current_network_boost">16</integer>
<!-- Integer indicating how to handle beacons with uninitialized RSSI value of 0 -->
<integer translatable="false" name="config_wifi_framework_scan_result_rssi_level_patchup_value">-85</integer>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index acea461..c883b1f8 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2689,6 +2689,7 @@
<public type="attr" name="tickMarkTint" />
<public type="attr" name="tickMarkTintMode" />
<public type="attr" name="canPerformGestures" />
+ <public type="attr" name="externalService" />
<public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
<public type="style" name="Widget.Material.SeekBar.Discrete" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 706dd20..a3021cb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -310,7 +310,12 @@
<java-symbol type="integer" name="config_wifi_framework_current_association_hysteresis_high" />
<java-symbol type="integer" name="config_wifi_framework_current_association_hysteresis_low" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_threshold" />
- <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_factor" />
+ <java-symbol type="integer" name="config_wifi_framework_RSSI_SCORE_OFFSET" />
+ <java-symbol type="integer" name="config_wifi_framework_RSSI_SCORE_SLOPE" />
+ <java-symbol type="integer" name="config_wifi_framework_SAME_BSSID_AWARD" />
+ <java-symbol type="integer" name="config_wifi_framework_LAST_SELECTION_AWARD" />
+ <java-symbol type="integer" name="config_wifi_framework_PASSPOINT_SECURITY_AWARD" />
+ <java-symbol type="integer" name="config_wifi_framework_SECURITY_AWARD" />
<java-symbol type="integer" name="config_wifi_disconnected_short_scan_interval" />
<java-symbol type="integer" name="config_wifi_disconnected_long_scan_interval" />
<java-symbol type="integer" name="config_wifi_associated_short_scan_interval" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 5f1f927..77d2ada 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -33,6 +33,9 @@
and http://mobilcent.com/info-worldwide.asp and extracted from:
http://smscoin.net/software/engine/WordPress/Paid+SMS-registration/ -->
+ <!-- Arab Emirates -->
+ <shortcode country="ae" free="3214|1017" />
+
<!-- Albania: 5 digits, known short codes listed -->
<shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
@@ -43,7 +46,7 @@
<shortcode country="at" pattern="11\\d{4}" premium="09.*" free="116\\d{3}" />
<!-- Australia: 6 or 8 digits starting with "19" -->
- <shortcode country="au" pattern="19(?:\\d{4}|\\d{6})" premium="19998882" />
+ <shortcode country="au" pattern="19(?:\\d{4}|\\d{6})" premium="19998882|19944444" />
<!-- Azerbaijan: 4-5 digits, known premium codes listed -->
<shortcode country="az" pattern="\\d{4,5}" premium="330[12]|87744|901[234]|93(?:94|101)|9426|9525" />
@@ -58,10 +61,10 @@
<shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" />
<!-- Canada: 5-6 digits -->
- <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188" />
+ <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188|43030" />
<!-- Switzerland: 3-5 digits: http://www.swisscom.ch/fxres/kmu/thirdpartybusiness_code_of_conduct_en.pdf -->
- <shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111" />
+ <shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111|30118" />
<!-- China: premium shortcodes start with "1066", free shortcodes start with "1065":
http://clients.txtnation.com/entries/197192-china-premium-sms-short-code-requirements -->
@@ -75,7 +78,7 @@
<shortcode country="cz" premium="9\\d{6,7}" free="116\\d{3}" />
<!-- Germany: 4-5 digits plus 1232xxx (premium codes from http://www.vodafone.de/infofaxe/537.pdf and http://premiumdienste.eplus.de/pdf/kodex.pdf), plus EU. To keep the premium regex from being too large, it only includes payment processors that have been used by SMS malware, with the regular pattern matching the other premium short codes. -->
- <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}|81214|81215" />
+ <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}|81214|81215|47529" />
<!-- Denmark: see http://iprs.webspacecommerce.com/Denmark-Premium-Rate-Numbers -->
<shortcode country="dk" pattern="\\d{4,5}" premium="1\\d{3}" free="116\\d{3}" />
@@ -89,7 +92,7 @@
<shortcode country="es" premium="[23][57]\\d{3}|280\\d{2}|[79]9[57]\\d{3}" free="116\\d{3}" />
<!-- Finland: 5-6 digits, premium 0600, 0700: http://en.wikipedia.org/wiki/Telephone_numbers_in_Finland -->
- <shortcode country="fi" pattern="\\d{5,6}" premium="0600.*|0700.*|171(?:59|63)" free="116\\d{3}" />
+ <shortcode country="fi" pattern="\\d{5,6}" premium="0600.*|0700.*|171(?:59|63)" free="116\\d{3}|14789" />
<!-- France: 5 digits, free: 3xxxx, premium [4-8]xxxx, plus EU:
http://clients.txtnation.com/entries/161972-france-premium-sms-short-code-requirements,
@@ -122,9 +125,15 @@
http://clients.txtnation.com/attachments/token/di5kfblvubttvlw/?name=Italy_CASP_EN.pdf -->
<shortcode country="it" pattern="\\d{5}" premium="4\\d{4}" free="116\\d{3}" />
+ <!-- Japan: 8083 used by SOFTBANK_DCB_2 -->
+ <shortcode country="jp" free="8083" />
+
<!-- Kyrgyzstan: 4 digits, known premium codes listed -->
<shortcode country="kg" pattern="\\d{4}" premium="415[2367]|444[69]" />
+ <!-- Korea: http://www.smsideatechnosolutions.com/chhattisgarh/korea/sms-short-code.html -->
+ <shortcode country="kr" pattern="\\d{4,7}" free="\\*9712|\\*9090|##900" />
+
<!-- Kazakhstan: 4 digits, known premium codes listed: http://smscoin.net/info/pricing-kazakhstan/ -->
<shortcode country="kz" pattern="\\d{4}" premium="335[02]|4161|444[469]|77[2359]0|8444|919[3-5]|968[2-5]" />
@@ -151,27 +160,33 @@
<shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" />
<!-- New Zealand: 3-4 digits, known premium codes listed -->
- <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995" />
+ <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" />
+
+ <!-- Philippines -->
+ <shortcode country="ph" free="2147" />
<!-- Poland: 4-5 digits (not confirmed), known premium codes listed, plus EU -->
- <shortcode country="pl" pattern="\\d{4,5}" premium="74240|79(?:10|866)|92525" free="116\\d{3}" />
+ <shortcode country="pl" pattern="\\d{4,5}" premium="74240|79(?:10|866)|92525" free="116\\d{3}|8012" />
<!-- Portugal: 5 digits, plus EU:
http://clients.txtnation.com/entries/158326-portugal-premium-sms-short-code-regulations -->
<shortcode country="pt" premium="6[1289]\\d{3}" free="116\\d{3}" />
<!-- Romania: 4 digits, plus EU: http://www.simplus.ro/en/resources/glossary-of-terms/ -->
- <shortcode country="ro" pattern="\\d{4}" premium="12(?:63|66|88)|13(?:14|80)" free="116\\d{3}" />
+ <shortcode country="ro" pattern="\\d{4}" premium="12(?:63|66|88)|13(?:14|80)" free="116\\d{3}|3654" />
<!-- Russia: 4 digits, known premium codes listed: http://smscoin.net/info/pricing-russia/ -->
- <shortcode country="ru" pattern="\\d{4}" premium="1(?:1[56]1|899)|2(?:09[57]|322|47[46]|880|990)|3[589]33|4161|44(?:4[3-9]|81)|77(?:33|81)" />
+ <shortcode country="ru" pattern="\\d{4}" premium="1(?:1[56]1|899)|2(?:09[57]|322|47[46]|880|990)|3[589]33|4161|44(?:4[3-9]|81)|77(?:33|81)|8424" />
+
+ <!-- Saudi Arabia -->
+ <shortcode country="sa" free="8145" />
<!-- Sweden: 5 digits (72xxx), plus EU: http://www.viatel.se/en/premium-sms/ -->
<shortcode country="se" premium="72\\d{3}" free="116\\d{3}" />
<!-- Singapore: 5 digits: http://clients.txtnation.com/entries/306442-singapore-premium-sms-short-code-requirements
Free government directory info at 74688: http://app.sgdi.gov.sg/sms_help.asp -->
- <shortcode country="sg" pattern="7\\d{4}" premium="73800" standard="74688" />
+ <shortcode country="sg" pattern="7\\d{4}" premium="73800" standard="74688|70134" />
<!-- Slovenia: 4 digits (premium=3xxx, 6xxx, 8xxx), plus EU: http://www.cmtelecom.com/premium-sms/slovenia -->
<shortcode country="si" pattern="\\d{4}" premium="[368]\\d{3}" free="116\\d{3}" />
@@ -179,9 +194,15 @@
<!-- Slovakia: 4 digits (premium), plus EU: http://www.cmtelecom.com/premium-sms/slovakia -->
<shortcode country="sk" premium="\\d{4}" free="116\\d{3}" />
+ <!-- Thailand: 4186001 used by AIS_TH_DCB -->
+ <shortcode country="th" free="4186001" />
+
<!-- Tajikistan: 4 digits, known premium codes listed -->
<shortcode country="tj" pattern="\\d{4}" premium="11[3-7]1|4161|4333|444[689]" />
+ <!-- Turkey -->
+ <shortcode country="tr" free="7529|5528" />
+
<!-- Ukraine: 4 digits, known premium codes listed -->
<shortcode country="ua" pattern="\\d{4}" premium="444[3-9]|70[579]4|7540" />
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java b/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
new file mode 100644
index 0000000..2e0e6dc
--- /dev/null
+++ b/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 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.text;
+
+import android.text.Layout.Alignment;
+import junit.framework.TestCase;
+
+/**
+ * Tests for text measuring methods of StaticLayout.
+ */
+public class StaticLayoutTextMeasuringTest extends TestCase {
+ private static final float SPACE_MULTI = 1.0f;
+ private static final float SPACE_ADD = 0.0f;
+ private static final int DEFAULT_OUTER_WIDTH = 150;
+ private static final Alignment DEFAULT_ALIGN = Alignment.ALIGN_LEFT;
+
+ private TextPaint mDefaultPaint;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ if (mDefaultPaint == null) {
+ mDefaultPaint = new TextPaint();
+ }
+ }
+
+ public void testGetPrimaryHorizontal_zwnbsp() {
+ // a, ZERO WIDTH NO-BREAK SPACE
+ String testString = "a\uFEFF";
+ StaticLayout layout = new StaticLayout(testString, mDefaultPaint,
+ DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+ assertEquals(0.0f, layout.getPrimaryHorizontal(0));
+ assertEquals(layout.getPrimaryHorizontal(2), layout.getPrimaryHorizontal(1));
+ }
+
+ public void testGetPrimaryHorizontal_devanagari() {
+ // DEVANAGARI LETTER KA, DEVANAGARI VOWEL SIGN AA
+ String testString = "\u0915\u093E";
+ StaticLayout layout = new StaticLayout(testString, mDefaultPaint,
+ DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+ assertEquals(0.0f, layout.getPrimaryHorizontal(0));
+ assertEquals(layout.getPrimaryHorizontal(2), layout.getPrimaryHorizontal(1));
+ }
+
+ public void testGetPrimaryHorizontal_flagEmoji() {
+ // REGIONAL INDICATOR SYMBOL LETTER U, REGIONAL INDICATOR SYMBOL LETTER S, REGIONAL
+ // INDICATOR SYMBOL LETTER Z
+ // First two code points (U and S) forms a US flag.
+ String testString = "\uD83C\uDDFA\uD83C\uDDF8\uD83C\uDDFF";
+ StaticLayout layout = new StaticLayout(testString, mDefaultPaint,
+ DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+ assertEquals(0.0f, layout.getPrimaryHorizontal(0));
+ assertEquals(layout.getPrimaryHorizontal(4), layout.getPrimaryHorizontal(1));
+ assertEquals(layout.getPrimaryHorizontal(4), layout.getPrimaryHorizontal(2));
+ assertEquals(layout.getPrimaryHorizontal(4), layout.getPrimaryHorizontal(3));
+
+ assertTrue(layout.getPrimaryHorizontal(6) > layout.getPrimaryHorizontal(4));
+ assertEquals(layout.getPrimaryHorizontal(6), layout.getPrimaryHorizontal(5));
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
index 48590c1..1966313 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
@@ -22,6 +22,7 @@
import android.view.ActionMode;
import android.view.ActionMode.Callback;
import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -32,6 +33,8 @@
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
+import java.util.List;
+
/**
* Tests {@link PhoneWindow}'s {@link ActionMode} related methods.
*/
@@ -288,6 +291,9 @@
@Override
public void onActionModeFinished(ActionMode mode) {}
+
+ @Override
+ public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {}
}
private static final class MockActionModeCallback implements ActionMode.Callback {
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 78424e3..c0dfe77 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -204,11 +204,13 @@
/**
* Sets the X position around which the drawable is rotated.
+ * <p>
+ * If the X pivot is relative (as specified by
+ * {@link #setPivotXRelative(boolean)}), then the position represents a
+ * fraction of the drawable width. Otherwise, the position represents an
+ * absolute value in pixels.
*
- * @param pivotX X position around which to rotate. If the X pivot is
- * relative, the position represents a fraction of the drawable
- * width. Otherwise, the position represents an absolute value in
- * pixels.
+ * @param pivotX X position around which to rotate
* @see #setPivotXRelative(boolean)
* @attr ref android.R.styleable#RotateDrawable_pivotX
*/
@@ -254,11 +256,13 @@
/**
* Sets the Y position around which the drawable is rotated.
+ * <p>
+ * If the Y pivot is relative (as specified by
+ * {@link #setPivotYRelative(boolean)}), then the position represents a
+ * fraction of the drawable height. Otherwise, the position represents an
+ * absolute value in pixels.
*
- * @param pivotY Y position around which to rotate. If the Y pivot is
- * relative, the position represents a fraction of the drawable
- * height. Otherwise, the position represents an absolute value
- * in pixels.
+ * @param pivotY Y position around which to rotate
* @see #getPivotY()
* @attr ref android.R.styleable#RotateDrawable_pivotY
*/
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index cdd891f..e2350b6 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -226,6 +226,7 @@
$(hwui_test_common_src_files) \
tests/unit/CanvasStateTests.cpp \
tests/unit/ClipAreaTests.cpp \
+ tests/unit/CrashHandlerInjector.cpp \
tests/unit/DamageAccumulatorTests.cpp \
tests/unit/DeviceInfoTests.cpp \
tests/unit/FatVectorTests.cpp \
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 166656cb..c4c655b 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -51,20 +51,25 @@
// updated in the order they're passed in (mLayerBuilders are issued to Renderer in reverse)
for (int i = layers.entries().size() - 1; i >= 0; i--) {
RenderNode* layerNode = layers.entries()[i].renderNode;
- const Rect& layerDamage = layers.entries()[i].damage;
- layerNode->computeOrdering();
+ // only schedule repaint if node still on layer - possible it may have been
+ // removed during a dropped frame, but layers may still remain scheduled so
+ // as not to lose info on what portion is damaged
+ if (CC_LIKELY(layerNode->getLayer() != nullptr)) {
+ const Rect& layerDamage = layers.entries()[i].damage;
+ layerNode->computeOrdering();
- // map current light center into RenderNode's coordinate space
- Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter();
- layerNode->getLayer()->inverseTransformInWindow.mapPoint3d(lightCenter);
+ // map current light center into RenderNode's coordinate space
+ Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter();
+ layerNode->getLayer()->inverseTransformInWindow.mapPoint3d(lightCenter);
- saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0,
- layerDamage, lightCenter, nullptr, layerNode);
+ saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0,
+ layerDamage, lightCenter, nullptr, layerNode);
- if (layerNode->getDisplayList()) {
- deferNodeOps(*layerNode);
+ if (layerNode->getDisplayList()) {
+ deferNodeOps(*layerNode);
+ }
+ restoreForLayer();
}
- restoreForLayer();
}
// Defer Fbo0
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 56cb104..793df92 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -407,8 +407,9 @@
float canvasScaleY = 1.0f;
if (mCanvasMatrix.getSkewX() == 0 && mCanvasMatrix.getSkewY() == 0) {
// Only use the scale value when there's no skew or rotation in the canvas matrix.
- canvasScaleX = mCanvasMatrix.getScaleX();
- canvasScaleY = mCanvasMatrix.getScaleY();
+ // TODO: Add a cts test for drawing VD on a canvas with negative scaling factors.
+ canvasScaleX = fabs(mCanvasMatrix.getScaleX());
+ canvasScaleY = fabs(mCanvasMatrix.getScaleY());
}
int scaledWidth = (int) (mBounds.width() * canvasScaleX);
int scaledHeight = (int) (mBounds.height() * canvasScaleY);
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 968135b..dd48a83 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -515,11 +515,11 @@
void CanvasContext::prepareAndDraw(RenderNode* node) {
ATRACE_CALL();
+ nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
UiFrameInfoBuilder(frameInfo)
.addFlag(FrameInfoFlags::RTAnimation)
- .setVsync(mRenderThread.timeLord().computeFrameTimeNanos(),
- mRenderThread.timeLord().latestVsync());
+ .setVsync(vsync, vsync);
TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
@@ -581,7 +581,7 @@
node->setPropertyFieldsDirty(RenderNode::GENERIC);
#if HWUI_NEW_OPS
- LOG_ALWAYS_FATAL("unsupported");
+ // TODO: support buildLayer
#else
mCanvas->markLayersAsBuildLayers();
mCanvas->flushLayerUpdates();
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 43282c9..72c7e4e 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -450,6 +450,11 @@
} else {
fprintf(file, "\nNo caches instance.\n");
}
+#if HWUI_NEW_OPS
+ fprintf(file, "\nPipeline=FrameBuilder\n");
+#else
+ fprintf(file, "\nPipeline=OpenGLRenderer\n");
+#endif
fflush(file);
return nullptr;
}
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 624f3bd..d56693c 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -19,6 +19,10 @@
#include "DeferredLayerUpdater.h"
#include "LayerRenderer.h"
+#include <unistd.h>
+#include <signal.h>
+#include <setjmp.h>
+
namespace android {
namespace uirenderer {
@@ -121,5 +125,41 @@
canvas->drawTextOnPath(glyphs.data(), glyphs.size(), path, 0, 0, paint);
}
+static void defaultCrashHandler() {
+ fprintf(stderr, "RenderThread crashed!");
+}
+
+static jmp_buf gErrJmpBuff;
+static std::function<void()> gCrashHandler = defaultCrashHandler;
+
+static void signalHandler(int sig) {
+ longjmp(gErrJmpBuff, 1);
+}
+
+void TestUtils::setRenderThreadCrashHandler(std::function<void()> crashHandler) {
+ gCrashHandler = crashHandler;
+}
+
+void TestUtils::TestTask::run() {
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = signalHandler;
+
+ if (setjmp(gErrJmpBuff)) {
+ gCrashHandler();
+ return;
+ }
+
+ sigaction(SIGABRT, &act, nullptr);
+
+
+ // RenderState only valid once RenderThread is running, so queried here
+ RenderState& renderState = renderthread::RenderThread::getInstance().renderState();
+
+ renderState.onGLContextCreated();
+ rtCallback(renderthread::RenderThread::getInstance());
+ renderState.onGLContextDestroyed();
+}
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 42cd0ce..c506bb3e 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -173,19 +173,14 @@
typedef std::function<void(renderthread::RenderThread& thread)> RtCallback;
+ static void setRenderThreadCrashHandler(std::function<void()> crashHandler);
+
class TestTask : public renderthread::RenderTask {
public:
TestTask(RtCallback rtCallback)
: rtCallback(rtCallback) {}
virtual ~TestTask() {}
- virtual void run() override {
- // RenderState only valid once RenderThread is running, so queried here
- RenderState& renderState = renderthread::RenderThread::getInstance().renderState();
-
- renderState.onGLContextCreated();
- rtCallback(renderthread::RenderThread::getInstance());
- renderState.onGLContextDestroyed();
- };
+ virtual void run() override;
RtCallback rtCallback;
};
diff --git a/libs/hwui/tests/unit/CrashHandlerInjector.cpp b/libs/hwui/tests/unit/CrashHandlerInjector.cpp
new file mode 100644
index 0000000..685c264
--- /dev/null
+++ b/libs/hwui/tests/unit/CrashHandlerInjector.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "tests/common/TestUtils.h"
+
+#include <gtest/gtest.h>
+
+using namespace android::uirenderer;
+
+static void gunitCrashHandler() {
+ FAIL() << "RenderThread fatal exception!";
+}
+
+static void hookError() {
+ TestUtils::setRenderThreadCrashHandler(gunitCrashHandler);
+}
+
+class HookErrorInit {
+public:
+ HookErrorInit() { hookError(); }
+};
+
+static HookErrorInit sInit;
diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp
index 05b4a72..dcc4946 100644
--- a/libs/hwui/utils/TestWindowContext.cpp
+++ b/libs/hwui/utils/TestWindowContext.cpp
@@ -18,6 +18,7 @@
#include "AnimationContext.h"
#include "DisplayListCanvas.h"
#include "IContextFactory.h"
+#include "RecordingCanvas.h"
#include "RenderNode.h"
#include "SkTypes.h"
#include "gui/BufferQueue.h"
@@ -88,9 +89,11 @@
mProxy->setup(mSize.width(), mSize.height(), 800.0f,
255 * 0.075f, 255 * 0.15f);
mProxy->setLightCenter(lightVector);
- mCanvas.reset(new
- android::uirenderer::DisplayListCanvas(mSize.width(),
- mSize.height()));
+#if HWUI_NEW_OPS
+ mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height()));
+#else
+ mCanvas.reset(new android::uirenderer::DisplayListCanvas(mSize.width(), mSize.height()));
+#endif
}
SkCanvas* prepareToDraw() {
@@ -168,7 +171,11 @@
std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
+#if HWUI_NEW_OPS
+ std::unique_ptr<android::uirenderer::RecordingCanvas> mCanvas;
+#else
std::unique_ptr<android::uirenderer::DisplayListCanvas> mCanvas;
+#endif
android::sp<android::IGraphicBufferProducer> mProducer;
android::sp<android::IGraphicBufferConsumer> mConsumer;
android::sp<android::CpuConsumer> mCpuConsumer;
diff --git a/media/java/android/media/IMediaResourceMonitor.aidl b/media/java/android/media/IMediaResourceMonitor.aidl
new file mode 100644
index 0000000..7b4bc39
--- /dev/null
+++ b/media/java/android/media/IMediaResourceMonitor.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2016 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.media;
+
+/** {@hide} */
+interface IMediaResourceMonitor
+{
+ oneway void notifyResourceGranted(in int pid, String type, String subType, long value);
+}
+
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 96c616b..dfe024a 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -17,6 +17,7 @@
package android.media;
import android.content.ContentProviderClient;
+import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
@@ -37,6 +38,7 @@
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video;
import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
import android.sax.Element;
import android.sax.ElementListener;
import android.sax.RootElement;
@@ -328,8 +330,6 @@
// used when scanning the image database so we know whether we have to prune
// old thumbnail files
private int mOriginalCount;
- /** Whether the database had any entries in it before the scan started */
- private boolean mWasEmptyPriorToScan = false;
/** Whether the scanner has set a default sound for the ringer ringtone. */
private boolean mDefaultRingtoneSet;
/** Whether the scanner has set a default sound for the notification ringtone. */
@@ -562,12 +562,29 @@
FileEntry entry = beginFile(path, mimeType, lastModified,
fileSize, isDirectory, noMedia);
+ if (entry == null) {
+ return null;
+ }
+
// if this file was just inserted via mtp, set the rowid to zero
// (even though it already exists in the database), to trigger
// the correct code path for updating its entry
if (mMtpObjectHandle != 0) {
entry.mRowId = 0;
}
+
+ if (entry.mPath != null &&
+ ((!mDefaultNotificationSet &&
+ doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename))
+ || (!mDefaultRingtoneSet &&
+ doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename))
+ || (!mDefaultAlarmSet &&
+ doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)))) {
+ Log.w(TAG, "forcing rescan of " + entry.mPath +
+ "since ringtone setting didn't finish");
+ scanAlways = true;
+ }
+
// rescan for metadata if file was modified since last scan
if (entry != null && (entry.mLastModifiedChanged || scanAlways)) {
if (noMedia) {
@@ -947,6 +964,26 @@
}
Uri result = null;
boolean needToSetSettings = false;
+ // Setting a flag in order not to use bulk insert for the file related with
+ // notifications, ringtones, and alarms, because the rowId of the inserted file is
+ // needed.
+ if (notifications && !mDefaultNotificationSet) {
+ if (TextUtils.isEmpty(mDefaultNotificationFilename) ||
+ doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) {
+ needToSetSettings = true;
+ }
+ } else if (ringtones && !mDefaultRingtoneSet) {
+ if (TextUtils.isEmpty(mDefaultRingtoneFilename) ||
+ doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) {
+ needToSetSettings = true;
+ }
+ } else if (alarms && !mDefaultAlarmSet) {
+ if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
+ doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
+ needToSetSettings = true;
+ }
+ }
+
if (rowId == 0) {
if (mMtpObjectHandle != 0) {
values.put(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, mMtpObjectHandle);
@@ -958,28 +995,6 @@
}
values.put(Files.FileColumns.FORMAT, format);
}
- // Setting a flag in order not to use bulk insert for the file related with
- // notifications, ringtones, and alarms, because the rowId of the inserted file is
- // needed.
- if (mWasEmptyPriorToScan) {
- if (notifications && !mDefaultNotificationSet) {
- if (TextUtils.isEmpty(mDefaultNotificationFilename) ||
- doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) {
- needToSetSettings = true;
- }
- } else if (ringtones && !mDefaultRingtoneSet) {
- if (TextUtils.isEmpty(mDefaultRingtoneFilename) ||
- doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) {
- needToSetSettings = true;
- }
- } else if (alarms && !mDefaultAlarmSet) {
- if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
- doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
- needToSetSettings = true;
- }
- }
- }
-
// New file, insert it.
// Directories need to be inserted before the files they contain, so they
// get priority when bulk inserting.
@@ -1049,14 +1064,18 @@
private void setSettingIfNotSet(String settingName, Uri uri, long rowId) {
- String existingSettingValue = Settings.System.getString(mContext.getContentResolver(),
- settingName);
+ if(wasSettingAlreadySet(settingName)) {
+ return;
+ }
+ ContentResolver cr = mContext.getContentResolver();
+ String existingSettingValue = Settings.System.getString(cr, settingName);
if (TextUtils.isEmpty(existingSettingValue)) {
// Set the setting to the given URI
- Settings.System.putString(mContext.getContentResolver(), settingName,
+ Settings.System.putString(cr, settingName,
ContentUris.withAppendedId(uri, rowId).toString());
}
+ Settings.System.putInt(cr, settingSetIndicatorName(settingName), 1);
}
private int getFileTypeFromDrm(String path) {
@@ -1083,6 +1102,20 @@
}; // end of anonymous MediaScannerClient instance
+ private String settingSetIndicatorName(String base) {
+ return base + "_set";
+ }
+
+ private boolean wasSettingAlreadySet(String name) {
+ ContentResolver cr = mContext.getContentResolver();
+ String indicatorName = settingSetIndicatorName(name);
+ try {
+ return Settings.System.getInt(cr, indicatorName) != 0;
+ } catch (SettingNotFoundException e) {
+ return false;
+ }
+ }
+
private void prescan(String filePath, boolean prescanFiles) throws RemoteException {
Cursor c = null;
String where = null;
@@ -1100,6 +1133,10 @@
selectionArgs = new String[] { "" };
}
+ mDefaultRingtoneSet = wasSettingAlreadySet(Settings.System.RINGTONE);
+ mDefaultNotificationSet = wasSettingAlreadySet(Settings.System.NOTIFICATION_SOUND);
+ mDefaultAlarmSet = wasSettingAlreadySet(Settings.System.ALARM_ALERT);
+
// Tell the provider to not delete the file.
// If the file is truly gone the delete is unnecessary, and we want to avoid
// accidentally deleting files that are really there (this may happen if the
@@ -1117,7 +1154,6 @@
// with CursorWindow positioning.
long lastId = Long.MIN_VALUE;
Uri limitUri = mFilesUri.buildUpon().appendQueryParameter("limit", "1000").build();
- mWasEmptyPriorToScan = true;
while (true) {
selectionArgs[0] = "" + lastId;
@@ -1136,7 +1172,6 @@
if (num == 0) {
break;
}
- mWasEmptyPriorToScan = false;
while (c.moveToNext()) {
long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
String path = c.getString(FILES_PRESCAN_PATH_COLUMN_INDEX);
@@ -1284,7 +1319,7 @@
}
}
- private void postscan(String[] directories) throws RemoteException {
+ private void postscan(final String[] directories) throws RemoteException {
// handle playlists last, after we know what media files are on the storage.
if (mProcessPlaylists) {
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index d24c5e8..4379a99 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -21,6 +21,8 @@
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
+import com.android.internal.util.Preconditions;
+
import java.io.IOException;
/**
@@ -164,12 +166,14 @@
* of the data and speed of the devices.
*
* @param objectHandle handle of the object to read
- * @param offset Start index of reading range.
- * @param size Size of reading range.
+ * @param offset Start index of reading range. It must be a non-negative value at most
+ * 0xffffffff.
+ * @param size Size of reading range. It must be a non-negative value at most 0xffffffff. If
+ * 0xffffffff is specified, the method obtains the full bytes of object.
* @param buffer Array to write data.
* @return Size of bytes that are actually read.
*/
- public int getPartialObject(int objectHandle, int offset, int size, byte[] buffer)
+ public long getPartialObject(int objectHandle, long offset, long size, byte[] buffer)
throws IOException {
return native_get_partial_object(objectHandle, offset, size, buffer);
}
@@ -340,8 +344,8 @@
private native int[] native_get_object_handles(int storageId, int format, int objectHandle);
private native MtpObjectInfo native_get_object_info(int objectHandle);
private native byte[] native_get_object(int objectHandle, int objectSize);
- private native int native_get_partial_object(
- int objectHandle, int offset, int objectSize, byte[] buffer) throws IOException;
+ private native long native_get_partial_object(
+ int objectHandle, long offset, long objectSize, byte[] buffer) throws IOException;
private native byte[] native_get_thumbnail(int objectHandle);
private native boolean native_delete_object(int objectHandle);
private native long native_get_parent(int objectHandle);
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 130dfe5..b1b3b62 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -372,12 +372,12 @@
return nullptr;
}
-static jint
+static jlong
android_mtp_MtpDevice_get_partial_object(JNIEnv *env,
jobject thiz,
jint objectID,
- jint offset,
- jint size,
+ jlong offset,
+ jlong size,
jbyteArray array)
{
if (!array) {
@@ -385,6 +385,22 @@
return -1;
}
+ if (offset < 0 || 0xffffffffL < offset) {
+ jniThrowException(
+ env,
+ "java/lang/IllegalArgumentException",
+ "Offset argument must be a 32-bit unsigned integer.");
+ return -1;
+ }
+
+ if (size < 0 || 0xffffffffL < size) {
+ jniThrowException(
+ env,
+ "java/lang/IllegalArgumentException",
+ "Size argument must be a 32-bit unsigned integer.");
+ return -1;
+ }
+
MtpDevice* const device = get_device_from_object(env, thiz);
if (!device) {
jniThrowException(env, "java/io/IOException", "Failed to obtain MtpDevice.");
@@ -393,16 +409,13 @@
JavaArrayWriter writer(env, array);
uint32_t written_size;
- bool success = device->readPartialObject(
+ const bool success = device->readPartialObject(
objectID, offset, size, &written_size, JavaArrayWriter::writeTo, &writer);
if (!success) {
jniThrowException(env, "java/io/IOException", "Failed to read data.");
return -1;
}
- // Note: assumption here is that a negative value will be treated as unsigned on the Java
- // level.
- // TODO: Make sure that actually holds.
- return static_cast<jint>(written_size);
+ return static_cast<jlong>(written_size);
}
static jbyteArray
@@ -615,7 +628,7 @@
{"native_get_object_info", "(I)Landroid/mtp/MtpObjectInfo;",
(void *)android_mtp_MtpDevice_get_object_info},
{"native_get_object", "(II)[B",(void *)android_mtp_MtpDevice_get_object},
- {"native_get_partial_object", "(III[B)I", (void *)android_mtp_MtpDevice_get_partial_object},
+ {"native_get_partial_object", "(IJJ[B)J", (void *)android_mtp_MtpDevice_get_partial_object},
{"native_get_thumbnail", "(I)[B",(void *)android_mtp_MtpDevice_get_thumbnail},
{"native_delete_object", "(I)Z", (void *)android_mtp_MtpDevice_delete_object},
{"native_get_parent", "(I)J", (void *)android_mtp_MtpDevice_get_parent},
diff --git a/packages/DocumentsUI/res/drawable/ic_root_home.xml b/packages/DocumentsUI/res/drawable/ic_root_home.xml
index 0a258ac..696ee05 100644
--- a/packages/DocumentsUI/res/drawable/ic_root_home.xml
+++ b/packages/DocumentsUI/res/drawable/ic_root_home.xml
@@ -1,15 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
+<!--
+Copyright (C) 2015 The Android Open Source Project
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
- android:fillColor="#000000"
- android:pathData="M20 6h-8l-2-2H4c-1.1 0-1.99 .9 -1.99 2L2 18c0 1.1 .9 2 2 2h16c1.1 0 2-.9
-2-2V8c0-1.1-.9-2-2-2zm-5 3c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm4
-8h-8v-1c0-1.33 2.67-2 4-2s4 .67 4 2v1z" />
- <path
- android:pathData="M0 0h24v24H0z" />
+ android:fillColor="#FF000000"
+ android:pathData="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
</vector>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 180a48e..be54496 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -176,6 +176,12 @@
return true;
}
+ @Override
+ protected void onDestroy() {
+ mRoots.setOnCacheUpdateListener(null);
+ super.onDestroy();
+ }
+
State buildDefaultState() {
State state = new State();
@@ -518,7 +524,7 @@
@Override
protected void onPostExecute(DocumentInfo result) {
- if (result != null) {
+ if (result != null && !isDestroyed()) {
openContainerDocument(result);
}
}
@@ -630,7 +636,7 @@
@Override
protected void onPostExecute(RootInfo homeRoot) {
- if (homeRoot != null && mHome != null) {
+ if (homeRoot != null && mHome != null && !isDestroyed()) {
// Clear entire backstack and start in new root
mState.onRootChanged(homeRoot);
mSearchManager.update(homeRoot);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index b03871a..64b443b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -123,39 +123,45 @@
mPendingLockCheck.cancel(false);
}
+ final int userId = KeyguardUpdateMonitor.getCurrentUser();
if (entry.length() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
// to avoid accidental lockout, only count attempts that are long enough to be a
// real password. This may require some tweaking.
setPasswordEntryInputEnabled(true);
- onPasswordChecked(false /* matched */, 0, false /* not valid - too short */);
+ onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */);
return;
}
mPendingLockCheck = LockPatternChecker.checkPassword(
mLockPatternUtils,
entry,
- KeyguardUpdateMonitor.getCurrentUser(),
+ userId,
new LockPatternChecker.OnCheckCallback() {
@Override
public void onChecked(boolean matched, int timeoutMs) {
setPasswordEntryInputEnabled(true);
mPendingLockCheck = null;
- onPasswordChecked(matched, timeoutMs, true /* isValidPassword */);
+ onPasswordChecked(userId, matched, timeoutMs,
+ true /* isValidPassword */);
}
});
}
- private void onPasswordChecked(boolean matched, int timeoutMs, boolean isValidPassword) {
+ private void onPasswordChecked(int userId, boolean matched, int timeoutMs,
+ boolean isValidPassword) {
+ boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
if (matched) {
- mDismissing = true;
- mCallback.reportUnlockAttempt(true, 0);
- mCallback.dismiss(true);
+ mCallback.reportUnlockAttempt(userId, true, 0);
+ if (dismissKeyguard) {
+ mDismissing = true;
+ mCallback.dismiss(true);
+ }
} else {
if (isValidPassword) {
- mCallback.reportUnlockAttempt(false, timeoutMs);
+ mCallback.reportUnlockAttempt(userId, false, timeoutMs);
if (timeoutMs > 0) {
long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
- KeyguardUpdateMonitor.getCurrentUser(), timeoutMs);
+ userId, timeoutMs);
handleAttemptLockout(deadline);
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 29b319f..2a2f5a0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -227,22 +227,23 @@
mPendingLockCheck.cancel(false);
}
+ final int userId = KeyguardUpdateMonitor.getCurrentUser();
if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
mLockPatternView.enableInput();
- onPatternChecked(false, 0, false /* not valid - too short */);
+ onPatternChecked(userId, false, 0, false /* not valid - too short */);
return;
}
mPendingLockCheck = LockPatternChecker.checkPattern(
mLockPatternUtils,
pattern,
- KeyguardUpdateMonitor.getCurrentUser(),
+ userId,
new LockPatternChecker.OnCheckCallback() {
@Override
public void onChecked(boolean matched, int timeoutMs) {
mLockPatternView.enableInput();
mPendingLockCheck = null;
- onPatternChecked(matched, timeoutMs, true);
+ onPatternChecked(userId, matched, timeoutMs, true);
}
});
if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
@@ -250,18 +251,22 @@
}
}
- private void onPatternChecked(boolean matched, int timeoutMs, boolean isValidPattern) {
+ private void onPatternChecked(int userId, boolean matched, int timeoutMs,
+ boolean isValidPattern) {
+ boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
if (matched) {
- mCallback.reportUnlockAttempt(true, 0);
- mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
- mCallback.dismiss(true);
+ mCallback.reportUnlockAttempt(userId, true, 0);
+ if (dismissKeyguard) {
+ mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
+ mCallback.dismiss(true);
+ }
} else {
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
if (isValidPattern) {
- mCallback.reportUnlockAttempt(false, timeoutMs);
+ mCallback.reportUnlockAttempt(userId, false, timeoutMs);
if (timeoutMs > 0) {
long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
- KeyguardUpdateMonitor.getCurrentUser(), timeoutMs);
+ userId, timeoutMs);
handleAttemptLockout(deadline);
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
index 836c195..232d4d2 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
@@ -36,11 +36,12 @@
/**
* Call to report an unlock attempt.
+ * @param userId id of the user whose unlock attempt is recorded.
* @param success set to 'true' if user correctly entered security credentials.
* @param timeoutMs timeout in milliseconds to wait before reattempting an unlock.
* Only nonzero if 'success' is false
*/
- void reportUnlockAttempt(boolean success, int timeoutMs);
+ void reportUnlockAttempt(int userId, boolean success, int timeoutMs);
/**
* Resets the keyguard view.
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index f45b9bd..409f6a7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -205,7 +205,8 @@
if (messageId != 0) {
final String message = mContext.getString(messageId,
- KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(),
+ KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(
+ KeyguardUpdateMonitor.getCurrentUser()),
timeoutInSeconds);
showDialog(null, message);
}
@@ -249,16 +250,15 @@
showDialog(null, message);
}
- private void reportFailedUnlockAttempt(int timeoutMs) {
+ private void reportFailedUnlockAttempt(int userId, int timeoutMs) {
final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
- final int failedAttempts = monitor.getFailedUnlockAttempts() + 1; // +1 for this time
+ final int failedAttempts = monitor.getFailedUnlockAttempts(userId) + 1; // +1 for this time
if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
- final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
final int failedAttemptsBeforeWipe =
- dpm.getMaximumFailedPasswordsForWipe(null, currentUser);
+ dpm.getMaximumFailedPasswordsForWipe(null, userId);
final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
(failedAttemptsBeforeWipe - failedAttempts)
@@ -268,9 +268,9 @@
// N attempts. Once we get below the grace period, we post this dialog every time as a
// clear warning until the deletion fires.
// Check which profile has the strictest policy for failed password attempts
- final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(currentUser);
+ final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
int userType = USER_TYPE_PRIMARY;
- if (expiringUser == currentUser) {
+ if (expiringUser == userId) {
// TODO: http://b/23522538
if (expiringUser != UserHandle.USER_SYSTEM) {
userType = USER_TYPE_SECONDARY_USER;
@@ -286,8 +286,8 @@
showWipeDialog(failedAttempts, userType);
}
}
- monitor.reportFailedStrongAuthUnlockAttempt();
- mLockPatternUtils.reportFailedPasswordAttempt(KeyguardUpdateMonitor.getCurrentUser());
+ monitor.reportFailedStrongAuthUnlockAttempt(userId);
+ mLockPatternUtils.reportFailedPasswordAttempt(userId);
if (timeoutMs > 0) {
showTimeoutDialog(timeoutMs);
}
@@ -422,14 +422,13 @@
return mIsVerifyUnlockOnly;
}
- public void reportUnlockAttempt(boolean success, int timeoutMs) {
+ public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
if (success) {
monitor.clearFailedUnlockAttempts();
- mLockPatternUtils.reportSuccessfulPasswordAttempt(
- KeyguardUpdateMonitor.getCurrentUser());
+ mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
} else {
- KeyguardSecurityContainer.this.reportFailedUnlockAttempt(timeoutMs);
+ KeyguardSecurityContainer.this.reportFailedUnlockAttempt(userId, timeoutMs);
}
}
@@ -445,7 +444,7 @@
@Override
public void userActivity() { }
@Override
- public void reportUnlockAttempt(boolean success, int timeoutMs) { }
+ public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
@Override
public boolean isVerifyUnlockOnly() { return false; }
@Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 8102c34..b4f9b9f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1552,12 +1552,12 @@
mFailedAttempts.delete(sCurrentUser);
}
- public int getFailedUnlockAttempts() {
- return mFailedAttempts.get(sCurrentUser, 0);
+ public int getFailedUnlockAttempts(int userId) {
+ return mFailedAttempts.get(userId, 0);
}
- public void reportFailedStrongAuthUnlockAttempt() {
- mFailedAttempts.put(sCurrentUser, getFailedUnlockAttempts() + 1);
+ public void reportFailedStrongAuthUnlockAttempt(int userId) {
+ mFailedAttempts.put(userId, getFailedUnlockAttempts(userId) + 1);
}
public void clearFingerprintRecognized() {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 9c726ba..0d81a30 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -188,6 +188,15 @@
}
}
+ @VisibleForTesting
+ long getPartialObject(int deviceId, int objectHandle, long offset, long size, byte[] buffer)
+ throws IOException {
+ final MtpDevice device = getDevice(deviceId);
+ synchronized (device) {
+ return device.getPartialObject(objectHandle, offset, size, buffer);
+ }
+ }
+
byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
final MtpDevice device = getDevice(deviceId);
synchronized (device) {
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
index 7527f54..25e9900 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
@@ -21,8 +21,10 @@
import android.hardware.usb.UsbManager;
import android.mtp.MtpConstants;
import android.mtp.MtpEvent;
+import android.mtp.MtpObjectInfo;
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
+import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.test.InstrumentationTestCase;
@@ -98,6 +100,52 @@
}
}
+ public void testCreateDocumentAndGetPartialObject() throws Exception {
+ final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+ final ParcelFileDescriptor.AutoCloseOutputStream stream =
+ new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
+ int storageId = 0;
+ for (final MtpDeviceRecord record : mManager.getDevices()) {
+ if (record.deviceId == mUsbDevice.getDeviceId()) {
+ storageId = record.roots[0].mStorageId;
+ break;
+ }
+ }
+ assertTrue("Valid storage not found.", storageId != 0);
+ final String testFileName = "MtpManagerTest_testFile.txt";
+ for (final int handle : mManager.getObjectHandles(
+ mUsbDevice.getDeviceId(), storageId, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN)) {
+ if (mManager.getObjectInfo(mUsbDevice.getDeviceId(), handle)
+ .getName().equals(testFileName)) {
+ mManager.deleteDocument(mUsbDevice.getDeviceId(), handle);
+ break;
+ }
+ }
+ final byte[] expectedBytes = "Hello Android!".getBytes("ascii");
+ final int objectHandle;
+ try {
+ stream.write(expectedBytes);
+ objectHandle = mManager.createDocument(
+ mUsbDevice.getDeviceId(),
+ new MtpObjectInfo.Builder()
+ .setStorageId(storageId)
+ .setName(testFileName)
+ .setCompressedSize(expectedBytes.length)
+ .setFormat(MtpConstants.FORMAT_TEXT)
+ .build(),
+ fds[0]);
+ } finally {
+ stream.close();
+ }
+ final byte[] bytes = new byte[100];
+ assertEquals(5, mManager.getPartialObject(
+ mUsbDevice.getDeviceId(), objectHandle, 0, 5, bytes));
+ assertEquals("Hello", new String(bytes, 0, 5, "ascii"));
+ assertEquals(8, mManager.getPartialObject(
+ mUsbDevice.getDeviceId(), objectHandle, 6, 100, bytes));
+ assertEquals("Android!", new String(bytes, 0, 8, "ascii"));
+ }
+
private Context getContext() {
return getInstrumentation().getContext();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index f6caaa9..2706e25 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -190,18 +190,27 @@
* Send the intent to trigger the {@link android.settings.ShowAdminSupportDetailsDialog}.
*/
public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
- Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
+ final Intent intent = getShowAdminSupportDetailsIntent(context, admin);
int adminUserId = UserHandle.myUserId();
+ if (admin.userId != UserHandle.USER_NULL) {
+ adminUserId = admin.userId;
+ }
+ context.startActivityAsUser(intent, new UserHandle(adminUserId));
+ }
+
+ public static Intent getShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
+ final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
if (admin != null) {
if (admin.component != null) {
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin.component);
}
+ int adminUserId = UserHandle.myUserId();
if (admin.userId != UserHandle.USER_NULL) {
adminUserId = admin.userId;
}
intent.putExtra(Intent.EXTRA_USER_ID, adminUserId);
}
- context.startActivityAsUser(intent, new UserHandle(adminUserId));
+ return intent;
}
public static void setTextViewPadlock(Context context,
@@ -224,6 +233,34 @@
this.userId = userId;
}
+ @Override
+ public boolean equals(Object object) {
+ if (object == this) return true;
+ if (!(object instanceof EnforcedAdmin)) return false;
+ EnforcedAdmin other = (EnforcedAdmin) object;
+ if (userId != other.userId) {
+ return false;
+ }
+ if ((component == null && other == null) ||
+ (component != null && component.equals(other))) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "EnforcedAdmin{component=" + component + ",userId=" + userId + "}";
+ }
+
+ public void copyTo(EnforcedAdmin other) {
+ if (other == null) {
+ other = new EnforcedAdmin();
+ }
+ other.component = component;
+ other.userId = userId;
+ }
+
public EnforcedAdmin() {}
}
}
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
index 569017a..13a46d0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
@@ -79,6 +79,15 @@
mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
}
+ @Override
+ public void setEnabled(boolean enabled) {
+ if (enabled && isDisabledByAdmin()) {
+ mHelper.setDisabledByAdmin(null);
+ return;
+ }
+ super.setEnabled(enabled);
+ }
+
public void setDisabledByAdmin(EnforcedAdmin admin) {
if (mHelper.setDisabledByAdmin(admin)) {
notifyChanged();
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index f041504..06aba96 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -45,7 +45,7 @@
private EnforcedAdmin mEnforcedAdmin;
private String mAttrUserRestriction = null;
- RestrictedPreferenceHelper(Context context, Preference preference,
+ public RestrictedPreferenceHelper(Context context, Preference preference,
AttributeSet attrs) {
mContext = context;
mPreference = preference;
@@ -54,21 +54,21 @@
mRestrictedPadlockPadding = mContext.getResources().getDimensionPixelSize(
R.dimen.restricted_lock_icon_padding);
- mAttrUserRestriction = attrs.getAttributeValue(
- R.styleable.RestrictedPreference_userRestriction);
- final TypedArray attributes = context.obtainStyledAttributes(attrs,
- R.styleable.RestrictedPreference);
- final TypedValue userRestriction =
- attributes.peekValue(R.styleable.RestrictedPreference_userRestriction);
- CharSequence data = null;
- if (userRestriction != null && userRestriction.type == TypedValue.TYPE_STRING) {
- if (userRestriction.resourceId != 0) {
- data = context.getText(userRestriction.resourceId);
- } else {
- data = userRestriction.string;
+ if (attrs != null) {
+ final TypedArray attributes = context.obtainStyledAttributes(attrs,
+ R.styleable.RestrictedPreference);
+ final TypedValue userRestriction =
+ attributes.peekValue(R.styleable.RestrictedPreference_userRestriction);
+ CharSequence data = null;
+ if (userRestriction != null && userRestriction.type == TypedValue.TYPE_STRING) {
+ if (userRestriction.resourceId != 0) {
+ data = context.getText(userRestriction.resourceId);
+ } else {
+ data = userRestriction.string;
+ }
}
+ mAttrUserRestriction = data == null ? null : data.toString();
}
- mAttrUserRestriction = data == null ? null : data.toString();
}
/**
@@ -100,7 +100,7 @@
/**
* Disable / enable if we have been passed the restriction in the xml.
*/
- protected void onAttachedToHierarchy() {
+ public void onAttachedToHierarchy() {
if (mAttrUserRestriction != null) {
checkRestrictionAndSetDisabled(mAttrUserRestriction, UserHandle.myUserId());
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index 308477b0..84e2bff 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -79,6 +79,15 @@
mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
}
+ @Override
+ public void setEnabled(boolean enabled) {
+ if (enabled && isDisabledByAdmin()) {
+ mHelper.setDisabledByAdmin(null);
+ return;
+ }
+ super.setEnabled(enabled);
+ }
+
public void setDisabledByAdmin(EnforcedAdmin admin) {
if (mHelper.setDisabledByAdmin(admin)) {
notifyChanged();
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index cff8c23..2ee4b12 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -234,10 +234,13 @@
}
public boolean matches(WifiConfiguration config) {
- if (config.isPasspoint() && mConfig != null && mConfig.isPasspoint())
+ if (config.isPasspoint() && mConfig != null && mConfig.isPasspoint()) {
return config.FQDN.equals(mConfig.providerFriendlyName);
- else
- return ssid.equals(removeDoubleQuotes(config.SSID)) && security == getSecurity(config);
+ } else {
+ return ssid.equals(removeDoubleQuotes(config.SSID))
+ && security == getSecurity(config)
+ && (mConfig == null || mConfig.shared == config.shared);
+ }
}
public WifiConfiguration getConfig() {
@@ -394,33 +397,20 @@
summary.append(String.format(format, mConfig.providerFriendlyName));
} else if (mConfig != null && mConfig.hasNoInternetAccess()) {
summary.append(mContext.getString(R.string.wifi_no_internet));
- } else if (mConfig != null && ((mConfig.status == WifiConfiguration.Status.DISABLED &&
- mConfig.disableReason != WifiConfiguration.DISABLED_UNKNOWN_REASON)
- || mConfig.autoJoinStatus
- >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE)) {
- if (mConfig.autoJoinStatus
- >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
- if (mConfig.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE) {
- summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
- } else if (mConfig.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE) {
+ } else if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
+ WifiConfiguration.NetworkSelectionStatus networkStatus =
+ mConfig.getNetworkSelectionStatus();
+ switch (networkStatus.getNetworkSelectionDisableReason()) {
+ case WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE:
summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
- } else {
- summary.append(mContext.getString(R.string.wifi_disabled_wifi_failure));
- }
- } else {
- switch (mConfig.disableReason) {
- case WifiConfiguration.DISABLED_AUTH_FAILURE:
- summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
- break;
- case WifiConfiguration.DISABLED_DHCP_FAILURE:
- case WifiConfiguration.DISABLED_DNS_FAILURE:
- summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
- break;
- case WifiConfiguration.DISABLED_UNKNOWN_REASON:
- case WifiConfiguration.DISABLED_ASSOCIATION_REJECT:
- summary.append(mContext.getString(R.string.wifi_disabled_generic));
- break;
- }
+ break;
+ case WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE:
+ case WifiConfiguration.NetworkSelectionStatus.DISABLED_DNS_FAILURE:
+ summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
+ break;
+ case WifiConfiguration.NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION:
+ summary.append(mContext.getString(R.string.wifi_disabled_generic));
+ break;
}
} else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
summary.append(mContext.getString(R.string.wifi_not_in_range));
@@ -437,11 +427,11 @@
summary.append(" f=" + Integer.toString(mInfo.getFrequency()));
}
summary.append(" " + getVisibilityStatus());
- if (mConfig != null && mConfig.autoJoinStatus > 0) {
- summary.append(" (" + mConfig.autoJoinStatus);
- if (mConfig.blackListTimestamp > 0) {
+ if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
+ summary.append(" (" + mConfig.getNetworkSelectionStatus().getNetworkStatusString());
+ if (mConfig.getNetworkSelectionStatus().getDisableTime() > 0) {
long now = System.currentTimeMillis();
- long diff = (now - mConfig.blackListTimestamp)/1000;
+ long diff = (now - mConfig.getNetworkSelectionStatus().getDisableTime()) / 1000;
long sec = diff%60; //seconds
long min = (diff/60)%60; //minutes
long hour = (min/60)%60; //hours
@@ -452,17 +442,19 @@
}
summary.append(")");
}
- if (mConfig != null && mConfig.numIpConfigFailures > 0) {
- summary.append(" ipf=").append(mConfig.numIpConfigFailures);
- }
- if (mConfig != null && mConfig.numConnectionFailures > 0) {
- summary.append(" cf=").append(mConfig.numConnectionFailures);
- }
- if (mConfig != null && mConfig.numAuthFailures > 0) {
- summary.append(" authf=").append(mConfig.numAuthFailures);
- }
- if (mConfig != null && mConfig.numNoInternetAccessReports > 0) {
- summary.append(" noInt=").append(mConfig.numNoInternetAccessReports);
+
+ if (mConfig != null) {
+ WifiConfiguration.NetworkSelectionStatus networkStatus =
+ mConfig.getNetworkSelectionStatus();
+ for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
+ index < WifiConfiguration.NetworkSelectionStatus
+ .NETWORK_SELECTION_DISABLED_MAX; index++) {
+ if (networkStatus.getDisableReasonCounter(index) != 0) {
+ summary.append(" " + WifiConfiguration.NetworkSelectionStatus
+ .getNetworkDisableReasonString(index) + "="
+ + networkStatus.getDisableReasonCounter(index));
+ }
+ }
}
}
return summary.toString();
@@ -508,10 +500,6 @@
Map<String, ScanResult> list = mScanResultCache.snapshot();
// TODO: sort list by RSSI or age
for (ScanResult result : list.values()) {
- if (result.seen == 0)
- continue;
-
- if (result.autoJoinStatus != ScanResult.ENABLED) numBlackListed++;
if (result.frequency >= LOWER_FREQ_5GHZ
&& result.frequency <= HIGHER_FREQ_5GHZ) {
@@ -525,8 +513,6 @@
num24 = num24 + 1;
}
- // Ignore results seen, older than 20 seconds
- if (now - result.seen > VISIBILITY_OUTDATED_AGE_IN_MILLI) continue;
if (result.frequency >= LOWER_FREQ_5GHZ
&& result.frequency <= HIGHER_FREQ_5GHZ) {
@@ -539,12 +525,6 @@
if (bssid != null && result.BSSID.equals(bssid)) scans5GHz.append("*");
scans5GHz.append("=").append(result.frequency);
scans5GHz.append(",").append(result.level);
- if (result.autoJoinStatus != 0) {
- scans5GHz.append(",st=").append(result.autoJoinStatus);
- }
- if (result.numIpConfigFailures != 0) {
- scans5GHz.append(",ipf=").append(result.numIpConfigFailures);
- }
scans5GHz.append("}");
n5++;
}
@@ -559,12 +539,6 @@
if (bssid != null && result.BSSID.equals(bssid)) scans24GHz.append("*");
scans24GHz.append("=").append(result.frequency);
scans24GHz.append(",").append(result.level);
- if (result.autoJoinStatus != 0) {
- scans24GHz.append(",st=").append(result.autoJoinStatus);
- }
- if (result.numIpConfigFailures != 0) {
- scans24GHz.append(",ipf=").append(result.numIpConfigFailures);
- }
scans24GHz.append("}");
n24++;
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java b/packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java
index f9f1d3f..2317dbc 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java
@@ -48,6 +48,23 @@
*/
private static int STATE_VERSION = 1;
+ /**
+ * write the Network selecton status to Byte Array
+ */
+ private static void writeNetworkSelectionStatus(WifiConfiguration config, DataOutputStream dest)
+ throws IOException {
+ WifiConfiguration.NetworkSelectionStatus status = config.getNetworkSelectionStatus();
+
+ dest.writeInt(status.getNetworkSelectionStatus());
+ dest.writeInt(status.getNetworkSelectionDisableReason());
+ for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
+ index < WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX;
+ index++) {
+ dest.writeInt(status.getDisableReasonCounter(index));
+ }
+ dest.writeLong(status.getDisableTime());
+ writeString(dest, status.getNetworkSelectionBSSID());
+ }
/**
* Marshals a WifiConfig object into a byte-array.
@@ -64,12 +81,11 @@
out.writeInt(STATE_VERSION);
out.writeInt(wifiConfig.networkId);
out.writeInt(wifiConfig.status);
- out.writeInt(wifiConfig.disableReason);
+ writeNetworkSelectionStatus(wifiConfig, out);
writeString(out, wifiConfig.SSID);
writeString(out, wifiConfig.BSSID);
out.writeInt(wifiConfig.apBand);
out.writeInt(wifiConfig.apChannel);
- writeString(out, wifiConfig.autoJoinBSSID);
writeString(out, wifiConfig.FQDN);
writeString(out, wifiConfig.providerFriendlyName);
out.writeInt(wifiConfig.roamingConsortiumIds.length);
@@ -98,7 +114,6 @@
writeString(out, wifiConfig.dhcpServer);
writeString(out, wifiConfig.defaultGwMacAddress);
- out.writeInt(wifiConfig.autoJoinStatus);
out.writeInt(wifiConfig.selfAdded ? 1 : 0);
out.writeInt(wifiConfig.didSelfAdd ? 1 : 0);
out.writeInt(wifiConfig.validatedInternetAccess ? 1 : 0);
@@ -108,14 +123,9 @@
out.writeInt(wifiConfig.lastUpdateUid);
writeString(out, wifiConfig.creatorName);
writeString(out, wifiConfig.lastUpdateName);
- out.writeLong(wifiConfig.blackListTimestamp);
out.writeLong(wifiConfig.lastConnectionFailure);
out.writeLong(wifiConfig.lastRoamingFailure);
out.writeInt(wifiConfig.lastRoamingFailureReason);
- out.writeLong(wifiConfig.roamingFailureBlackListTimeMilli);
- out.writeLong(wifiConfig.numConnectionFailures);
- out.writeLong(wifiConfig.numIpConfigFailures);
- out.writeInt(wifiConfig.numAuthFailures);
out.writeInt(wifiConfig.numScorerOverride);
out.writeInt(wifiConfig.numScorerOverrideAndSwitchedNetwork);
out.writeInt(wifiConfig.numAssociation);
@@ -126,8 +136,6 @@
out.writeInt(wifiConfig.numTicksAtBadRSSI);
out.writeInt(wifiConfig.numTicksAtNotHighRSSI);
out.writeInt(wifiConfig.numUserTriggeredJoinAttempts);
- out.writeInt(wifiConfig.autoJoinUseAggressiveJoinAttemptThreshold);
- out.writeInt(wifiConfig.autoJoinBailedDueToLowRssi ? 1 : 0);
out.writeInt(wifiConfig.userApproved);
out.writeInt(wifiConfig.numNoInternetAccessReports);
out.writeInt(wifiConfig.noInternetAccessExpected ? 1 : 0);
@@ -140,6 +148,23 @@
}
/**
+ *
+ */
+ private static void readNetworkSelectionStatusFromByteArray(DataInputStream in,
+ WifiConfiguration config, int version) throws IOException {
+ WifiConfiguration.NetworkSelectionStatus status = config.getNetworkSelectionStatus();
+ status.setNetworkSelectionStatus(in.readInt());
+ status.setNetworkSelectionDisableReason(in.readInt());
+ for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
+ index < WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX;
+ index++) {
+ status.setDisableReasonCounter(index, in.readInt());
+ }
+ status.setDisableTime(in.readLong());
+ status.setNetworkSelectionBSSID(readString(in, version));
+ }
+
+ /**
* Unmarshals a byte array into a WifiConfig Object
*
* @param data - marshalled WifiConfig Object
@@ -157,12 +182,11 @@
config.networkId = in.readInt();
config.status = in.readInt();
- config.disableReason = in.readInt();
+ readNetworkSelectionStatusFromByteArray(in, config, version);
config.SSID = readString(in, version);
config.BSSID = readString(in, version);
config.apBand = in.readInt();
config.apChannel = in.readInt();
- config.autoJoinBSSID = readString(in, version);
config.FQDN = readString(in, version);
config.providerFriendlyName = readString(in, version);
int numRoamingConsortiumIds = in.readInt();
@@ -195,7 +219,6 @@
config.dhcpServer = readString(in, version);
config.defaultGwMacAddress = readString(in, version);
- config.autoJoinStatus = in.readInt();
config.selfAdded = in.readInt() != 0;
config.didSelfAdd = in.readInt() != 0;
config.validatedInternetAccess = in.readInt() != 0;
@@ -205,14 +228,10 @@
config.lastUpdateUid = in.readInt();
config.creatorName = readString(in, version);
config.lastUpdateName = readString(in, version);
- config.blackListTimestamp = in.readLong();
config.lastConnectionFailure = in.readLong();
config.lastRoamingFailure = in.readLong();
config.lastRoamingFailureReason = in.readInt();
config.roamingFailureBlackListTimeMilli = in.readLong();
- config.numConnectionFailures = in.readInt();
- config.numIpConfigFailures = in.readInt();
- config.numAuthFailures = in.readInt();
config.numScorerOverride = in.readInt();
config.numScorerOverrideAndSwitchedNetwork = in.readInt();
config.numAssociation = in.readInt();
@@ -223,8 +242,6 @@
config.numTicksAtBadRSSI = in.readInt();
config.numTicksAtNotHighRSSI = in.readInt();
config.numUserTriggeredJoinAttempts = in.readInt();
- config.autoJoinUseAggressiveJoinAttemptThreshold = in.readInt();
- config.autoJoinBailedDueToLowRssi = in.readInt() != 0;
config.userApproved = in.readInt();
config.numNoInternetAccessReports = in.readInt();
config.noInternetAccessExpected = in.readInt() != 0;
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 5c807e1..df8fad4 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -65,6 +65,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemProperties;
import android.os.Vibrator;
@@ -108,7 +109,7 @@
* </ol>
*/
public class BugreportProgressService extends Service {
- static final String TAG = "Shell";
+ private static final String TAG = "BugreportProgressService";
private static final boolean DEBUG = false;
private static final String AUTHORITY = "com.android.shell";
@@ -137,6 +138,7 @@
static final String EXTRA_TITLE = "android.intent.extra.TITLE";
static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION";
static final String EXTRA_ORIGINAL_INTENT = "android.intent.extra.ORIGINAL_INTENT";
+ static final String EXTRA_INFO = "android.intent.extra.INFO";
private static final int MSG_SERVICE_COMMAND = 1;
private static final int MSG_POLL = 2;
@@ -325,7 +327,7 @@
takeScreenshot(pid, true);
break;
case INTENT_BUGREPORT_SHARE:
- shareBugreport(pid);
+ shareBugreport(pid, (BugreportInfo) intent.getParcelableExtra(EXTRA_INFO));
break;
case INTENT_BUGREPORT_CANCEL:
cancel(pid);
@@ -483,6 +485,7 @@
if (mProcesses.indexOfKey(pid) < 0) {
Log.w(TAG, "PID not watched: " + pid);
} else {
+ Log.d(TAG, "Removing PID " + pid);
mProcesses.remove(pid);
}
stopSelfWhenDone();
@@ -675,6 +678,11 @@
final int msgId;
if (taken) {
info.addScreenshot(screenshotFile);
+ if (info.finished) {
+ Log.d(TAG, "Screenshot finished after bugreport; updating share notification");
+ info.renameScreenshots(mScreenshotsDir);
+ sendBugreportNotification(mContext, info);
+ }
msgId = R.string.bugreport_screenshot_taken;
} else {
// TODO: try again using Framework APIs instead of relying on screencap.
@@ -814,12 +822,13 @@
* Shares the bugreport upon user's request by issuing a {@link Intent#ACTION_SEND_MULTIPLE}
* intent, but issuing a warning dialog the first time.
*/
- private void shareBugreport(int pid) {
- final BugreportInfo info = getInfo(pid);
+ private void shareBugreport(int pid, BugreportInfo sharedInfo) {
+ BugreportInfo info = getInfo(pid);
if (info == null) {
- // Should not happen, so log if it does...
- Log.e(TAG, "INTERNAL ERROR: no info for PID " + pid + ": " + mProcesses);
- return;
+ // Service was terminated but notification persisted
+ info = sharedInfo;
+ Log.d(TAG, "shareBugreport(): no info for PID " + pid + " on managed processes ("
+ + mProcesses + "), using info from intent instead (" + info + ")");
}
addDetailsToZipFile(info);
@@ -850,6 +859,7 @@
shareIntent.setClass(context, BugreportProgressService.class);
shareIntent.setAction(INTENT_BUGREPORT_SHARE);
shareIntent.putExtra(EXTRA_PID, info.pid);
+ shareIntent.putExtra(EXTRA_INFO, info);
final String title = context.getString(R.string.bugreport_finished_title);
final Notification.Builder builder = new Notification.Builder(context)
@@ -919,6 +929,11 @@
* description will be saved on {@code description.txt}.
*/
private void addDetailsToZipFile(BugreportInfo info) {
+ if (info.bugreportFile == null) {
+ // One possible reason is a bug in the Parcelization code.
+ Log.e(TAG, "INTERNAL ERROR: no bugreportFile on " + info);
+ return;
+ }
// It's not possible to add a new entry into an existing file, so we need to create a new
// zip, copy all entries, then rename it.
final File dir = info.bugreportFile.getParentFile();
@@ -1281,7 +1296,7 @@
/**
* Information about a bugreport process while its in progress.
*/
- private static final class BugreportInfo {
+ private static final class BugreportInfo implements Parcelable {
private final Context context;
/**
@@ -1325,6 +1340,11 @@
long lastUpdate = System.currentTimeMillis();
/**
+ * Time of the last progress update when Parcel was created.
+ */
+ String formattedLastUpdate;
+
+ /**
* Path of the main bugreport file.
*/
File bugreportFile;
@@ -1403,6 +1423,11 @@
}
String getFormattedLastUpdate() {
+ if (context == null) {
+ // Restored from Parcel
+ return formattedLastUpdate == null ?
+ Long.toString(lastUpdate) : formattedLastUpdate;
+ }
return DateUtils.formatDateTime(context, lastUpdate,
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME);
}
@@ -1416,5 +1441,74 @@
+ "\n\tprogress: " + progress + "/" + max + "(" + percent + ")"
+ "\n\tlast_update: " + getFormattedLastUpdate();
}
+
+ // Parcelable contract
+ protected BugreportInfo(Parcel in) {
+ context = null;
+ pid = in.readInt();
+ name = in.readString();
+ title = in.readString();
+ description = in.readString();
+ max = in.readInt();
+ progress = in.readInt();
+ lastUpdate = in.readLong();
+ formattedLastUpdate = in.readString();
+ bugreportFile = readFile(in);
+
+ int screenshotSize = in.readInt();
+ for (int i = 1; i <= screenshotSize; i++) {
+ screenshotFiles.add(readFile(in));
+ }
+
+ finished = in.readInt() == 1;
+ screenshotCounter = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(pid);
+ dest.writeString(name);
+ dest.writeString(title);
+ dest.writeString(description);
+ dest.writeInt(max);
+ dest.writeInt(progress);
+ dest.writeLong(lastUpdate);
+ dest.writeString(getFormattedLastUpdate());
+ writeFile(dest, bugreportFile);
+
+ dest.writeInt(screenshotFiles.size());
+ for (File screenshotFile : screenshotFiles) {
+ writeFile(dest, screenshotFile);
+ }
+
+ dest.writeInt(finished ? 1 : 0);
+ dest.writeInt(screenshotCounter);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ private void writeFile(Parcel dest, File file) {
+ dest.writeString(file == null ? null : file.getPath());
+ }
+
+ private File readFile(Parcel in) {
+ final String path = in.readString();
+ return path == null ? null : new File(path);
+ }
+
+ public static final Parcelable.Creator<BugreportInfo> CREATOR =
+ new Parcelable.Creator<BugreportInfo>() {
+ public BugreportInfo createFromParcel(Parcel source) {
+ return new BugreportInfo(source);
+ }
+
+ public BugreportInfo[] newArray(int size) {
+ return new BugreportInfo[size];
+ }
+ };
+
}
}
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
index c8898b9..9afa900 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -19,7 +19,6 @@
import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
import static com.android.shell.BugreportProgressService.EXTRA_ORIGINAL_INTENT;
import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
-import static com.android.shell.BugreportProgressService.TAG;
import static com.android.shell.BugreportProgressService.getFileExtra;
import java.io.File;
@@ -37,6 +36,7 @@
* {@link Intent#ACTION_SEND_MULTIPLE}.
*/
public class BugreportReceiver extends BroadcastReceiver {
+ private static final String TAG = "BugreportReceiver";
/**
* Always keep the newest 8 bugreport files; 4 reports and 4 screenshots are
@@ -74,7 +74,11 @@
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
- FileUtils.deleteOlderFiles(bugreportFile.getParentFile(), minCount, minAge);
+ try {
+ FileUtils.deleteOlderFiles(bugreportFile.getParentFile(), minCount, minAge);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "RuntimeException deleting old files", e);
+ }
result.finish();
return null;
}
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index d1a07ea..52e1b56 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -65,6 +65,7 @@
import android.util.Log;
import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
+import com.android.shell.BugreportProgressService;
/**
* Integration tests for {@link BugreportReceiver}.
@@ -89,6 +90,9 @@
// Timeout for UI operations, in milliseconds.
private static final int TIMEOUT = (int) BugreportProgressService.POLLING_FREQUENCY * 4;
+ // Timeout for when waiting for a screenshot to finish.
+ private static final int SAFE_SCREENSHOT_DELAY = SCREENSHOT_DELAY_SECONDS + 10;
+
private static final String BUGREPORTS_DIR = "bugreports";
private static final String BUGREPORT_FILE = "test_bugreport.txt";
private static final String ZIP_FILE = "test_bugreport.zip";
@@ -109,6 +113,7 @@
private static final String NO_NAME = null;
private static final String NO_SCREENSHOT = null;
private static final String NO_TITLE = null;
+ private static final Integer NO_PID = null;
private String mDescription;
@@ -122,6 +127,7 @@
@Override
protected void setUp() throws Exception {
+ Log.i(TAG, "#### setup() on " + getName());
Instrumentation instrumentation = getInstrumentation();
mContext = instrumentation.getTargetContext();
mUiBot = new UiBot(UiDevice.getInstance(instrumentation), TIMEOUT);
@@ -164,13 +170,21 @@
Bundle extras =
sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath);
- assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, ZIP_FILE,
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE,
NAME, NO_TITLE, NO_DESCRIPTION, 1, true);
assertServiceNotRunning();
}
public void testProgress_takeExtraScreenshot() throws Exception {
+ takeExtraScreenshotTest(false);
+ }
+
+ public void testProgress_takeExtraScreenshotServiceDiesAfterScreenshotTaken() throws Exception {
+ takeExtraScreenshotTest(true);
+ }
+
+ private void takeExtraScreenshotTest(boolean serviceDies) throws Exception {
resetProperties();
sendBugreportStarted(1000);
@@ -179,14 +193,49 @@
assertScreenshotButtonEnabled(false);
waitForScreenshotButtonEnabled(true);
- Bundle extras =
- sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath);
- assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, ZIP_FILE,
+ sendBugreportFinished(PID, mPlainTextPath, mScreenshotPath);
+
+ if (serviceDies) {
+ waitShareNotification();
+ killService();
+ }
+
+ Bundle extras = acceptBugreportAndGetSharedIntent();
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE,
NAME, NO_TITLE, NO_DESCRIPTION, 2, true);
assertServiceNotRunning();
}
+ public void testScreenshotFinishesAfterBugreport() throws Exception {
+ screenshotFinishesAfterBugreportTest(false);
+ }
+
+ public void testScreenshotFinishesAfterBugreportAndServiceDiesBeforeSharing() throws Exception {
+ screenshotFinishesAfterBugreportTest(true);
+ }
+
+ private void screenshotFinishesAfterBugreportTest(boolean serviceDies) throws Exception {
+ resetProperties();
+
+ sendBugreportStarted(1000);
+ sendBugreportFinished(PID, mPlainTextPath, NO_SCREENSHOT);
+ waitShareNotification();
+
+ // There's no indication in the UI about the screenshot finish, so just sleep like a baby...
+ Thread.sleep(SAFE_SCREENSHOT_DELAY * DateUtils.SECOND_IN_MILLIS);
+
+ if (serviceDies) {
+ killService();
+ }
+
+ Bundle extras = acceptBugreportAndGetSharedIntent();
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, PID, ZIP_FILE,
+ NAME, NO_TITLE, NO_DESCRIPTION, 1, true);
+
+ assertServiceNotRunning();
+ }
+
public void testProgress_changeDetailsInvalidInput() throws Exception {
resetProperties();
@@ -227,7 +276,7 @@
Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath,
mScreenshotPath);
- assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, TITLE,
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
NEW_NAME, TITLE, mDescription, 1, true);
assertServiceNotRunning();
@@ -266,7 +315,7 @@
Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID,
plainText? mPlainTextPath : mZipPath, mScreenshotPath);
- assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, TITLE,
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
NEW_NAME, TITLE, mDescription, 1, true);
assertServiceNotRunning();
@@ -317,8 +366,8 @@
// Finally, share bugreport.
Bundle extras = acceptBugreportAndGetSharedIntent();
- assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, TITLE,
- NAME, TITLE, mDescription, 1, waitScreenshot);
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
+ NAME, TITLE, mDescription, 1, true);
assertServiceNotRunning();
}
@@ -328,7 +377,7 @@
BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_SHOW);
// Send notification and click on share.
- sendBugreportFinished(null, mPlainTextPath, null);
+ sendBugreportFinished(NO_PID, mPlainTextPath, null);
acceptBugreport();
// Handle the warning
@@ -350,6 +399,13 @@
assertEquals("Didn't change state", BugreportPrefs.STATE_HIDE, newState);
}
+ public void testShareBugreportAfterServiceDies() throws Exception {
+ sendBugreportFinished(NO_PID, mPlainTextPath, NO_SCREENSHOT);
+ killService();
+ Bundle extras = acceptBugreportAndGetSharedIntent();
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
+ }
+
public void testBugreportFinished_plainBugreportAndScreenshot() throws Exception {
Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, mScreenshotPath);
assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
@@ -444,6 +500,13 @@
}
/**
+ * Waits for the notification to share the finished bugreport.
+ */
+ private void waitShareNotification() {
+ mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title));
+ }
+
+ /**
* Accepts the notification to share the finished bugreport.
*/
private void acceptBugreport() {
@@ -512,7 +575,8 @@
expectedNumberScreenshots ++; // Add screenshot received by dumpstate
}
int expectedSize = expectedNumberScreenshots + 1; // All screenshots plus the bugreport file
- assertEquals("wrong number of attachments", expectedSize, attachments.size());
+ assertEquals("wrong number of attachments (" + attachments + ")",
+ expectedSize, attachments.size());
// Need to interact through all attachments, since order is not guaranteed.
Uri zipUri = null;
@@ -607,6 +671,15 @@
assertFalse("Service '" + service + "' is still running", isServiceRunning(service));
}
+ private void killService() {
+ waitForService(true);
+ Log.v(TAG, "Stopping service");
+ boolean stopped = mContext.stopService(new Intent(mContext, BugreportProgressService.class));
+ Log.d(TAG, "stopService returned " + stopped);
+ waitForService(false);
+ assertServiceNotRunning(); // Sanity check.
+ }
+
private boolean isServiceRunning(String name) {
ActivityManager manager = (ActivityManager) mContext
.getSystemService(Context.ACTIVITY_SERVICE);
@@ -618,6 +691,33 @@
return false;
}
+ private void waitForService(boolean expectRunning) {
+ String service = BugreportProgressService.class.getName();
+ boolean actualRunning;
+ for (int i = 1; i <= 5; i++) {
+ actualRunning = isServiceRunning(service);
+ Log.d(TAG, "Attempt " + i + " to check status of service '"
+ + service + "': expected=" + expectRunning + ", actual= " + actualRunning);
+ if (actualRunning == expectRunning) {
+ return;
+ }
+ try {
+ Thread.sleep(DateUtils.SECOND_IN_MILLIS);
+ } catch (InterruptedException e) {
+ Log.w(TAG, "thread interrupted");
+ Thread.currentThread().interrupt();
+ }
+ }
+ if (!expectRunning) {
+ // Typically happens when service is waiting for a screenshot to finish.
+ Log.w(TAG, "Service didn't stop; try to kill it again");
+ killService();
+ return;
+ }
+
+ fail("Service status didn't change to " + expectRunning);
+ }
+
private static void createTextFile(String path, String content) throws IOException {
Log.v(TAG, "createFile(" + path + ")");
try (Writer writer = new BufferedWriter(new OutputStreamWriter(
@@ -669,7 +769,7 @@
private UiObject waitForScreenshotButtonEnabled(boolean expectedEnabled) throws Exception {
UiObject screenshotButton = getScreenshotButton();
- int maxAttempts = SCREENSHOT_DELAY_SECONDS + 5;
+ int maxAttempts = SAFE_SCREENSHOT_DELAY;
int i = 0;
do {
boolean enabled = screenshotButton.isEnabled();
diff --git a/packages/SystemUI/res/color/qs_tile_text.xml b/packages/SystemUI/res/color/qs_tile_text.xml
new file mode 100644
index 0000000..90e0bce
--- /dev/null
+++ b/packages/SystemUI/res/color/qs_tile_text.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@color/qs_tile_disabled_color" />
+ <item android:color="#B3FFFFFF" /> <!-- 70% white -->
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/qs_user_detail_name.xml b/packages/SystemUI/res/color/qs_user_detail_name.xml
index 57f7e65..35c7a4f 100644
--- a/packages/SystemUI/res/color/qs_user_detail_name.xml
+++ b/packages/SystemUI/res/color/qs_user_detail_name.xml
@@ -18,5 +18,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true" android:color="@color/current_user_border_color" />
+ <item android:state_enabled="false" android:color="@color/qs_tile_disabled_color" />
<item android:color="#66ffffff" /> <!-- 40% white -->
</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index 071b7c8..03451b4 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -25,15 +25,15 @@
android:gravity="top|start"
android:orientation="vertical"
android:paddingStart="@*android:dimen/notification_content_margin_start"
- android:paddingEnd="@*android:dimen/notification_content_margin_end"
- android:background="@color/notification_guts_text_color" >
+ android:paddingEnd="8dp"
+ android:background="@color/notification_guts_bg_color" >
<!-- header -->
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="8dp"
- android:paddingTop="8dp"
+ android:layout_height="30dp"
+ android:paddingTop="9dp"
+ android:paddingEnd="8dp"
android:id="@+id/notification_guts_header"
android:orientation="horizontal"
android:layout_gravity="center_vertical|start">
@@ -42,25 +42,21 @@
android:id="@android:id/icon"
android:layout_width="18dp"
android:layout_height="18dp"
- android:layout_marginEnd="3dp"
+ android:layout_marginEnd="6dp"
android:src="@android:drawable/arrow_down_float" />
<TextView
- android:id="@+id/pkgname"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="@android:style/TextAppearance.Material.Notification.Info"
- android:layout_marginStart="3dp"
- android:layout_marginEnd="4dp"
- android:textColor="@color/notification_guts_title_color" />
+ android:id="@+id/pkgname"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.NotificationGuts.Header" />
<TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/debug_info"
- android:layout_weight="0"
- android:textAppearance="@android:style/TextAppearance.Material.Notification.Time"
- android:layout_gravity="bottom|start"
- android:visibility="gone"
- android:textColor="#ffffff" />
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/debug_info"
+ android:layout_weight="0"
+ style="@style/TextAppearance.NotificationGuts.Header"
+ android:layout_gravity="bottom|start"
+ android:visibility="gone" />
</LinearLayout>
<!-- Importance slider -->
<LinearLayout
@@ -70,16 +66,17 @@
android:orientation="vertical"
android:clickable="false"
android:focusable="false"
- android:paddingBottom="8dip">
+ android:paddingBottom="8dip"
+ android:paddingEnd="8dp" >
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
- android:textAppearance="@android:style/TextAppearance.Material.Subhead"
- android:textColor="@color/notification_guts_text_color"
+ style="@style/TextAppearance.NotificationGuts.Primary"
android:ellipsize="marquee"
- android:fadingEdge="horizontal"/>
+ android:fadingEdge="horizontal"
+ android:paddingBottom="2dp"/>
<TextView
android:id="@+id/summary"
@@ -87,38 +84,41 @@
android:layout_height="wrap_content"
android:layout_alignStart="@android:id/title"
android:textAlignment="viewStart"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="@color/notification_guts_title_color"
+ style="@style/TextAppearance.NotificationGuts.Secondary"
android:maxLines="3"
- android:minLines="2" />
+ android:minLines="2"
+ android:paddingBottom="4dp" />
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="48dp"
android:paddingTop="8dp" >
<ImageView
android:id="@+id/low_importance"
- android:src="@android:drawable/ic_menu_close_clear_cancel"
+ android:src="@*android:drawable/ic_notification_block"
android:layout_gravity="center_vertical|start"
android:layout_width="24dp"
android:layout_height="24dp" />
<SeekBar
android:id="@+id/seekbar"
- android:layout_marginStart="24dp"
- android:layout_marginEnd="24dp"
+ android:layout_marginStart="56dp"
+ android:layout_marginEnd="56dp"
android:layout_gravity="center_vertical"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="48dp"
android:focusable="true"
android:background="#00ffffff"
- android:thumbTint="@android:color/white"
- android:progressTint="@android:color/white" />
+ android:progressBackgroundTint="@color/notification_guts_secondary_slider_color"
+ android:thumbTint="@color/notification_guts_slider_color"
+ android:progressTint="@color/notification_guts_slider_color"
+ style="@android:style/Widget.Material.SeekBar.Discrete"
+ android:tickMarkTint="@android:color/black" />
<ImageView
android:id="@+id/max_importance"
- android:src="@android:drawable/ic_popup_reminder"
+ android:src="@*android:drawable/ic_notification_alert"
android:layout_gravity="center_vertical|end"
android:layout_width="24dp"
android:layout_height="24dp"/>
@@ -128,19 +128,22 @@
<RadioGroup
android:id="@+id/apply_to"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingTop="8dp">
+ android:layout_height="wrap_content" >
<RadioButton android:id="@+id/apply_to_topic"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/notification_guts_text_color"
- android:visibility="gone"/>
+ android:layout_height="48dp"
+ style="@style/TextAppearance.NotificationGuts.Primary"
+ android:visibility="gone"
+ android:buttonTint="#858383"
+ />
<RadioButton android:id="@+id/apply_to_app"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="48dp"
android:text="@string/apply_to_app"
- android:textColor="@color/notification_guts_text_color"
- android:visibility="gone"/>
+ style="@style/TextAppearance.NotificationGuts.Primary"
+ android:visibility="gone"
+ android:buttonTint="#858383"
+ />
</RadioGroup>
</LinearLayout>
<!-- buttons -->
@@ -148,29 +151,30 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
- android:paddingTop="8dp"
- android:paddingBottom="16dp" >
+ android:paddingBottom="8dp" >
<TextView
android:id="@+id/more_settings"
android:text="@string/notification_more_settings"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="@style/TextAppearance.NotificationGuts"
+ android:layout_height="48dp"
+ style="@style/TextAppearance.NotificationGuts.Button"
android:background="@drawable/btn_borderless_rect"
android:gravity="center"
- android:paddingEnd="24dp"
- android:paddingStart="12dp"
+ android:paddingEnd="8dp"
+ android:paddingStart="8dp"
android:focusable="true" />
<TextView
android:id="@+id/done"
android:text="@string/notification_done"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="@style/TextAppearance.NotificationGuts"
+ android:layout_height="48dp"
+ style="@style/TextAppearance.NotificationGuts.Button"
android:background="@drawable/btn_borderless_rect"
android:gravity="center"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
android:focusable="true"/>
</LinearLayout>
</com.android.systemui.statusbar.NotificationGuts>
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
new file mode 100644
index 0000000..603ebbf
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <TextView android:id="@+id/tile_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/qs_tile_text"
+ android:gravity="center_horizontal"
+ android:minLines="2"
+ android:padding="0dp"
+ android:fontFamily="sans-serif-condensed"
+ android:textStyle="normal"
+ android:textSize="@dimen/qs_tile_text_size"
+ android:clickable="false" />
+ <ImageView android:id="@+id/restricted_padlock"
+ android:layout_width="@dimen/qs_tile_text_size"
+ android:layout_height="@dimen/qs_tile_text_size"
+ android:src="@drawable/ic_settings_lock_outline"
+ android:layout_marginLeft="@dimen/restricted_padlock_pading"
+ android:baselineAlignBottom="true"
+ android:scaleType="centerInside"
+ android:visibility="gone" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index af22f03..a22c360 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -40,12 +40,25 @@
systemui:framePadding="6dp"
systemui:activeFrameColor="@color/current_user_border_color"/>
- <TextView
- android:id="@+id/user_name"
+ <LinearLayout
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="@dimen/qs_detail_item_secondary_text_size"
- android:textColor="@color/qs_user_detail_name"
- android:gravity="center_horizontal" />
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/user_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/qs_detail_item_secondary_text_size"
+ android:textColor="@color/qs_user_detail_name"
+ android:gravity="center_horizontal" />
+ <ImageView
+ android:id="@+id/restricted_padlock"
+ android:layout_width="@dimen/qs_detail_item_secondary_text_size"
+ android:layout_height="@dimen/qs_detail_item_secondary_text_size"
+ android:src="@drawable/ic_settings_lock_outline"
+ android:layout_marginLeft="@dimen/restricted_padlock_pading"
+ android:baselineAlignBottom="true"
+ android:scaleType="centerInside"
+ android:visibility="gone" />
+ </LinearLayout>
</com.android.systemui.qs.tiles.UserDetailItemView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 905da13..a80a5de 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -36,7 +36,6 @@
<color name="system_warning_color">#fff4511e</color><!-- deep orange 600 -->
<color name="qs_text">#FFFFFFFF</color>
<color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
- <color name="qs_tile_text">#B3FFFFFF</color><!-- 70% white -->
<color name="qs_subhead">#99FFFFFF</color><!-- 60% white -->
<color name="qs_detail_empty">#24B0BEC5</color><!-- 14% blue grey 200 -->
<color name="qs_detail_button">#FFB0BEC5</color><!-- 100% blue grey 200 -->
@@ -48,6 +47,7 @@
<color name="data_usage_graph_warning">#FFFFFFFF</color>
<color name="status_bar_clock_color">#FFFFFFFF</color>
<color name="qs_user_detail_icon_muted">#FFFFFFFF</color> <!-- not so muted after all -->
+ <color name="qs_tile_disabled_color">#9E9E9E</color> <!-- 38% black -->
<!-- Tint color for the content on the notification overflow card. -->
<color name="keyguard_overflow_content_color">#ff686868</color>
@@ -100,10 +100,9 @@
<color name="current_user_border_color">@color/system_accent_color</color>
<!-- The "inside" of a notification, reached via longpress -->
- <color name="notification_guts_bg_color">@*android:color/material_deep_teal_500</color>
- <color name="notification_guts_title_color">#B2DFDB</color>
- <color name="notification_guts_text_color">#FFFFFFFF</color>
- <color name="notification_guts_btn_color">#FFFFFFFF</color>
+ <color name="notification_guts_bg_color">@*android:color/material_grey_50</color>
+ <color name="notification_guts_slider_color">@*android:color/material_deep_teal_500</color>
+ <color name="notification_guts_secondary_slider_color">#858383</color>
<color name="assist_orb_color">#ffffff</color>
@@ -147,4 +146,8 @@
<color name="default_remote_input_background">@*android:color/notification_default_color</color>
<color name="remote_input_hint">#4dffffff</color>
+
+ <color name="qs_tile_tint_unavailable">#40ffffff</color>
+ <color name="qs_tile_tint_inactive">#4dffffff</color>
+ <color name="qs_tile_tint_active">#ffffffff</color>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 097c352..1a9b874 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -167,6 +167,8 @@
<dimen name="segmented_button_spacing">0dp</dimen>
<dimen name="borderless_button_radius">2dp</dimen>
+ <dimen name="restricted_padlock_pading">4dp</dimen>
+
<!-- How far the expanded QS panel peeks from the header in collapsed state. -->
<dimen name="qs_peek_height">0dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4136c11..0e4f98f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1281,4 +1281,13 @@
<!-- Summary of switch for battery saver [CHAR LIMIT=NONE] -->
<string name="battery_detail_switch_summary">Reduces performance and background data</string>
+ <!-- User visible title for the system-wide keyboard shortcuts list. -->
+ <string name="keyboard_shortcut_group_system">System</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the home screen. -->
+ <string name="keyboard_shortcut_group_system_home">Home</string>
+ <!-- User visible title for the the keyboard shortcut that takes the user to the recents screen. -->
+ <string name="keyboard_shortcut_group_system_recents">Recents</string>
+ <!-- User visible title for the the keyboard shortcut that triggers the back action. -->
+ <string name="keyboard_shortcut_group_system_back">Back</string>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 527b638..4329f78 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -319,10 +319,30 @@
<style name="TextAppearance.NotificationGuts">
<item name="android:textSize">14sp</item>
- <item name="android:textColor">@color/notification_guts_btn_color</item>
+ <item name="android:fontFamily">sans-serif-medium</item>
+ <item name="android:textColor">@android:color/black</item>
+ </style>
+
+ <style name="TextAppearance.NotificationGuts.Header">
+ <item name="android:alpha">.38</item>
+ <item name="android:textSize">12sp</item>
+ </style>
+
+ <style name="TextAppearance.NotificationGuts.Secondary">
+ <item name="android:alpha">.54</item>
+ </style>
+
+ <style name="TextAppearance.NotificationGuts.Primary">
+ <item name="android:alpha">.87</item>
+ <item name="android:textSize">16sp</item>
+ </style>
+
+ <style name="TextAppearance.NotificationGuts.Button">
+ <item name="android:textSize">14sp</item>
<item name="android:textAllCaps">true</item>
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:gravity">center</item>
+ <item name="android:textColor">@*android:color/material_deep_teal_500</item>
</style>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
index 01eb5f9..7651ae8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
@@ -81,7 +81,11 @@
}
}
}
-
+ if (state.disabledByPolicy) {
+ iv.setColorFilter(getContext().getColor(R.color.qs_tile_disabled_color));
+ } else {
+ iv.clearColorFilter();
+ }
}
protected int getIconMeasureMode() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 2d9d105..de7c02d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -23,10 +23,13 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
+
+import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.qs.QSTile.State;
import com.android.systemui.qs.external.TileServices;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -47,6 +50,8 @@
import java.util.Collection;
import java.util.Objects;
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
/**
* Base quick-settings tile, extend this to create a new tile.
*
@@ -256,6 +261,18 @@
mCallbacks.clear();
}
+ protected void checkIfRestrictionEnforced(State state, String userRestriction) {
+ EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
+ userRestriction, UserHandle.myUserId());
+ if (admin != null) {
+ state.disabledByPolicy = true;
+ state.enforcedAdmin = admin;
+ } else {
+ state.disabledByPolicy = false;
+ state.enforcedAdmin = null;
+ }
+ }
+
protected final class H extends Handler {
private static final int ADD_CALLBACK = 1;
private static final int CLICK = 2;
@@ -282,8 +299,14 @@
handleAddCallback((QSTile.Callback)msg.obj);
} else if (msg.what == CLICK) {
name = "handleClick";
- mAnnounceNextStateChange = true;
- handleClick();
+ if (mState.disabledByPolicy) {
+ Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
+ mContext, mState.enforcedAdmin);
+ mHost.startActivityDismissingKeyguard(intent);
+ } else {
+ mAnnounceNextStateChange = true;
+ handleClick();
+ }
} else if (msg.what == SECONDARY_CLICK) {
name = "handleSecondaryClick";
handleSecondaryClick();
@@ -437,6 +460,8 @@
public CharSequence contentDescription;
public CharSequence dualLabelContentDescription;
public boolean autoMirrorDrawable = true;
+ public boolean disabledByPolicy;
+ public EnforcedAdmin enforcedAdmin;
public boolean copyTo(State other) {
if (other == null) throw new IllegalArgumentException();
@@ -446,12 +471,16 @@
|| !Objects.equals(other.contentDescription, contentDescription)
|| !Objects.equals(other.autoMirrorDrawable, autoMirrorDrawable)
|| !Objects.equals(other.dualLabelContentDescription,
- dualLabelContentDescription);
+ dualLabelContentDescription)
+ || !Objects.equals(other.disabledByPolicy, disabledByPolicy)
+ || !Objects.equals(other.enforcedAdmin, enforcedAdmin);
other.icon = icon;
other.label = label;
other.contentDescription = contentDescription;
other.dualLabelContentDescription = dualLabelContentDescription;
other.autoMirrorDrawable = autoMirrorDrawable;
+ other.disabledByPolicy = disabledByPolicy;
+ enforcedAdmin.copyTo(other.enforcedAdmin);
return changed;
}
@@ -467,6 +496,8 @@
sb.append(",contentDescription=").append(contentDescription);
sb.append(",dualLabelContentDescription=").append(dualLabelContentDescription);
sb.append(",autoMirrorDrawable=").append(autoMirrorDrawable);
+ sb.append(",disabledByPolicy=").append(disabledByPolicy);
+ sb.append(",enforcedAdmin=").append(enforcedAdmin);
return sb.append(']');
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 41ac4d9..664ca39 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -19,32 +19,33 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Typeface;
import android.util.MathUtils;
-import android.util.TypedValue;
import android.view.Gravity;
+import android.view.LayoutInflater;
import android.view.View;
+import android.widget.ImageView;
import android.widget.TextView;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
/** View that represents a standard quick settings tile. **/
public class QSTileView extends QSTileBaseView {
- private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed",
- Typeface.NORMAL);
-
protected final Context mContext;
+ private QSIconView mIconView;
private final int mTileSpacingPx;
private int mTilePaddingTopPx;
private TextView mLabel;
+ private ImageView mPadLock;
public QSTileView(Context context, QSIconView icon) {
super(context, icon);
mContext = context;
+ mIconView = icon;
final Resources res = context.getResources();
mTileSpacingPx = res.getDimensionPixelSize(R.dimen.qs_tile_spacing);
+
setClipChildren(false);
setClickable(true);
@@ -76,16 +77,10 @@
private void createLabel() {
final Resources res = mContext.getResources();
- mLabel = new TextView(mContext);
- mLabel.setTextColor(mContext.getColor(R.color.qs_tile_text));
- mLabel.setGravity(Gravity.CENTER_HORIZONTAL);
- mLabel.setMinLines(2);
- mLabel.setPadding(0, 0, 0, 0);
- mLabel.setTypeface(CONDENSED);
- mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
- res.getDimensionPixelSize(R.dimen.qs_tile_text_size));
- mLabel.setClickable(false);
- addView(mLabel);
+ View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
+ mLabel = (TextView) view.findViewById(R.id.tile_label);
+ mPadLock = (ImageView) view.findViewById(R.id.restricted_padlock);
+ addView(view);
}
public void init(OnClickListener clickPrimary, OnLongClickListener longClick) {
@@ -96,5 +91,7 @@
protected void handleStateChanged(QSTile.State state) {
super.handleStateChanged(state);
mLabel.setText(state.label);
+ mLabel.setEnabled(!state.disabledByPolicy);
+ mPadLock.setVisibility(state.disabledByPolicy ? View.VISIBLE : View.GONE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java
index 95ff611..ac4f05f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java
@@ -19,8 +19,9 @@
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
-
+import android.graphics.drawable.Drawable;
import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
public class BlankCustomTile extends QSTile<QSTile.State> {
@@ -72,7 +73,9 @@
try {
PackageManager pm = mContext.getPackageManager();
ServiceInfo info = pm.getServiceInfo(mComponent, 0);
- state.icon = new DrawableIcon(info.loadIcon(pm));
+ Drawable drawable = info.loadIcon(pm);
+ drawable.setTint(mContext.getColor(R.color.qs_tile_tint_active));
+ state.icon = new DrawableIcon(drawable);
state.label = info.loadLabel(pm).toString();
state.contentDescription = state.label;
} catch (Exception e) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index eefff30..d398b64 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -25,11 +25,14 @@
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
+import android.text.SpannableStringBuilder;
+import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.IWindowManager;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.phone.QSTileHost;
@@ -88,6 +91,7 @@
mTile.setIcon(tile.getIcon());
mTile.setLabel(tile.getLabel());
mTile.setContentDescription(tile.getContentDescription());
+ mTile.setState(tile.getState());
}
public void onDialogShown() {
@@ -147,6 +151,9 @@
@Override
protected void handleClick() {
+ if (mTile.getState() == Tile.STATE_UNAVAILABLE) {
+ return;
+ }
try {
if (DEBUG) Log.d(TAG, "Adding token");
mWindowManager.addWindowToken(mToken, WindowManager.LayoutParams.TYPE_QS_DIALOG);
@@ -172,9 +179,15 @@
@Override
protected void handleUpdateState(State state, Object arg) {
Drawable drawable = mTile.getIcon().loadDrawable(mContext);
- drawable.setTint(mContext.getColor(android.R.color.white));
+ int color = mContext.getColor(getColor(mTile.getState()));
+ drawable.setTint(color);
state.icon = new DrawableIcon(drawable);
state.label = mTile.getLabel();
+ if (mTile.getState() == Tile.STATE_UNAVAILABLE) {
+ state.label = new SpannableStringBuilder().append(state.label,
+ new ForegroundColorSpan(color),
+ SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
+ }
if (mTile.getContentDescription() != null) {
state.contentDescription = mTile.getContentDescription();
} else {
@@ -187,6 +200,30 @@
return MetricsLogger.QS_CUSTOM;
}
+ public void startUnlockAndRun() {
+ mHost.startRunnableDismissingKeyguard(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mService.onUnlockComplete();
+ } catch (RemoteException e) {
+ }
+ }
+ });
+ }
+
+ private static int getColor(int state) {
+ switch (state) {
+ case Tile.STATE_UNAVAILABLE:
+ return R.color.qs_tile_tint_unavailable;
+ case Tile.STATE_INACTIVE:
+ return R.color.qs_tile_tint_inactive;
+ case Tile.STATE_ACTIVE:
+ return R.color.qs_tile_tint_active;
+ }
+ return 0;
+ }
+
public static ComponentName getComponentFromSpec(String spec) {
final String action = spec.substring(PREFIX.length(), spec.length() - 1);
if (action.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
index d41cdde..3830ac5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
@@ -104,4 +104,14 @@
return false;
}
}
+
+ public boolean onUnlockComplete() {
+ try {
+ mService.onUnlockComplete();
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 8c5e87e..4977d80 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -55,6 +55,7 @@
private static final int MSG_ON_ADDED = 0;
private static final int MSG_ON_REMOVED = 1;
private static final int MSG_ON_CLICK = 2;
+ private static final int MSG_ON_UNLOCK_COMPLETE = 3;
// Bind retry control.
private static final int MAX_BIND_RETRIES = 5;
@@ -174,6 +175,15 @@
onClick(mClickBinder);
}
}
+ if (queue.contains(MSG_ON_UNLOCK_COMPLETE)) {
+ if (DEBUG) Log.d(TAG, "Handling pending onUnlockComplete");
+ if (!mListening) {
+ Log.w(TAG, "Managed to get unlock on non-listening state...");
+ // Skipping unlock since lost click privileges.
+ } else {
+ onUnlockComplete();
+ }
+ }
if (queue.contains(MSG_ON_REMOVED)) {
if (DEBUG) Log.d(TAG, "Handling pending onRemoved");
if (mListening) {
@@ -348,6 +358,15 @@
}
@Override
+ public void onUnlockComplete() {
+ if (DEBUG) Log.d(TAG, "onUnlockComplete");
+ if (mWrapper == null || !mWrapper.onUnlockComplete()) {
+ queueMessage(MSG_ON_UNLOCK_COMPLETE);
+ handleDeath();
+ }
+ }
+
+ @Override
public IBinder asBinder() {
return mWrapper != null ? mWrapper.asBinder() : null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index a831c87..44d8776 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -36,6 +36,7 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
import java.util.ArrayList;
import java.util.Collections;
@@ -199,6 +200,16 @@
}
@Override
+ public void onStartActivity(Tile tile) {
+ ComponentName componentName = tile.getComponentName();
+ verifyCaller(componentName.getPackageName());
+ CustomTile customTile = getTileForComponent(componentName);
+ if (customTile != null) {
+ mHost.collapsePanels();
+ }
+ }
+
+ @Override
public void updateStatusIcon(Tile tile, Icon icon, String contentDescription) {
final ComponentName componentName = tile.getComponentName();
String packageName = componentName.getPackageName();
@@ -228,6 +239,28 @@
}
}
+ @Override
+ public void startUnlockAndRun(Tile tile) {
+ ComponentName componentName = tile.getComponentName();
+ verifyCaller(componentName.getPackageName());
+ CustomTile customTile = getTileForComponent(componentName);
+ if (customTile != null) {
+ customTile.startUnlockAndRun();
+ }
+ }
+
+ @Override
+ public boolean isLocked() {
+ KeyguardMonitor keyguardMonitor = mHost.getKeyguardMonitor();
+ return keyguardMonitor.isShowing();
+ }
+
+ @Override
+ public boolean isSecure() {
+ KeyguardMonitor keyguardMonitor = mHost.getKeyguardMonitor();
+ return keyguardMonitor.isSecure() && keyguardMonitor.isShowing();
+ }
+
private CustomTile getTileForComponent(ComponentName component) {
synchronized (mServices) {
return mTiles.get(component);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 4d9b266..39eda6b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -22,6 +22,7 @@
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.view.LayoutInflater;
@@ -99,14 +100,6 @@
@Override
public void handleClick() {
- if (mController.isVolumeRestricted()) {
- // Collapse the panels, so the user can see the toast.
- mHost.collapsePanels();
- SysUIToast.makeText(mContext, mContext.getString(
- com.android.internal.R.string.error_message_change_not_allowed),
- Toast.LENGTH_LONG).show();
- return;
- }
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
if (mState.value) {
mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
@@ -123,6 +116,8 @@
final boolean newValue = zen != Global.ZEN_MODE_OFF;
final boolean valueChanged = state.value != newValue;
state.value = newValue;
+ state.disabledByPolicy = mController.isVolumeRestricted();
+ checkIfRestrictionEnforced(state, UserManager.DISALLOW_ADJUST_VOLUME);
switch (zen) {
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index 21c5c96..167c611 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -43,6 +43,7 @@
private TextView mName;
private Typeface mRegularTypeface;
private Typeface mActivatedTypeface;
+ private View mRestrictedPadlock;
public UserDetailItemView(Context context) {
this(context, null);
@@ -59,6 +60,7 @@
public UserDetailItemView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.UserDetailItemView, defStyleAttr, defStyleRes);
final int N = a.getIndexCount();
@@ -95,6 +97,12 @@
mAvatar.setDrawable(picture);
}
+ public void setDisabledByAdmin(boolean disabled) {
+ mRestrictedPadlock.setVisibility(disabled ? View.VISIBLE : View.GONE);
+ mName.setEnabled(!disabled);
+ mAvatar.setDisabled(disabled);
+ }
+
@Override
protected void onFinishInflate() {
mAvatar = (UserAvatarView) findViewById(R.id.user_picture);
@@ -106,6 +114,7 @@
mActivatedTypeface = mName.getTypeface();
}
updateTypeface();
+ mRestrictedPadlock = findViewById(R.id.restricted_padlock);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index d4f54b6..b44ef0b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -16,17 +16,18 @@
package com.android.systemui.qs.tiles;
-import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.R;
-import com.android.systemui.qs.PseudoGridView;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-
import android.content.Context;
+import android.content.Intent;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.logging.MetricsLogger;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.systemui.R;
+import com.android.systemui.qs.PseudoGridView;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
/**
* Quick settings detail view for user switching.
*/
@@ -55,11 +56,13 @@
public static class Adapter extends UserSwitcherController.BaseUserAdapter
implements OnClickListener {
- private Context mContext;
+ private final Context mContext;
+ private final UserSwitcherController mController;
public Adapter(Context context, UserSwitcherController controller) {
super(controller);
mContext = context;
+ mController = controller;
}
@Override
@@ -77,6 +80,7 @@
v.bind(name, item.picture);
}
v.setActivated(item.isCurrent);
+ v.setDisabledByAdmin(item.isDisabledByAdmin);
v.setTag(item);
return v;
}
@@ -85,8 +89,14 @@
public void onClick(View view) {
UserSwitcherController.UserRecord tag =
(UserSwitcherController.UserRecord) view.getTag();
- MetricsLogger.action(mContext, MetricsLogger.QS_SWITCH_USER);
- switchTo(tag);
+ if (tag.isDisabledByAdmin) {
+ final Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
+ mContext, tag.enforcedAdmin);
+ mController.startActivity(intent);
+ } else {
+ MetricsLogger.action(mContext, MetricsLogger.QS_SWITCH_USER);
+ switchTo(tag);
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index ddeb8dc..60a2ee5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -110,9 +110,7 @@
/** Preloads the next task */
public void run() {
- // TODO: Temporarily skip this if multi stack is enabled
- /*
- RecentsConfiguration config = RecentsConfiguration.getInstance();
+ RecentsConfiguration config = Recents.getConfiguration();
if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
RecentsTaskLoader loader = Recents.getTaskLoader();
SystemServicesProxy ssp = Recents.getSystemServices();
@@ -134,7 +132,6 @@
launchOpts.onlyLoadPausedActivities = true;
loader.loadTasks(mContext, plan, launchOpts);
}
- */
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 3406da9..f9e825a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -60,6 +60,7 @@
import android.view.Display;
import android.view.IDockedStackListener;
import android.view.WindowManager;
+import android.view.WindowManager.KeyboardShortcutsReceiver;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
import com.android.internal.app.AssistUtils;
@@ -915,4 +916,8 @@
e.printStackTrace();
}
}
+
+ public void requestKeyboardShortcuts(Context context, KeyboardShortcutsReceiver receiver) {
+ mWm.requestAppKeyboardShortcuts(receiver);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 3e0ea90..b36fb7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -20,50 +20,92 @@
import android.app.Dialog;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
-import android.view.Gravity;
+import android.os.Handler;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
+import android.view.KeyboardShortcutInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
+import android.view.WindowManager.KeyboardShortcutsReceiver;
import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+
+import java.util.List;
+
+import static android.content.Context.LAYOUT_INFLATER_SERVICE;
+import static android.graphics.Color.TRANSPARENT;
+import static android.view.Gravity.TOP;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
/**
* Contains functionality for handling keyboard shortcuts.
*/
public class KeyboardShortcuts {
+ private static final String TAG = "KeyboardShortcuts";
+
private Dialog mKeyboardShortcutsDialog;
public KeyboardShortcuts() {}
- public void toggleKeyboardShortcuts(Context context) {
+ public void toggleKeyboardShortcuts(final Context context) {
if (mKeyboardShortcutsDialog == null) {
- // Create dialog.
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
- LayoutInflater inflater = (LayoutInflater) context.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- final View keyboardShortcutsView = inflater.inflate(
- R.layout.keyboard_shortcuts_view, null);
-
- populateKeyboardShortcuts(keyboardShortcutsView.findViewById(
- R.id.keyboard_shortcuts_wrapper));
- dialogBuilder.setView(keyboardShortcutsView);
- mKeyboardShortcutsDialog = dialogBuilder.create();
- mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true);
-
- // Setup window.
- Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow();
- keyboardShortcutsWindow.setType(
- WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
- keyboardShortcutsWindow.setBackgroundDrawable(
- new ColorDrawable(android.graphics.Color.TRANSPARENT));
- keyboardShortcutsWindow.setGravity(Gravity.TOP);
- mKeyboardShortcutsDialog.show();
+ Recents.getSystemServices().requestKeyboardShortcuts(context,
+ new KeyboardShortcutsReceiver() {
+ @Override
+ public void onKeyboardShortcutsReceived(
+ final List<KeyboardShortcutGroup> result) {
+ KeyboardShortcutGroup systemGroup = new KeyboardShortcutGroup(
+ context.getString(R.string.keyboard_shortcut_group_system));
+ systemGroup.addItem(new KeyboardShortcutInfo(
+ context.getString(R.string.keyboard_shortcut_group_system_home),
+ '\u2386', KeyEvent.META_META_ON));
+ systemGroup.addItem(new KeyboardShortcutInfo(
+ context.getString(R.string.keyboard_shortcut_group_system_back),
+ '\u007F', KeyEvent.META_META_ON));
+ systemGroup.addItem(new KeyboardShortcutInfo(
+ context.getString(R.string.keyboard_shortcut_group_system_recents),
+ '\u0009', KeyEvent.META_ALT_ON));
+ result.add(systemGroup);
+ Log.i(TAG, "Keyboard shortcuts received: " + String.valueOf(result));
+ showKeyboardShortcutsDialog(context);
+ }
+ });
} else {
dismissKeyboardShortcutsDialog();
}
}
+ private void showKeyboardShortcutsDialog(Context context) {
+ // Create dialog.
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
+ LayoutInflater inflater = (LayoutInflater) context.getSystemService(
+ LAYOUT_INFLATER_SERVICE);
+ final View keyboardShortcutsView = inflater.inflate(
+ R.layout.keyboard_shortcuts_view, null);
+
+ populateKeyboardShortcuts(keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_wrapper));
+ dialogBuilder.setView(keyboardShortcutsView);
+ mKeyboardShortcutsDialog = dialogBuilder.create();
+ mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true);
+
+ // Setup window.
+ Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow();
+ keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
+ keyboardShortcutsWindow.setBackgroundDrawable(
+ new ColorDrawable(TRANSPARENT));
+ keyboardShortcutsWindow.setGravity(TOP);
+ keyboardShortcutsView.post(new Runnable() {
+ public void run() {
+ mKeyboardShortcutsDialog.show();
+ }
+ });
+ }
+
public void dismissKeyboardShortcutsDialog() {
if (mKeyboardShortcutsDialog != null) {
mKeyboardShortcutsDialog.dismiss();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 50e88d3..5be52ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -866,7 +866,7 @@
mKeyguardMonitor = new KeyguardMonitor(mContext);
if (UserManager.get(mContext).isUserSwitcherEnabled()) {
mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
- mHandler);
+ mHandler, this);
if (mUserSwitcherController.useFullscreenUserSwitcher()) {
mFullscreenUserSwitcher = new FullscreenUserSwitcher(this, mUserSwitcherController,
(ViewStub) mStatusBarWindow.findViewById(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
index 101a5f3..4f33d82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
@@ -23,6 +23,9 @@
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;
@@ -41,6 +44,7 @@
private float mFramePadding;
private Bitmap mBitmap;
private Drawable mDrawable;
+ private boolean mIsDisabled;
private final Paint mFramePaint = new Paint();
private final Paint mBitmapPaint = new Paint();
@@ -239,4 +243,28 @@
mDrawable.setState(getDrawableState());
}
}
+
+ public void setDisabled(boolean disabled) {
+ if (mIsDisabled == disabled) {
+ return;
+ }
+ mIsDisabled = disabled;
+ int disabledColor = getContext().getColor(R.color.qs_tile_disabled_color);
+ PorterDuffColorFilter filter = new PorterDuffColorFilter(disabledColor,
+ PorterDuff.Mode.SRC_ATOP);
+ if (mBitmap != null) {
+ if (disabled) {
+ mBitmapPaint.setColorFilter(filter);
+ } else {
+ mBitmapPaint.setColorFilter(null);
+ }
+ } else if (mDrawable != null) {
+ if (disabled) {
+ mDrawable.setColorFilter(filter);
+ } else {
+ mDrawable.setColorFilter(null);
+ }
+ }
+ invalidate();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index b65bf43..ad8e3bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -440,6 +440,7 @@
+ " dataState=" + state.getDataRegState());
}
mServiceState = state;
+ mDataNetType = state.getDataNetworkType();
updateTelephony();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index f3a3554..ffec615 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -22,7 +22,9 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -33,6 +35,7 @@
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
+import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -48,11 +51,13 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.UserIcons;
+import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.BitmapHelper;
import com.android.systemui.GuestResumeSessionReceiver;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.tiles.UserDetailView;
+import com.android.systemui.statusbar.phone.ActivityStarter;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import java.io.FileDescriptor;
@@ -61,6 +66,8 @@
import java.util.ArrayList;
import java.util.List;
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
/**
* Keeps a list of all users on the device for user switching.
*/
@@ -88,6 +95,7 @@
= new GuestResumeSessionReceiver();
private final KeyguardMonitor mKeyguardMonitor;
private final Handler mHandler;
+ private final ActivityStarter mActivityStarter;
private ArrayList<UserRecord> mUsers = new ArrayList<>();
private Dialog mExitGuestDialog;
@@ -99,11 +107,12 @@
private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor,
- Handler handler) {
+ Handler handler, ActivityStarter activityStarter) {
mContext = context;
mGuestResumeSessionReceiver.register(context);
mKeyguardMonitor = keyguardMonitor;
mHandler = handler;
+ mActivityStarter = activityStarter;
mUserManager = UserManager.get(context);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_ADDED);
@@ -206,25 +215,23 @@
}
}
- boolean systemCanCreateUsers = !mUserManager.hasUserRestriction(
- UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM);
boolean currentUserCanCreateUsers = currentUserInfo != null
&& (currentUserInfo.isAdmin()
- || currentUserInfo.id == UserHandle.USER_SYSTEM)
- && systemCanCreateUsers;
- boolean anyoneCanCreateUsers = systemCanCreateUsers && addUsersWhenLocked;
- boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
+ || currentUserInfo.id == UserHandle.USER_SYSTEM);
+ boolean canCreateGuest = (currentUserCanCreateUsers || addUsersWhenLocked)
&& guestRecord == null;
- boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
+ boolean canCreateUser = (currentUserCanCreateUsers || addUsersWhenLocked)
&& mUserManager.canAddMoreUsers();
boolean createIsRestricted = !addUsersWhenLocked;
if (!mSimpleUserSwitcher) {
if (guestRecord == null) {
if (canCreateGuest) {
- records.add(new UserRecord(null /* info */, null /* picture */,
+ guestRecord = new UserRecord(null /* info */, null /* picture */,
true /* isGuest */, false /* isCurrent */,
- false /* isAddUser */, createIsRestricted));
+ false /* isAddUser */, createIsRestricted);
+ checkIfAddUserDisallowed(guestRecord);
+ records.add(guestRecord);
}
} else {
int index = guestRecord.isCurrent ? 0 : records.size();
@@ -233,9 +240,11 @@
}
if (!mSimpleUserSwitcher && canCreateUser) {
- records.add(new UserRecord(null /* info */, null /* picture */,
+ UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
- createIsRestricted));
+ createIsRestricted);
+ checkIfAddUserDisallowed(addUserRecord);
+ records.add(addUserRecord);
}
return records;
@@ -594,6 +603,22 @@
}
}
+ private void checkIfAddUserDisallowed(UserRecord record) {
+ EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
+ UserManager.DISALLOW_ADD_USER, UserHandle.myUserId());
+ if (admin != null) {
+ record.isDisabledByAdmin = true;
+ record.enforcedAdmin = admin;
+ } else {
+ record.isDisabledByAdmin = false;
+ record.enforcedAdmin = null;
+ }
+ }
+
+ public void startActivity(Intent intent) {
+ mActivityStarter.startActivity(intent, true);
+ }
+
public static final class UserRecord {
public final UserInfo info;
public final Bitmap picture;
@@ -602,6 +627,8 @@
public final boolean isAddUser;
/** If true, the record is only visible to the owner and only when unlocked. */
public final boolean isRestricted;
+ public boolean isDisabledByAdmin;
+ public EnforcedAdmin enforcedAdmin;
public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
boolean isAddUser, boolean isRestricted) {
@@ -634,6 +661,10 @@
if (isCurrent) sb.append(" <isCurrent>");
if (picture != null) sb.append(" <hasPicture>");
if (isRestricted) sb.append(" <isRestricted>");
+ if (isDisabledByAdmin) {
+ sb.append(" <isDisabledByAdmin>");
+ sb.append(" enforcedAdmin=" + enforcedAdmin);
+ }
sb.append(')');
return sb.toString();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
index 6ebf488..f86c6a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
@@ -283,6 +283,11 @@
public void onClick(IBinder iBinder) throws RemoteException {
sendCallback("onClick");
}
+
+ @Override
+ public void onUnlockComplete() throws RemoteException {
+ sendCallback("onUnlockComplete");
+ }
};
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 13fc47d..b64fbea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -60,8 +60,8 @@
protected NetworkControllerImpl mNetworkController;
protected MobileSignalController mMobileSignalController;
protected PhoneStateListener mPhoneStateListener;
- private SignalStrength mSignalStrength;
- private ServiceState mServiceState;
+ protected SignalStrength mSignalStrength;
+ protected ServiceState mServiceState;
protected ConnectivityManager mMockCm;
protected WifiManager mMockWm;
protected SubscriptionManager mMockSm;
@@ -235,7 +235,7 @@
mPhoneStateListener.onSignalStrengthsChanged(mSignalStrength);
}
- private void updateServiceState() {
+ protected void updateServiceState() {
Log.d(TAG, "Sending Service State: " + mServiceState);
mPhoneStateListener.onServiceStateChanged(mServiceState);
}
@@ -246,6 +246,7 @@
}
public void updateDataConnectionState(int dataState, int dataNetType) {
+ when(mServiceState.getDataNetworkType()).thenReturn(dataNetType);
mPhoneStateListener.onDataConnectionStateChanged(dataState, dataNetType);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 587e2b5..e4f858b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -115,6 +115,21 @@
TelephonyIcons.QS_DATA_4G);
}
+ public void testDataChangeWithoutConnectionState() {
+ setupDefaultSignal();
+ updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ verifyDataIndicators(TelephonyIcons.DATA_LTE[1][0 /* No direction */],
+ TelephonyIcons.QS_DATA_LTE);
+
+ Mockito.when(mServiceState.getDataNetworkType())
+ .thenReturn(TelephonyManager.NETWORK_TYPE_HSPA);
+ updateServiceState();
+ verifyDataIndicators(TelephonyIcons.DATA_H[1][0 /* No direction */],
+ TelephonyIcons.QS_DATA_H);
+ }
+
public void testDataActivity() {
setupDefaultSignal();
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 39d5952..28aeef7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -715,7 +715,7 @@
}
@Override
- public IBinder getWindowToken(int windowId) {
+ public IBinder getWindowToken(int windowId, int userId) {
mSecurityPolicy.enforceCallingPermission(
Manifest.permission.RETRIEVE_WINDOW_TOKEN,
GET_WINDOW_TOKEN);
@@ -724,8 +724,7 @@
// share the accessibility state of the parent. The call below
// performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.getCallingUserId());
+ .resolveCallingUserIdEnforcingPermissionsLocked(userId);
if (resolvedUserId != mCurrentUserId) {
return null;
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 2264c69..aa15373 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -239,6 +239,11 @@
// How long between attempts to perform a full-data backup of any given app
static final long MIN_FULL_BACKUP_INTERVAL = 1000 * 60 * 60 * 24; // one day
+ // If an app is busy when we want to do a full-data backup, how long to defer the retry.
+ // This is fuzzed, so there are two parameters; backoff_min + Rand[0, backoff_fuzz)
+ static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60; // one hour
+ static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2; // two hours
+
Context mContext;
private PackageManager mPackageManager;
IPackageManager mPackageManagerBinder;
@@ -4496,35 +4501,72 @@
return false;
}
- // At this point we know that we have work to do, just not right now. Any
- // exit without actually running backups will also require that we
+ // At this point we know that we have work to do, but possibly not right now.
+ // Any exit without actually running backups will also require that we
// reschedule the job.
boolean runBackup = true;
+ boolean headBusy;
- if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Preconditions not met; not running full backup");
- }
- runBackup = false;
- // Typically this means we haven't run a key/value backup yet. Back off
- // full-backup operations by the key/value job's run interval so that
- // next time we run, we are likely to be able to make progress.
- latency = KeyValueBackupJob.BATCH_INTERVAL;
- }
+ do {
+ headBusy = false;
- if (runBackup) {
- entry = mFullBackupQueue.get(0);
- long timeSinceRun = now - entry.lastBackup;
- runBackup = (timeSinceRun >= MIN_FULL_BACKUP_INTERVAL);
- if (!runBackup) {
- // It's too early to back up the next thing in the queue, so bow out
+ if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
if (MORE_DEBUG) {
- Slog.i(TAG, "Device ready but too early to back up next app");
+ Slog.i(TAG, "Preconditions not met; not running full backup");
}
- // Wait until the next app in the queue falls due for a full data backup
- latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun;
+ runBackup = false;
+ // Typically this means we haven't run a key/value backup yet. Back off
+ // full-backup operations by the key/value job's run interval so that
+ // next time we run, we are likely to be able to make progress.
+ latency = KeyValueBackupJob.BATCH_INTERVAL;
}
- }
+
+ if (runBackup) {
+ entry = mFullBackupQueue.get(0);
+ long timeSinceRun = now - entry.lastBackup;
+ runBackup = (timeSinceRun >= MIN_FULL_BACKUP_INTERVAL);
+ if (!runBackup) {
+ // It's too early to back up the next thing in the queue, so bow out
+ if (MORE_DEBUG) {
+ Slog.i(TAG, "Device ready but too early to back up next app");
+ }
+ // Wait until the next app in the queue falls due for a full data backup
+ latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun;
+ break; // we know we aren't doing work yet, so bail.
+ }
+
+ try {
+ PackageInfo appInfo = mPackageManager.getPackageInfo(entry.packageName, 0);
+ headBusy = mActivityManager.isAppForeground(appInfo.applicationInfo.uid);
+
+ if (headBusy) {
+ final long nextEligible = System.currentTimeMillis()
+ + BUSY_BACKOFF_MIN_MILLIS
+ + mTokenGenerator.nextInt(BUSY_BACKOFF_FUZZ);
+ if (DEBUG_SCHEDULING) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ Slog.i(TAG, "Full backup time but " + entry.packageName
+ + " is busy; deferring to "
+ + sdf.format(new Date(nextEligible)));
+ }
+ // This relocates the app's entry from the head of the queue to
+ // its order-appropriate position further down, so upon looping
+ // a new candidate will be considered at the head.
+ enqueueFullBackup(entry.packageName,
+ nextEligible - MIN_FULL_BACKUP_INTERVAL);
+ }
+
+ } catch (NameNotFoundException nnf) {
+ // So, we think we want to back this up, but it turns out the package
+ // in question is no longer installed. We want to drop it from the
+ // queue entirely and move on, but if there's nothing else in the queue
+ // we should bail entirely. headBusy cannot have been set to true yet.
+ runBackup = (mFullBackupQueue.size() > 1);
+ } catch (RemoteException e) {
+ // Cannot happen; the Activity Manager is in the same process
+ }
+ }
+ } while (headBusy);
if (!runBackup) {
if (DEBUG_SCHEDULING) {
@@ -4539,7 +4581,7 @@
return false;
}
- // Okay, the top thing is runnable now. Pop it off and get going.
+ // Okay, the top thing is ready for backup now. Do it.
mFullBackupQueue.remove(0);
CountDownLatch latch = new CountDownLatch(1);
String[] pkg = new String[] {entry.packageName};
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 37a6c02..2de5324 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1568,12 +1568,11 @@
// load the global proxy at startup
mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
- // Try bringing up tracker, but if KeyStore isn't ready yet, wait
- // for user to unlock device.
- if (!updateLockdownVpn()) {
- final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_PRESENT);
- mContext.registerReceiver(mUserPresentReceiver, filter);
- }
+ // Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
+ // for user to unlock device too.
+ updateLockdownVpn();
+ final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_PRESENT);
+ mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.ALL, filter, null, null);
// Configure whether mobile data is always on.
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON));
@@ -1586,10 +1585,16 @@
private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ // User that sent this intent = user that was just unlocked
+ final int unlockedUser = getSendingUserId();
+
// Try creating lockdown tracker, since user present usually means
// unlocked keystore.
- if (updateLockdownVpn()) {
- mContext.unregisterReceiver(this);
+ if (mUserManager.getUserInfo(unlockedUser).isPrimary() &&
+ LockdownVpnTracker.isEnabled()) {
+ updateLockdownVpn();
+ } else {
+ updateAlwaysOnVpn(unlockedUser);
}
}
};
@@ -3258,6 +3263,76 @@
}
}
+ /**
+ * Sets up or tears down the always-on VPN for user {@param user} as appropriate.
+ *
+ * @return {@code false} in case of errors; {@code true} otherwise.
+ */
+ private boolean updateAlwaysOnVpn(int user) {
+ final String lockdownPackage = getAlwaysOnVpnPackage(user);
+ if (lockdownPackage == null) {
+ return true;
+ }
+
+ // Create an intent to start the VPN service declared in the app's manifest.
+ Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
+ serviceIntent.setPackage(lockdownPackage);
+
+ try {
+ return mContext.startServiceAsUser(serviceIntent, UserHandle.of(user)) != null;
+ } catch (RuntimeException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean setAlwaysOnVpnPackage(int userId, String packageName) {
+ enforceConnectivityInternalPermission();
+ enforceCrossUserPermission(userId);
+
+ // Can't set always-on VPN if legacy VPN is already in lockdown mode.
+ if (LockdownVpnTracker.isEnabled()) {
+ return false;
+ }
+
+ // If the current VPN package is the same as the new one, this is a no-op
+ final String oldPackage = getAlwaysOnVpnPackage(userId);
+ if (TextUtils.equals(oldPackage, packageName)) {
+ return true;
+ }
+
+ synchronized (mVpns) {
+ Vpn vpn = mVpns.get(userId);
+ if (vpn == null) {
+ Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+ return false;
+ }
+ if (!vpn.setAlwaysOnPackage(packageName)) {
+ return false;
+ }
+ if (!updateAlwaysOnVpn(userId)) {
+ vpn.setAlwaysOnPackage(null);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String getAlwaysOnVpnPackage(int userId) {
+ enforceConnectivityInternalPermission();
+ enforceCrossUserPermission(userId);
+
+ synchronized (mVpns) {
+ Vpn vpn = mVpns.get(userId);
+ if (vpn == null) {
+ Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+ return null;
+ }
+ return vpn.getAlwaysOnPackage();
+ }
+ }
+
@Override
public int checkMobileProvisioning(int suggestedTimeOutMs) {
// TODO: Remove? Any reason to trigger a provisioning check?
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 11f9e2d..f345d7e 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2312,6 +2312,14 @@
}
final int uid = Binder.getCallingUid();
+ // Only allow system to start session
+ if (!isSystemUid(uid)) {
+ String msg = String.format(
+ "uid %s cannot stat add account session.",
+ uid);
+ throw new SecurityException(msg);
+ }
+
final int userId = UserHandle.getUserId(uid);
if (!canUserModifyAccounts(userId, uid)) {
try {
@@ -2499,6 +2507,14 @@
}
final int uid = Binder.getCallingUid();
+ // Only allow system to finish session
+ if (!isSystemUid(uid)) {
+ String msg = String.format(
+ "uid %s cannot finish session.",
+ uid);
+ throw new SecurityException(msg);
+ }
+
final int userId = UserHandle.getUserId(uid);
if (!canUserModifyAccounts(userId, uid)) {
sendErrorResponse(response,
@@ -2717,6 +2733,16 @@
if (account == null) {
throw new IllegalArgumentException("account is null");
}
+
+ final int uid = Binder.getCallingUid();
+ // Only allow system to start session
+ if (!isSystemUid(uid)) {
+ String msg = String.format(
+ "uid %s cannot start update credentials session.",
+ uid);
+ throw new SecurityException(msg);
+ }
+
int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d12eadb..7ba6338 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -61,6 +61,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -326,7 +327,7 @@
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
- callingPid, callingUid, userId, true, callerFg);
+ callingPid, callingUid, userId, true, callerFg, false);
if (res == null) {
return null;
}
@@ -549,7 +550,7 @@
// If this service is active, make sure it is stopped.
ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, null,
- Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false);
+ Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false);
if (r != null) {
if (r.record != null) {
final long origId = Binder.clearCallingIdentity();
@@ -598,7 +599,7 @@
IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) {
ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(),
- UserHandle.getCallingUserId(), false, false);
+ UserHandle.getCallingUserId(), false, false, false);
IBinder ret = null;
if (r != null) {
@@ -831,10 +832,11 @@
}
final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
ServiceLookupResult res =
- retrieveServiceLocked(service, resolvedType, callingPackage,
- Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
+ retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
if (res == null) {
return 0;
}
@@ -1192,7 +1194,7 @@
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
- boolean createIfNeeded, boolean callingFromFg) {
+ boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
ServiceRecord r = null;
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
+ " type=" + resolvedType + " callingUid=" + callingUid);
@@ -1205,10 +1207,16 @@
if (comp != null) {
r = smap.mServicesByName.get(comp);
}
- if (r == null) {
+ if (r == null && !isBindExternal) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
r = smap.mServicesByIntent.get(filter);
}
+ if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
+ && !callingPackage.equals(r.packageName)) {
+ // If an external service is running within its own package, other packages
+ // should not bind to that instance.
+ r = null;
+ }
if (r == null) {
try {
// TODO: come back and remove this assumption to triage all services
@@ -1225,6 +1233,37 @@
}
ComponentName name = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
+ if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) {
+ if (isBindExternal) {
+ if (!sInfo.exported) {
+ throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
+ " is not exported");
+ }
+ if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {
+ throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
+ " is not an isolatedProcess");
+ }
+ // Run the service under the calling package's application.
+ ApplicationInfo aInfo = AppGlobals.getPackageManager().getApplicationInfo(
+ callingPackage, ActivityManagerService.STOCK_PM_FLAGS, userId);
+ if (aInfo == null) {
+ throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " +
+ "could not resolve client package " + callingPackage);
+ }
+ sInfo = new ServiceInfo(sInfo);
+ sInfo.applicationInfo = new ApplicationInfo(sInfo.applicationInfo);
+ sInfo.applicationInfo.packageName = aInfo.packageName;
+ sInfo.applicationInfo.uid = aInfo.uid;
+ name = new ComponentName(aInfo.packageName, name.getClassName());
+ service.setComponent(name);
+ } else {
+ throw new SecurityException("BIND_EXTERNAL_SERVICE required for " +
+ name);
+ }
+ } else if (isBindExternal) {
+ throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
+ " is not an externalService");
+ }
if (userId > 0) {
if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
sInfo.name, sInfo.flags)
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 093a33d..ca38b71 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18,7 +18,6 @@
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
-
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.AssistUtils;
@@ -240,6 +239,7 @@
import java.util.concurrent.atomic.AtomicLong;
import dalvik.system.VMRuntime;
+
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
@@ -7256,6 +7256,17 @@
}
@Override
+ public boolean isAppForeground(int uid) throws RemoteException {
+ synchronized (this) {
+ UidRecord uidRec = mActiveUids.get(uid);
+ if (uidRec == null || uidRec.idle) {
+ return false;
+ }
+ return uidRec.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+ }
+ }
+
+ @Override
public boolean inMultiWindowMode(IBinder token) {
final long origId = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 312e309..8e68aec 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1179,8 +1179,12 @@
prev.cpuTimeAtResume = 0; // reset it
}
- // Notfiy when the task stack has changed
- mService.notifyTaskStackChangedLocked();
+ // Notify when the task stack has changed, but only if visibilities changed (not just
+ // focus).
+ if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause) {
+ mService.notifyTaskStackChangedLocked();
+ mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
+ }
}
private void addToStopping(ActivityRecord r) {
@@ -1257,6 +1261,7 @@
ActivityContainer container = containers.get(containerNdx);
container.setVisible(visible);
}
+ mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
}
// Find the first visible activity above the passed activity and if it is translucent return it
@@ -1385,9 +1390,10 @@
final int focusedStackId = focusedStack.mStackId;
if (mStackId == FULLSCREEN_WORKSPACE_STACK_ID
- && hasVisibleBehindActivity() && focusedStackId == HOME_STACK_ID) {
+ && hasVisibleBehindActivity() && focusedStackId == HOME_STACK_ID
+ && !focusedStack.topActivity().fullscreen) {
// The fullscreen stack should be visible if it has a visible behind activity behind
- // the home stack that will be translucent.
+ // the home stack that is translucent.
return true;
}
@@ -1507,8 +1513,7 @@
aboveTop = false;
// mLaunchingBehind: Activities launching behind are at the back of the task stack
// but must be drawn initially for the animation as though they were visible.
- if ((!behindFullscreenActivity || r.mLaunchTaskBehind)
- && okToShowLocked(r)) {
+ if ((!behindFullscreenActivity || r.mLaunchTaskBehind) && okToShowLocked(r)) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Make visible? " + r + " finishing=" + r.finishing
+ " state=" + r.state);
@@ -1607,7 +1612,7 @@
}
// Now for any activities that aren't visible to the user, make sure they no longer are
// keeping the screen frozen.
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.state);
try {
setVisible(r, false);
switch (r.state) {
@@ -3713,9 +3718,9 @@
void releaseBackgroundResources(ActivityRecord r) {
if (hasVisibleBehindActivity() &&
!mHandler.hasMessages(RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG)) {
- if (r == topRunningActivityLocked()) {
+ if (r == topRunningActivityLocked() && isStackVisibleLocked()) {
// Don't release the top activity if it has requested to run behind the next
- // activity.
+ // activity and the stack is currently visible.
return;
}
if (DEBUG_STATES) Slog.d(TAG_STATES, "releaseBackgroundResources activtyDisplay=" +
@@ -4753,8 +4758,7 @@
}
void addConfigOverride(ActivityRecord r, TaskRecord task) {
- final Rect bounds = task.getLaunchBounds();
- task.updateOverrideConfiguration(bounds);
+ final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
@@ -4810,10 +4814,9 @@
}
private void setAppTask(ActivityRecord r, TaskRecord task) {
- final Rect bounds = task.getLaunchBounds();
- task.updateOverrideConfiguration(bounds);
+ final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
mWindowManager.setAppTask(
- r.appToken, task.taskId, mStackId, task.getLaunchBounds(), task.mOverrideConfig);
+ r.appToken, task.taskId, mStackId, bounds, task.mOverrideConfig);
mWindowManager.setTaskResizeable(task.taskId, task.mResizeable);
r.taskConfigOverride = task.mOverrideConfig;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c634e0e..e837d9a 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -399,6 +399,12 @@
private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
/**
+ * Used to keep track whether app visibilities got changed since the last pause. Useful to
+ * determine whether to invoke the task stack change listener after pausing.
+ */
+ boolean mAppVisibilitiesChangedSinceLastPause;
+
+ /**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
*/
@@ -1673,7 +1679,7 @@
if (task.mResizeable && options != null) {
int stackId = options.getLaunchStackId();
if (canUseActivityOptionsLaunchBounds(options, stackId)) {
- Rect bounds = options.getLaunchBounds();
+ final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds());
task.updateOverrideConfiguration(bounds);
if (stackId == INVALID_STACK_ID) {
stackId = task.getLaunchStackId();
@@ -1841,6 +1847,7 @@
// can have the right fullscreen state.
bounds = null;
}
+ bounds = TaskRecord.validateBounds(bounds);
mTmpBounds.clear();
mTmpConfigs.clear();
@@ -1857,8 +1864,8 @@
fitWithinBounds(tempRect2, bounds);
task.updateOverrideConfiguration(tempRect2);
} else {
- task.updateOverrideConfiguration(tempTaskBounds != null
- ? tempTaskBounds : bounds);
+ task.updateOverrideConfiguration(
+ tempTaskBounds != null ? tempTaskBounds : bounds);
}
}
@@ -1973,6 +1980,7 @@
// Nothing to do here...
return true;
}
+ bounds = TaskRecord.validateBounds(bounds);
if (!mWindowManager.isValidTaskId(task.taskId)) {
// Task doesn't exist in window manager yet (e.g. was restored from recents).
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index cfa4433..6fa8950 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1739,7 +1739,7 @@
if (options != null && (r.isResizeable() || (inTask != null && inTask.mResizeable))) {
if (mSupervisor.canUseActivityOptionsLaunchBounds(
options, options.getLaunchStackId())) {
- newBounds = options.getLaunchBounds();
+ newBounds = TaskRecord.validateBounds(options.getLaunchBounds());
}
}
return newBounds;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index ae987e6..f7e30c0 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
@@ -1310,6 +1311,20 @@
return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
}
+ Rect updateOverrideConfigurationFromLaunchBounds() {
+ final Rect bounds = validateBounds(getLaunchBounds());
+ updateOverrideConfiguration(bounds);
+ return bounds;
+ }
+
+ static Rect validateBounds(Rect bounds) {
+ if (bounds != null && bounds.isEmpty()) {
+ Slog.wtf(TAG, "Received strange task bounds: " + bounds, new Throwable());
+ return null;
+ }
+ return bounds;
+ }
+
private void reportMultiWindowModeChange() {
for (int i = mActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = mActivities.get(i);
@@ -1386,17 +1401,20 @@
/** Returns the bounds that should be used to launch this task. */
Rect getLaunchBounds() {
- final int stackId = stack.mStackId;
-
// If we're over lockscreen, forget about stack bounds and use fullscreen.
if (mService.mLockScreenShown == LOCK_SCREEN_SHOWN) {
return null;
}
- if (stack == null
- || stackId == HOME_STACK_ID
- || stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
- return (mResizeable && stack != null) ? stack.mBounds : null;
+ if (stack == null) {
+ return null;
+ }
+
+ final int stackId = stack.mStackId;
+ if (stackId == HOME_STACK_ID
+ || stackId == FULLSCREEN_WORKSPACE_STACK_ID
+ || (stackId == DOCKED_STACK_ID && !mResizeable)) {
+ return mResizeable ? stack.mBounds : null;
} else if (!StackId.persistTaskBounds(stackId)) {
return stack.mBounds;
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 5bd4f98..e957fc6 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -63,6 +63,7 @@
import android.os.SystemService;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyStore;
import android.text.TextUtils;
@@ -169,6 +170,58 @@
}
/**
+ * Configures an always-on VPN connection through a specific application.
+ * This connection is automatically granted and persisted after a reboot.
+ *
+ * <p>The designated package should exist and declare a {@link VpnService} in its
+ * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
+ * otherwise the call will fail.
+ *
+ * @param newPackage the package to designate as always-on VPN supplier.
+ */
+ public synchronized boolean setAlwaysOnPackage(String packageName) {
+ enforceControlPermissionOrInternalCaller();
+
+ // Disconnect current VPN.
+ prepareInternal(VpnConfig.LEGACY_VPN);
+
+ // Pre-authorize new always-on VPN package.
+ if (packageName != null) {
+ if (!setPackageAuthorization(packageName, true)) {
+ return false;
+ }
+ }
+
+ // Save the new package name in Settings.Secure.
+ final long token = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.ALWAYS_ON_VPN_APP, packageName, mUserHandle);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return true;
+ }
+
+ /**
+ * @return the package name of the VPN controller responsible for always-on VPN,
+ * or {@code null} if none is set or always-on VPN is controlled through
+ * lockdown instead.
+ * @hide
+ */
+ public synchronized String getAlwaysOnPackage() {
+ enforceControlPermissionOrInternalCaller();
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
* Prepare for a VPN application. This method is designed to solve
* race conditions. It first compares the current prepared package
* with {@code oldPackage}. If they are the same, the prepared
@@ -270,14 +323,14 @@
/**
* Set whether a package has the ability to launch VPNs without user intervention.
*/
- public void setPackageAuthorization(String packageName, boolean authorized) {
+ public boolean setPackageAuthorization(String packageName, boolean authorized) {
// Check if the caller is authorized.
- enforceControlPermission();
+ enforceControlPermissionOrInternalCaller();
int uid = getAppUid(packageName, mUserHandle);
if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) {
// Authorization for nonexistent packages (or fake ones) can't be updated.
- return;
+ return false;
}
long token = Binder.clearCallingIdentity();
@@ -286,11 +339,13 @@
(AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, uid, packageName,
authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
+ return true;
} catch (Exception e) {
Log.wtf(TAG, "Failed to set app ops for package " + packageName + ", uid " + uid, e);
} finally {
Binder.restoreCallingIdentity(token);
}
+ return false;
}
private boolean isVpnUserPreConsented(String packageName) {
@@ -743,6 +798,13 @@
mContext.enforceCallingPermission(Manifest.permission.CONTROL_VPN, "Unauthorized Caller");
}
+ private void enforceControlPermissionOrInternalCaller() {
+ // Require caller to be either an application with CONTROL_VPN permission or a process
+ // in the system server.
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONTROL_VPN,
+ "Unauthorized Caller");
+ }
+
private class Connection implements ServiceConnection {
private IBinder mService;
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 78618ce..2eb9095 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -2682,6 +2682,31 @@
}
continue;
}
+ String packageName = getPackageName(op.target);
+ ApplicationInfo ai = null;
+ if (packageName != null) {
+ try {
+ ai = mContext.getPackageManager().getApplicationInfo(packageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES
+ | PackageManager.GET_DISABLED_COMPONENTS);
+ } catch (NameNotFoundException e) {
+ operationIterator.remove();
+ mSyncStorageEngine.deleteFromPending(op.pendingOperation);
+ continue;
+ }
+ }
+ // If app is considered idle, then skip for now and backoff
+ if (ai != null
+ && mAppIdleMonitor.isAppIdle(packageName, ai.uid, op.target.userId)) {
+ increaseBackoffSetting(op);
+ op.appIdle = true;
+ if (isLoggable) {
+ Log.v(TAG, "Sync backing off idle app " + packageName);
+ }
+ continue;
+ } else {
+ op.appIdle = false;
+ }
if (!isOperationValidLocked(op)) {
operationIterator.remove();
mSyncStorageEngine.deleteFromPending(op.pendingOperation);
@@ -2700,28 +2725,6 @@
}
continue;
}
- String packageName = getPackageName(op.target);
- ApplicationInfo ai = null;
- if (packageName != null) {
- try {
- ai = mContext.getPackageManager().getApplicationInfo(packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES
- | PackageManager.GET_DISABLED_COMPONENTS);
- } catch (NameNotFoundException e) {
- }
- }
- // If app is considered idle, then skip for now and backoff
- if (ai != null
- && mAppIdleMonitor.isAppIdle(packageName, ai.uid, op.target.userId)) {
- increaseBackoffSetting(op);
- op.appIdle = true;
- if (isLoggable) {
- Log.v(TAG, "Sync backing off idle app " + packageName);
- }
- continue;
- } else {
- op.appIdle = false;
- }
// Add this sync to be run.
operations.add(op);
}
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 835ba17..a16fcd2 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -587,16 +587,16 @@
Slog.e(TAG, "Unable to create surface.", ex);
return false;
}
+
+ mSurfaceControl.setLayerStack(mDisplayLayerStack);
+ mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
+ mSurface = new Surface();
+ mSurface.copyFrom(mSurfaceControl);
+
+ mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
+ mDisplayId, mSurfaceControl);
+ mSurfaceLayout.onDisplayTransaction();
}
-
- mSurfaceControl.setLayerStack(mDisplayLayerStack);
- mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
- mSurface = new Surface();
- mSurface.copyFrom(mSurfaceControl);
-
- mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
- mDisplayId, mSurfaceControl);
- mSurfaceLayout.onDisplayTransaction();
} finally {
SurfaceControl.closeTransaction();
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 433d887..b74b0f2 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -673,6 +673,9 @@
slowChange = false;
}
mAppliedDimming = true;
+ } else if (mAppliedDimming) {
+ slowChange = false;
+ mAppliedDimming = false;
}
// If low power mode is enabled, cut the brightness level by half
@@ -685,6 +688,9 @@
slowChange = false;
}
mAppliedLowPower = true;
+ } else if (mAppliedLowPower) {
+ slowChange = false;
+ mAppliedLowPower = false;
}
// Animate the screen brightness when the screen is on or dozing.
diff --git a/services/core/java/com/android/server/media/MediaResourceMonitorService.java b/services/core/java/com/android/server/media/MediaResourceMonitorService.java
new file mode 100644
index 0000000..50dd607
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaResourceMonitorService.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2016 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.media;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.content.Intent;
+import android.media.IMediaResourceMonitor;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+import com.android.server.SystemService;
+
+import java.util.List;
+
+/** This class provides a system service that monitors media resource usage. */
+public class MediaResourceMonitorService extends SystemService {
+ private static final String TAG = "MediaResourceMonitor";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static final String SERVICE_NAME = "media_resource_monitor";
+
+ /*
+ * Resource types. Should be in sync with:
+ * frameworks/av/media/libmedia/MediaResource.cpp
+ */
+ private static final String RESOURCE_AUDIO_CODEC = "audio-codec";
+ private static final String RESOURCE_VIDEO_CODEC = "video-codec";
+
+ private final MediaResourceMonitorImpl mMediaResourceMonitorImpl;
+
+ public MediaResourceMonitorService(Context context) {
+ super(context);
+ mMediaResourceMonitorImpl = new MediaResourceMonitorImpl();
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(SERVICE_NAME, mMediaResourceMonitorImpl);
+ }
+
+ class MediaResourceMonitorImpl extends IMediaResourceMonitor.Stub {
+ @Override
+ public void notifyResourceGranted(int pid, String type, String subType, long value)
+ throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "notifyResourceGranted(pid=" + pid + ", type=" + type + ", subType="
+ + subType + ", value=" + value + ")");
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ String pkgNames[] = getPackageNamesFromPid(pid);
+ Integer resourceType = null;
+ if (RESOURCE_AUDIO_CODEC.equals(subType)) {
+ resourceType = Intent.EXTRA_MEDIA_RESOURCE_TYPE_AUDIO_CODEC;
+ } else if (RESOURCE_VIDEO_CODEC.equals(subType)) {
+ resourceType = Intent.EXTRA_MEDIA_RESOURCE_TYPE_VIDEO_CODEC;
+ }
+ if (pkgNames != null && resourceType != null) {
+ Intent intent = new Intent(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
+ intent.putExtra(Intent.EXTRA_PACKAGES, pkgNames);
+ intent.putExtra(Intent.EXTRA_MEDIA_RESOURCE_TYPE, resourceType);
+ getContext().sendBroadcastAsUser(intent,
+ new UserHandle(ActivityManager.getCurrentUser()),
+ android.Manifest.permission.RECEIVE_MEDIA_RESOURCE_USAGE);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private String[] getPackageNamesFromPid(int pid) {
+ try {
+ for (ActivityManager.RunningAppProcessInfo proc :
+ ActivityManagerNative.getDefault().getRunningAppProcesses()) {
+ if (proc.pid == pid) {
+ return proc.pkgList;
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "ActivityManager.getRunningAppProcesses() failed");
+ }
+ return null;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/policy/ShortcutManager.java b/services/core/java/com/android/server/policy/ShortcutManager.java
index 9908624..9284442 100644
--- a/services/core/java/com/android/server/policy/ShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ShortcutManager.java
@@ -26,6 +26,7 @@
import android.util.Log;
import android.util.SparseArray;
import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -47,8 +48,10 @@
private static final String ATTRIBUTE_CLASS = "class";
private static final String ATTRIBUTE_SHORTCUT = "shortcut";
private static final String ATTRIBUTE_CATEGORY = "category";
+ private static final String ATTRIBUTE_SHIFT = "shift";
private final SparseArray<ShortcutInfo> mShortcuts = new SparseArray<>();
+ private final SparseArray<ShortcutInfo> mShiftShortcuts = new SparseArray<>();
private final Context mContext;
@@ -75,17 +78,21 @@
public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
ShortcutInfo shortcut = null;
+ // If the Shift key is preesed, then search for the shift shortcuts.
+ boolean isShiftOn = (metaState & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON;
+ SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mShortcuts;
+
// First try the exact keycode (with modifiers).
int shortcutChar = kcm.get(keyCode, metaState);
if (shortcutChar != 0) {
- shortcut = mShortcuts.get(shortcutChar);
+ shortcut = shortcutMap.get(shortcutChar);
}
// Next try the primary character on that key.
if (shortcut == null) {
shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
if (shortcutChar != 0) {
- shortcut = mShortcuts.get(shortcutChar);
+ shortcut = shortcutMap.get(shortcutChar);
}
}
@@ -114,6 +121,7 @@
String className = parser.getAttributeValue(null, ATTRIBUTE_CLASS);
String shortcutName = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT);
String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
+ String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT);
if (TextUtils.isEmpty(shortcutName)) {
Log.w(TAG, "Unable to get shortcut for: " + packageName + "/" + className);
@@ -121,6 +129,7 @@
}
final int shortcutChar = shortcutName.charAt(0);
+ final boolean isShiftShortcut = (shiftName != null && shiftName.equals("true"));
final Intent intent;
final String title;
@@ -158,7 +167,11 @@
}
ShortcutInfo shortcut = new ShortcutInfo(title, intent);
- mShortcuts.put(shortcutChar, shortcut);
+ if (isShiftShortcut) {
+ mShiftShortcuts.put(shortcutChar, shortcut);
+ } else {
+ mShortcuts.put(shortcutChar, shortcut);
+ }
}
} catch (XmlPullParserException e) {
Log.w(TAG, "Got exception parsing bookmarks.", e);
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
index a035826..ebbb8b3 100644
--- a/services/core/java/com/android/server/tv/TvInputHal.java
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -116,7 +116,7 @@
public void close() {
synchronized (mLock) {
- if (mPtr != 0l) {
+ if (mPtr != 0L) {
nativeClose(mPtr);
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index d814ebf..3193ff8 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -465,7 +465,7 @@
try {
context = mContext.createPackageContextAsUser("android", 0, user);
} catch (NameNotFoundException e) {
- Slog.e(TAG, "failed to create package contenxt as user " + user);
+ Slog.e(TAG, "failed to create package context as user " + user);
context = mContext;
}
return context.getContentResolver();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a9025bd..0c429e5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -222,6 +222,10 @@
out.set(left, top, left + width, top + height);
}
+ void getContentRect(Rect out) {
+ out.set(mContentRect);
+ }
+
/** Refer to {@link WindowManagerService#attachStack(int, int, boolean)} */
void attachStack(TaskStack stack, boolean onTop) {
if (stack.mStackId == HOME_STACK_ID) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 6bb3e20..71d616d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -63,6 +63,9 @@
private Rect mBounds = new Rect();
final Rect mPreparedFrozenBounds = new Rect();
+ private Rect mPreScrollBounds = new Rect();
+ private boolean mScrollValid;
+
// Bounds used to calculate the insets.
private final Rect mTempInsetBounds = new Rect();
@@ -127,12 +130,25 @@
int yOffset = 0;
if (dockSide != DOCKED_INVALID) {
mStack.getBounds(mTmpRect);
- displayContent.getLogicalDisplayRect(mTmpRect2);
if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
+ // The toast was originally placed at the bottom and centered. To place it
+ // at the bottom-center of the stack, we offset it horizontally by the diff
+ // between the center of the stack bounds vs. the center of the screen.
+ displayContent.getLogicalDisplayRect(mTmpRect2);
xOffset = mTmpRect.centerX() - mTmpRect2.centerX();
} else if (dockSide == DOCKED_TOP) {
+ // The toast was originally placed at the bottom and centered. To place it
+ // at the bottom center of the top stack, we offset it vertically by the diff
+ // between the bottom of the stack bounds vs. the bottom of the content rect.
+ //
+ // Note here we use the content rect instead of the display rect, as we want
+ // the toast's distance to the dock divider (when it's placed at the top half)
+ // to be the same as it's distance to the top of the navigation bar (when it's
+ // placed at the bottom).
+
// We don't adjust for DOCKED_BOTTOM case since it's already at the bottom.
+ displayContent.getContentRect(mTmpRect2);
yOffset = mTmpRect2.bottom - mTmpRect.bottom;
}
mService.mH.obtainMessage(
@@ -258,19 +274,23 @@
// Can't set to fullscreen if we don't have a display to get bounds from...
return BOUNDS_CHANGE_NONE;
}
- if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
+ if (mPreScrollBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
return BOUNDS_CHANGE_NONE;
}
int boundsChange = BOUNDS_CHANGE_NONE;
- if (mBounds.left != bounds.left || mBounds.top != bounds.top) {
+ if (mPreScrollBounds.left != bounds.left || mPreScrollBounds.top != bounds.top) {
boundsChange |= BOUNDS_CHANGE_POSITION;
}
- if (mBounds.width() != bounds.width() || mBounds.height() != bounds.height()) {
+ if (mPreScrollBounds.width() != bounds.width() || mPreScrollBounds.height() != bounds.height()) {
boundsChange |= BOUNDS_CHANGE_SIZE;
}
- mBounds.set(bounds);
+
+ mPreScrollBounds.set(bounds);
+
+ resetScrollLocked();
+
mRotation = rotation;
if (displayContent != null) {
displayContent.mDimLayerController.updateDimLayer(this);
@@ -331,6 +351,32 @@
mPreparedFrozenBounds.set(mBounds);
}
+ void resetScrollLocked() {
+ if (mScrollValid) {
+ mScrollValid = false;
+ applyScrollToAllWindows(0, 0);
+ }
+ mBounds.set(mPreScrollBounds);
+ }
+
+ void applyScrollToAllWindows(final int xOffset, final int yOffset) {
+ for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
+ final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ final WindowState win = windows.get(winNdx);
+ win.mXOffset = xOffset;
+ win.mYOffset = yOffset;
+ }
+ }
+ }
+
+ void applyScrollToWindowIfNeeded(final WindowState win) {
+ if (mScrollValid) {
+ win.mXOffset = mBounds.left;
+ win.mYOffset = mBounds.top;
+ }
+ }
+
boolean scrollLocked(Rect bounds) {
// shift the task bound if it doesn't fully cover the stack area
mStack.getDimBounds(mTmpRect);
@@ -352,21 +398,17 @@
}
}
- if (bounds.equals(mBounds)) {
+ // We can stop here if we're already scrolling and the scrolled bounds not changed.
+ if (mScrollValid && bounds.equals(mBounds)) {
return false;
}
+
// Normal setBounds() does not allow non-null bounds for fullscreen apps.
// We only change bounds for the scrolling case without change it size,
// on resizing path we should still want the validation.
mBounds.set(bounds);
- for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
- final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
- for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
- final WindowState win = windows.get(winNdx);
- win.mXOffset = bounds.left;
- win.mYOffset = bounds.top;
- }
- }
+ mScrollValid = true;
+ applyScrollToAllWindows(bounds.left, bounds.top);
return true;
}
@@ -481,19 +523,25 @@
return;
}
- // Device rotation changed. We don't want the task to move around on the screen when
- // this happens, so update the task bounds so it stays in the same place.
- mTmpRect2.set(mBounds);
+ // Device rotation changed.
+ // - Reset the bounds to the pre-scroll bounds as whatever scrolling was done is no longer
+ // valid.
+ // - Rotate the bounds and notify activity manager if the task can be resized independently
+ // from its stack. The stack will take care of task rotation for the other case.
+ mTmpRect2.set(mPreScrollBounds);
+
+ if (!StackId.isTaskResizeAllowed(mStack.mStackId)) {
+ setBounds(mTmpRect2, mOverrideConfig);
+ return;
+ }
+
displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) {
- // Post message to inform activity manager of the bounds change simulating
- // a one-way call. We do this to prevent a deadlock between window manager
- // lock and activity manager lock been held. Only tasks within the freeform stack
- // are resizeable independently of their stack resizing.
- if (mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
- mService.mH.sendMessage(mService.mH.obtainMessage(
- RESIZE_TASK, mTaskId, RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds));
- }
+ // Post message to inform activity manager of the bounds change simulating a one-way
+ // call. We do this to prevent a deadlock between window manager lock and activity
+ // manager lock been held.
+ mService.mH.obtainMessage(RESIZE_TASK, mTaskId,
+ RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mPreScrollBounds).sendToTarget();
}
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index e75780f..632c033 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -18,7 +18,6 @@
import android.app.ActivityManager.StackId;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Debug;
import android.util.EventLog;
@@ -38,6 +37,7 @@
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_LEFT;
@@ -89,6 +89,7 @@
/** Detach this stack from its display when animation completes. */
boolean mDeferDetach;
+ private boolean mUpdateBoundsAfterRotation = false;
TaskStack(WindowManagerService service, int stackId) {
mService = service;
@@ -136,8 +137,8 @@
// it might no longer fully cover the stack area.
// Save the old bounds and re-apply the scroll. This adjusts the bounds to
// fit the new stack bounds.
- task.getBounds(mTmpRect);
task.setBounds(bounds, config);
+ task.getBounds(mTmpRect);
task.scrollLocked(mTmpRect);
} else {
task.setBounds(bounds, config);
@@ -239,6 +240,7 @@
}
void updateDisplayInfo(Rect bounds) {
+ mUpdateBoundsAfterRotation = false;
if (mDisplayContent != null) {
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
@@ -248,6 +250,7 @@
} else if (mFullscreen) {
setBounds(null);
} else {
+ mUpdateBoundsAfterRotation = true;
mTmpRect2.set(mBounds);
final int newRotation = mDisplayContent.getDisplayInfo().rotation;
if (mRotation == newRotation) {
@@ -265,6 +268,10 @@
* yet.
*/
void updateBoundsAfterRotation() {
+ if (!mUpdateBoundsAfterRotation) {
+ return;
+ }
+ mUpdateBoundsAfterRotation = false;
final int newRotation = getDisplayInfo().rotation;
mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
if (mStackId == DOCKED_STACK_ID) {
@@ -359,6 +366,10 @@
"positionTask: task=" + task + " position=" + position);
mTasks.add(position, task);
+ // If we are moving the task across stacks, the scroll is no longer valid.
+ if (task.mStack != this) {
+ task.resetScrollLocked();
+ }
task.mStack = this;
task.updateDisplayInfo(mDisplayContent);
boolean toTop = position == mTasks.size() - 1;
@@ -539,20 +550,32 @@
outBounds.set(mService.mDockedStackCreateBounds);
return;
}
- // The initial bounds of the docked stack when it is created half the screen space and
- // its bounds can be adjusted after that. The bounds of all other stacks are adjusted
- // to occupy whatever screen space the docked stack isn't occupying.
+
+ // The initial bounds of the docked stack when it is created about half the screen space
+ // and its bounds can be adjusted after that. The bounds of all other stacks are
+ // adjusted to occupy whatever screen space the docked stack isn't occupying.
+ final DisplayInfo di = mDisplayContent.getDisplayInfo();
+ mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
+ mTmpRect2);
+ final int position = new DividerSnapAlgorithm(mService.mContext.getResources(),
+ 0 /* minFlingVelocityPxPerSecond */,
+ di.logicalWidth,
+ di.logicalHeight,
+ dockDividerWidth,
+ mService.mCurConfiguration.orientation == ORIENTATION_PORTRAIT,
+ mTmpRect2).getMiddleTarget().position;
+
if (dockOnTopOrLeft) {
if (splitHorizontally) {
- outBounds.right = displayRect.centerX() - dockDividerWidth / 2;
+ outBounds.right = position;
} else {
- outBounds.bottom = displayRect.centerY() - dockDividerWidth / 2;
+ outBounds.bottom = position;
}
} else {
if (splitHorizontally) {
- outBounds.left = displayRect.centerX() + dockDividerWidth / 2;
+ outBounds.left = position - dockDividerWidth;
} else {
- outBounds.top = displayRect.centerY() + dockDividerWidth / 2;
+ outBounds.top = position - dockDividerWidth;
}
}
return;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 685df25..7d142ec 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -119,6 +119,7 @@
import com.android.internal.R;
import com.android.internal.app.IAssistScreenshotReceiver;
+import com.android.internal.os.IResultReceiver;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -10269,6 +10270,14 @@
listener);
}
+ @Override
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
+ try {
+ getFocusedWindow().mClient.requestAppKeyboardShortcuts(receiver);
+ } catch (RemoteException e) {
+ }
+ }
+
private final class LocalService extends WindowManagerInternal {
@Override
public void requestTraversalFromDisplayManager() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 058fa67..afbaf00 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1469,10 +1469,8 @@
void applyScrollIfNeeded() {
final Task task = getTask();
- if (task != null && task.isTwoFingerScrollMode()) {
- task.getDimBounds(mTmpRect);
- mXOffset = mTmpRect.left;
- mYOffset = mTmpRect.top;
+ if (task != null) {
+ task.applyScrollToWindowIfNeeded(this);
}
}
@@ -2284,10 +2282,12 @@
void transformFromScreenToSurfaceSpace(Rect rect) {
if (mHScale >= 0) {
- rect.right = rect.left + (int)((rect.right - rect.left) / mHScale);
+ rect.left = (int) (rect.left / mHScale);
+ rect.right = (int) (rect.right / mHScale);
}
if (mVScale >= 0) {
- rect.bottom = rect.top + (int)((rect.bottom - rect.top) / mVScale);
+ rect.top = (int) (rect.top / mVScale);
+ rect.bottom = (int) (rect.bottom / mVScale);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 83ab190..a3a59c0 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1355,6 +1355,11 @@
}
}
w.mToken.hasVisible = true;
+
+ final Task task = w.getTask();
+ if (task != null) {
+ task.scheduleShowNonResizeableDockToastIfNeeded();
+ }
}
}
@@ -1513,10 +1518,6 @@
mWin.mAppToken.updateReportedVisibilityLocked();
}
- final Task task = mWin.getTask();
- if (task != null) {
- task.scheduleShowNonResizeableDockToastIfNeeded();
- }
return true;
}
return false;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c4d5c50..ce0474d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3907,6 +3907,42 @@
}
}
+ @Override
+ public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage)
+ throws SecurityException {
+ synchronized (this) {
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ }
+
+ final int userId = mInjector.userHandleGetCallingUserId();
+ final long token = mInjector.binderClearCallingIdentity();
+ try{
+ ConnectivityManager connectivityManager = (ConnectivityManager)
+ mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ return connectivityManager.setAlwaysOnVpnPackageForUser(userId, vpnPackage);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public String getAlwaysOnVpnPackage(ComponentName admin)
+ throws SecurityException {
+ synchronized (this) {
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ }
+
+ final int userId = mInjector.userHandleGetCallingUserId();
+ final long token = mInjector.binderClearCallingIdentity();
+ try{
+ ConnectivityManager connectivityManager = (ConnectivityManager)
+ mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ return connectivityManager.getAlwaysOnVpnPackageForUser(userId);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(token);
+ }
+ }
+
private void wipeDataLocked(boolean wipeExtRequested, String reason) {
if (wipeExtRequested) {
StorageManager sm = (StorageManager) mContext.getSystemService(
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 287b39c..10b175f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -67,6 +67,7 @@
import com.android.server.lights.LightsService;
import com.android.server.media.MediaRouterService;
import com.android.server.media.MediaSessionService;
+import com.android.server.media.MediaResourceMonitorService;
import com.android.server.media.projection.MediaProjectionManagerService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
@@ -1025,6 +1026,8 @@
mSystemServiceManager.startService(TvInputManagerService.class);
}
+ mSystemServiceManager.startService(MediaResourceMonitorService.class);
+
if (!disableNonCoreServices) {
traceBeginAndSlog("StartMediaRouterService");
try {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index e27441e..4253cd4 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -280,6 +280,11 @@
mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL);
}
+ @Override
+ public long getAppIdleRollingWindowDurationMillis() {
+ return mAppIdleWallclockThresholdMillis * 2;
+ }
+
private void cleanUpRemovedUsersLocked() {
final List<UserInfo> users = mUserManager.getUsers(true);
if (users == null || users.size() == 0) {
@@ -548,7 +553,8 @@
final int userCount = mUserState.size();
for (int i = 0; i < userCount; i++) {
final UserUsageStatsService service = mUserState.valueAt(i);
- service.onTimeChanged(expectedSystemTime, actualSystemTime, resetBeginIdleTime);
+ service.onTimeChanged(expectedSystemTime, actualSystemTime, mScreenOnTime,
+ resetBeginIdleTime);
}
mRealTimeSnapshot = actualRealtime;
mSystemTimeSnapshot = actualSystemTime;
@@ -1106,7 +1112,13 @@
* Observe settings changes for {@link Settings.Global#APP_IDLE_CONSTANTS}.
*/
private class SettingsObserver extends ContentObserver {
- private static final String KEY_IDLE_DURATION = "idle_duration";
+ /**
+ * This flag has been used to disable app idle on older builds with bug b/26355386.
+ */
+ @Deprecated
+ private static final String KEY_IDLE_DURATION_OLD = "idle_duration";
+
+ private static final String KEY_IDLE_DURATION = "idle_duration2";
private static final String KEY_WALLCLOCK_THRESHOLD = "wallclock_threshold";
private static final String KEY_PAROLE_INTERVAL = "parole_interval";
private static final String KEY_PAROLE_DURATION = "parole_duration";
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 630367d..224faf4 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -73,6 +73,7 @@
interface StatsUpdatedListener {
void onStatsUpdated();
+ long getAppIdleRollingWindowDurationMillis();
}
UserUsageStatsService(Context context, int userId, File usageStatsDir,
@@ -134,12 +135,12 @@
stat.updateConfigurationStats(null, stat.lastTimeSaved);
}
+ refreshAppIdleRollingWindow(currentTimeMillis, deviceUsageTime);
+
if (mDatabase.isNewUpdate()) {
initializeDefaultsForApps(currentTimeMillis, deviceUsageTime,
mDatabase.isFirstUpdate());
}
-
- refreshAppIdleRollingWindow(currentTimeMillis);
}
/**
@@ -161,19 +162,24 @@
for (IntervalStats stats : mCurrentStats) {
stats.update(packageName, currentTimeMillis, Event.SYSTEM_INTERACTION);
stats.updateBeginIdleTime(packageName, deviceUsageTime);
- mStatsChanged = true;
}
+
+ mAppIdleRollingWindow.update(packageName, currentTimeMillis,
+ Event.SYSTEM_INTERACTION);
+ mAppIdleRollingWindow.updateBeginIdleTime(packageName, deviceUsageTime);
+ mStatsChanged = true;
}
}
// Persist the new OTA-related access stats.
persistActiveStats();
}
- void onTimeChanged(long oldTime, long newTime, boolean resetBeginIdleTime) {
+ void onTimeChanged(long oldTime, long newTime, long deviceUsageTime,
+ boolean resetBeginIdleTime) {
persistActiveStats();
mDatabase.onTimeChanged(newTime - oldTime);
loadActiveStats(newTime, resetBeginIdleTime);
- refreshAppIdleRollingWindow(newTime);
+ refreshAppIdleRollingWindow(newTime, deviceUsageTime);
}
void reportEvent(UsageEvents.Event event, long deviceUsageTime) {
@@ -185,7 +191,7 @@
if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) {
// Need to rollover
- rolloverStats(event.mTimeStamp);
+ rolloverStats(event.mTimeStamp, deviceUsageTime);
}
final IntervalStats currentDailyStats = mCurrentStats[UsageStatsManager.INTERVAL_DAILY];
@@ -429,7 +435,7 @@
}
}
- private void rolloverStats(final long currentTimeMillis) {
+ private void rolloverStats(final long currentTimeMillis, final long deviceUsageTime) {
final long startTime = SystemClock.elapsedRealtime();
Slog.i(TAG, mLogPrefix + "Rolling over usage stats");
@@ -470,7 +476,7 @@
}
persistActiveStats();
- refreshAppIdleRollingWindow(currentTimeMillis);
+ refreshAppIdleRollingWindow(currentTimeMillis, deviceUsageTime);
final long totalTime = SystemClock.elapsedRealtime() - startTime;
Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime
@@ -528,44 +534,30 @@
mDailyExpiryDate.getTimeInMillis() + ")");
}
- private static void mergePackageStats(IntervalStats dst, IntervalStats src) {
+ private static void mergePackageStats(IntervalStats dst, IntervalStats src,
+ final long deviceUsageTime) {
dst.endTime = Math.max(dst.endTime, src.endTime);
final int srcPackageCount = src.packageStats.size();
for (int i = 0; i < srcPackageCount; i++) {
final String packageName = src.packageStats.keyAt(i);
final UsageStats srcStats = src.packageStats.valueAt(i);
- final UsageStats dstStats = dst.packageStats.get(packageName);
+ UsageStats dstStats = dst.packageStats.get(packageName);
if (dstStats == null) {
- dst.packageStats.put(packageName, new UsageStats(srcStats));
+ dstStats = new UsageStats(srcStats);
+ dst.packageStats.put(packageName, dstStats);
} else {
dstStats.add(src.packageStats.valueAt(i));
}
+
+ // App idle times can not begin in the future. This happens if we had a time change.
+ if (dstStats.mBeginIdleTime > deviceUsageTime) {
+ dstStats.mBeginIdleTime = deviceUsageTime;
+ }
}
}
/**
- * Merges all the stats into the first element of the resulting list.
- */
- private static final StatCombiner<IntervalStats> sPackageStatsMerger =
- new StatCombiner<IntervalStats>() {
- @Override
- public void combine(IntervalStats stats, boolean mutable,
- List<IntervalStats> accumulatedResult) {
- IntervalStats accum;
- if (accumulatedResult.isEmpty()) {
- accum = new IntervalStats();
- accum.beginTime = stats.beginTime;
- accumulatedResult.add(accum);
- } else {
- accum = accumulatedResult.get(0);
- }
-
- mergePackageStats(accum, stats);
- }
- };
-
- /**
* App idle operates on a rolling window of time. When we roll over time, we end up with a
* period of time where in-memory stats are empty and we don't hit the disk for older stats
* for performance reasons. Suddenly all apps will become idle.
@@ -575,16 +567,33 @@
*
* @param currentTimeMillis
*/
- void refreshAppIdleRollingWindow(long currentTimeMillis) {
+ void refreshAppIdleRollingWindow(final long currentTimeMillis, final long deviceUsageTime) {
// Start the rolling window for AppIdle requests.
+ final long startRangeMillis = currentTimeMillis -
+ mListener.getAppIdleRollingWindowDurationMillis();
+
List<IntervalStats> stats = mDatabase.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,
- currentTimeMillis - (1000 * 60 * 60 * 24 * 2), currentTimeMillis,
- sPackageStatsMerger);
+ startRangeMillis, currentTimeMillis, new StatCombiner<IntervalStats>() {
+ @Override
+ public void combine(IntervalStats stats, boolean mutable,
+ List<IntervalStats> accumulatedResult) {
+ IntervalStats accum;
+ if (accumulatedResult.isEmpty()) {
+ accum = new IntervalStats();
+ accum.beginTime = stats.beginTime;
+ accumulatedResult.add(accum);
+ } else {
+ accum = accumulatedResult.get(0);
+ }
+
+ mergePackageStats(accum, stats, deviceUsageTime);
+ }
+ });
if (stats == null || stats.isEmpty()) {
mAppIdleRollingWindow = new IntervalStats();
mergePackageStats(mAppIdleRollingWindow,
- mCurrentStats[UsageStatsManager.INTERVAL_YEARLY]);
+ mCurrentStats[UsageStatsManager.INTERVAL_YEARLY], deviceUsageTime);
} else {
mAppIdleRollingWindow = stats.get(0);
}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 59a8a67..b9d7297 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -53,6 +53,9 @@
private static final String TAG = "CallerInfo";
private static final boolean VDBG = Rlog.isLoggable(TAG, Log.VERBOSE);
+ public static final long USER_TYPE_CURRENT = 0;
+ public static final long USER_TYPE_WORK = 1;
+
/**
* Please note that, any one of these member variables can be null,
* and any accesses to them should be prepared to handle such a case.
@@ -103,6 +106,8 @@
public Uri contactRefUri;
public String lookupKey;
+ public long userType;
+
/**
* Contact display photo URI. If a contact has no display photo but a thumbnail, it'll be
* the thumbnail URI instead.
@@ -154,6 +159,7 @@
// TODO: Move all the basic initialization here?
mIsEmergency = false;
mIsVoiceMail = false;
+ userType = USER_TYPE_CURRENT;
}
/**
@@ -173,6 +179,7 @@
info.cachedPhoto = null;
info.isCachedPhotoCurrent = false;
info.contactExists = false;
+ info.userType = USER_TYPE_CURRENT;
if (VDBG) Rlog.v(TAG, "getCallerInfo() based on cursor...");
@@ -225,6 +232,9 @@
Rlog.v(TAG, "==> got info.contactIdOrZero: " + info.contactIdOrZero);
}
}
+ if (Contacts.isEnterpriseContactId(contactId)) {
+ info.userType = USER_TYPE_WORK;
+ }
} else {
// No valid columnIndex, so we can't look up person_id.
Rlog.w(TAG, "Couldn't find contact_id column for " + contactRef);
@@ -628,6 +638,7 @@
/**
* @return a string debug representation of this instance.
*/
+ @Override
public String toString() {
// Warning: never check in this file with VERBOSE_DEBUG = true
// because that will result in PII in the system log.
@@ -658,6 +669,7 @@
.append("\nemergency: " + mIsEmergency)
.append("\nvoicemail " + mIsVoiceMail)
.append("\ncontactExists " + contactExists)
+ .append("\nuserType " + userType)
.append(" }")
.toString();
} else {
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
new file mode 100644
index 0000000..5dffa28
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.os.Bundle;
+
+
+/**
+ * Interface used to interact with the Telephony debug service.
+ *
+ * {@hide}
+ */
+interface ITelephonyDebug {
+
+ /**
+ * Write telephony event
+ * @param timestamp returned by System.currentTimeMillis()
+ * @param phoneId for which event is written
+ * @param tag constant defined in TelephonyEventLog
+ * @param param1 optional
+ * @param param2 optional
+ * @param data optional
+ */
+ void writeEvent(long timestamp, int phoneId, int tag, int param1, int param2, in Bundle data);
+}
diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp
index 64353de..13f8b3b 100644
--- a/tools/aapt2/ConfigDescription.cpp
+++ b/tools/aapt2/ConfigDescription.cpp
@@ -30,6 +30,11 @@
static const char* kWildcardName = "any";
+const ConfigDescription& ConfigDescription::defaultConfig() {
+ static ConfigDescription config = {};
+ return config;
+}
+
static bool parseMcc(const char* name, ResTable_config* out) {
if (strcmp(name, kWildcardName) == 0) {
if (out) out->mcc = 0;
diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h
index 4af089d..5749816 100644
--- a/tools/aapt2/ConfigDescription.h
+++ b/tools/aapt2/ConfigDescription.h
@@ -29,6 +29,11 @@
* initialization and comparison methods.
*/
struct ConfigDescription : public android::ResTable_config {
+ /**
+ * Returns an immutable default config.
+ */
+ static const ConfigDescription& defaultConfig();
+
/*
* Parse a string of the form 'fr-sw600dp-land' and fill in the
* given ResTable_config with resulting configuration parameters.
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 5fce2c1..b4e75f9 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -210,4 +210,19 @@
std::cout << "}" << std::endl;
}
+void Debug::dumpHex(const void* data, size_t len) {
+ const uint8_t* d = (const uint8_t*) data;
+ for (size_t i = 0; i < len; i++) {
+ std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t) d[i] << " ";
+ if (i % 8 == 7) {
+ std::cerr << "\n";
+ }
+ }
+
+ if (len - 1 % 8 != 7) {
+ std::cerr << std::endl;
+ }
+}
+
+
} // namespace aapt
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index 5b0d7d6..ba05be9 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -20,12 +20,16 @@
#include "Resource.h"
#include "ResourceTable.h"
+// Include for printf-like debugging.
+#include <iostream>
+
namespace aapt {
struct Debug {
static void printTable(ResourceTable* table);
static void printStyleGraph(ResourceTable* table,
const ResourceName& targetStyle);
+ static void dumpHex(const void* data, size_t len);
};
} // namespace aapt
diff --git a/tools/aapt2/Flags.cpp b/tools/aapt2/Flags.cpp
index 9435396..666e8a8e 100644
--- a/tools/aapt2/Flags.cpp
+++ b/tools/aapt2/Flags.cpp
@@ -81,6 +81,8 @@
}
void Flags::usage(const StringPiece& command, std::ostream* out) {
+ constexpr size_t kWidth = 50;
+
*out << command << " [options]";
for (const Flag& flag : mFlags) {
if (flag.required) {
@@ -100,11 +102,11 @@
// the first line) followed by the description line. This will make sure that multiline
// descriptions are still right justified and aligned.
for (StringPiece line : util::tokenize<char>(flag.description, '\n')) {
- *out << " " << std::setw(30) << std::left << argLine << line << "\n";
+ *out << " " << std::setw(kWidth) << std::left << argLine << line << "\n";
argLine = " ";
}
}
- *out << " " << std::setw(30) << std::left << "-h" << "Displays this help menu\n";
+ *out << " " << std::setw(kWidth) << std::left << "-h" << "Displays this help menu\n";
out->flush();
}
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 5e7d3ec..b37d366 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -70,6 +70,7 @@
*/
struct ParsedResource {
ResourceName name;
+ ConfigDescription config;
Source source;
ResourceId id;
Maybe<SymbolState> symbolState;
@@ -108,8 +109,7 @@
}
// Recursively adds resources to the ResourceTable.
-static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config,
- IDiagnostics* diag, ParsedResource* res) {
+static bool addResourcesToTable(ResourceTable* table, IDiagnostics* diag, ParsedResource* res) {
if (res->symbolState) {
Symbol symbol;
symbol.state = res->symbolState.value();
@@ -125,14 +125,14 @@
res->value->setComment(std::move(res->comment));
res->value->setSource(std::move(res->source));
- if (!table->addResource(res->name, res->id, config, std::move(res->value), diag)) {
+ if (!table->addResource(res->name, res->id, res->config, std::move(res->value), diag)) {
return false;
}
}
bool error = false;
for (ParsedResource& child : res->childResources) {
- error |= !addResourcesToTable(table, config, diag, &child);
+ error |= !addResourcesToTable(table, diag, &child);
}
return !error;
}
@@ -290,6 +290,7 @@
}
ParsedResource parsedResource;
+ parsedResource.config = mConfig;
parsedResource.source = mSource.withLine(parser->getLineNumber());
parsedResource.comment = std::move(comment);
@@ -310,7 +311,7 @@
// Record that we stripped out this resource name.
// We will check that at least one variant of this resource was included.
strippedResources.insert(parsedResource.name);
- } else if (!addResourcesToTable(mTable, mConfig, mDiag, &parsedResource)) {
+ } else if (!addResourcesToTable(mTable, mDiag, &parsedResource)) {
error = true;
}
}
@@ -769,6 +770,13 @@
bool weak) {
outResource->name.type = ResourceType::kAttr;
+ // Attributes only end up in default configuration.
+ if (outResource->config != ConfigDescription::defaultConfig()) {
+ mDiag->warn(DiagMessage(outResource->source) << "ignoring configuration '"
+ << outResource->config << "' for attribute " << outResource->name);
+ outResource->config = ConfigDescription::defaultConfig();
+ }
+
uint32_t typeMask = 0;
Maybe<StringPiece16> maybeFormat = xml::findAttribute(parser, u"format");
@@ -940,8 +948,7 @@
}
return Attribute::Symbol{
- Reference(ResourceNameRef({}, ResourceType::kId, maybeName.value())),
- val.data };
+ Reference(ResourceNameRef({}, ResourceType::kId, maybeName.value())), val.data };
}
static Maybe<Reference> parseXmlAttributeName(StringPiece16 str) {
@@ -1190,12 +1197,21 @@
return true;
}
-bool ResourceParser::parseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* outResource) {
+bool ResourceParser::parseDeclareStyleable(xml::XmlPullParser* parser,
+ ParsedResource* outResource) {
outResource->name.type = ResourceType::kStyleable;
// Declare-styleable is kPrivate by default, because it technically only exists in R.java.
outResource->symbolState = SymbolState::kPublic;
+ // Declare-styleable only ends up in default config;
+ if (outResource->config != ConfigDescription::defaultConfig()) {
+ mDiag->warn(DiagMessage(outResource->source) << "ignoring configuration '"
+ << outResource->config << "' for styleable "
+ << outResource->name.entry);
+ outResource->config = ConfigDescription::defaultConfig();
+ }
+
std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
std::u16string comment;
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 8d10ba1..cf0fcd1 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -47,13 +47,26 @@
mContext = test::ContextBuilder().build();
}
+ ::testing::AssertionResult testParse(const StringPiece& str) {
+ return testParse(str, ConfigDescription{}, {});
+ }
+
+ ::testing::AssertionResult testParse(const StringPiece& str, const ConfigDescription& config) {
+ return testParse(str, config, {});
+ }
+
::testing::AssertionResult testParse(const StringPiece& str,
- std::initializer_list<std::u16string> products = {}) {
+ std::initializer_list<std::u16string> products) {
+ return testParse(str, {}, std::move(products));
+ }
+
+ ::testing::AssertionResult testParse(const StringPiece& str, const ConfigDescription& config,
+ std::initializer_list<std::u16string> products) {
std::stringstream input(kXmlPreamble);
input << "<resources>\n" << str << "\n</resources>" << std::endl;
ResourceParserOptions parserOptions;
parserOptions.products = products;
- ResourceParser parser(mContext->getDiagnostics(), &mTable, Source{ "test" }, {},
+ ResourceParser parser(mContext->getDiagnostics(), &mTable, Source{ "test" }, config,
parserOptions);
xml::XmlPullParser xmlParser(input);
if (parser.parse(&xmlParser)) {
@@ -138,6 +151,26 @@
EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_ANY), attr->typeMask);
}
+// Old AAPT allowed attributes to be defined under different configurations, but ultimately
+// stored them with the default configuration. Check that we have the same behavior.
+TEST_F(ResourceParserTest, ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoConfig) {
+ const ConfigDescription watchConfig = test::parseConfigOrDie("watch");
+ std::string input = R"EOF(
+ <attr name="foo" />
+ <declare-styleable name="bar">
+ <attr name="baz" />
+ </declare-styleable>)EOF";
+ ASSERT_TRUE(testParse(input, watchConfig));
+
+ EXPECT_EQ(nullptr, test::getValueForConfig<Attribute>(&mTable, u"@attr/foo", watchConfig));
+ EXPECT_EQ(nullptr, test::getValueForConfig<Attribute>(&mTable, u"@attr/baz", watchConfig));
+ EXPECT_EQ(nullptr, test::getValueForConfig<Styleable>(&mTable, u"@styleable/bar", watchConfig));
+
+ EXPECT_NE(nullptr, test::getValue<Attribute>(&mTable, u"@attr/foo"));
+ EXPECT_NE(nullptr, test::getValue<Attribute>(&mTable, u"@attr/baz"));
+ EXPECT_NE(nullptr, test::getValue<Styleable>(&mTable, u"@styleable/bar"));
+}
+
TEST_F(ResourceParserTest, ParseAttrWithMinMax) {
std::string input = "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"integer\"/>";
ASSERT_TRUE(testParse(input));
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 1dc123e..07f62af 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -176,7 +176,7 @@
/*
* Style parent's are a bit different. We accept the following formats:
*
- * @[[*]package:]style/<entry>
+ * @[[*]package:][style/]<entry>
* ?[[*]package:]style/<entry>
* <[*]package>:[style/]<entry>
* [[*]package:style/]<entry>
@@ -216,14 +216,6 @@
*outError = err.str();
return {};
}
- } else {
- // No type was defined, this should not have a leading identifier.
- if (hasLeadingIdentifiers) {
- std::stringstream err;
- err << "invalid parent reference '" << str << "'";
- *outError = err.str();
- return {};
- }
}
if (!hasLeadingIdentifiers && ref.package.empty() && !typeStr.empty()) {
@@ -294,6 +286,12 @@
const StringPiece16& str) {
android::Res_value flags = { };
flags.dataType = android::Res_value::TYPE_INT_DEC;
+ flags.data = 0u;
+
+ if (util::trimWhitespace(str).empty()) {
+ // Empty string is a valid flag (0).
+ return util::make_unique<BinaryPrimitive>(flags);
+ }
for (StringPiece16 part : util::tokenize(str, u'|')) {
StringPiece16 trimmedPart = util::trimWhitespace(part);
@@ -386,12 +384,12 @@
bool tryParseBool(const StringPiece16& str, bool* outValue) {
StringPiece16 trimmedStr(util::trimWhitespace(str));
- if (trimmedStr == u"true" || trimmedStr == u"TRUE") {
+ if (trimmedStr == u"true" || trimmedStr == u"TRUE" || trimmedStr == u"True") {
if (outValue) {
*outValue = true;
}
return true;
- } else if (trimmedStr == u"false" || trimmedStr == u"FALSE") {
+ } else if (trimmedStr == u"false" || trimmedStr == u"FALSE" || trimmedStr == u"False") {
if (outValue) {
*outValue = false;
}
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index 88efa67..c9f93e1 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -16,12 +16,34 @@
#include "Resource.h"
#include "ResourceUtils.h"
+#include "test/Builders.h"
#include "test/Common.h"
#include <gtest/gtest.h>
namespace aapt {
+TEST(ResourceUtilsTest, ParseBool) {
+ bool val = false;
+ EXPECT_TRUE(ResourceUtils::tryParseBool(u"true", &val));
+ EXPECT_TRUE(val);
+
+ EXPECT_TRUE(ResourceUtils::tryParseBool(u"TRUE", &val));
+ EXPECT_TRUE(val);
+
+ EXPECT_TRUE(ResourceUtils::tryParseBool(u"True", &val));
+ EXPECT_TRUE(val);
+
+ EXPECT_TRUE(ResourceUtils::tryParseBool(u"false", &val));
+ EXPECT_FALSE(val);
+
+ EXPECT_TRUE(ResourceUtils::tryParseBool(u"FALSE", &val));
+ EXPECT_FALSE(val);
+
+ EXPECT_TRUE(ResourceUtils::tryParseBool(u"False", &val));
+ EXPECT_FALSE(val);
+}
+
TEST(ResourceUtilsTest, ParseResourceName) {
ResourceNameRef actual;
bool actualPriv = false;
@@ -154,6 +176,10 @@
AAPT_ASSERT_TRUE(ref);
EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName);
+ ref = ResourceUtils::parseStyleParentReference(u"@android:foo", &errStr);
+ AAPT_ASSERT_TRUE(ref);
+ EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName);
+
ref = ResourceUtils::parseStyleParentReference(u"foo", &errStr);
AAPT_ASSERT_TRUE(ref);
EXPECT_EQ(ref.value().name.value(), kStyleFooName);
@@ -164,4 +190,16 @@
EXPECT_TRUE(ref.value().privateReference);
}
+TEST(ResourceUtilsTest, ParseEmptyFlag) {
+ std::unique_ptr<Attribute> attr = test::AttributeBuilder(false)
+ .setTypeMask(android::ResTable_map::TYPE_FLAGS)
+ .addItem(u"one", 0x01)
+ .addItem(u"two", 0x02)
+ .build();
+
+ std::unique_ptr<BinaryPrimitive> result = ResourceUtils::tryParseFlagSymbol(attr.get(), u"");
+ ASSERT_NE(nullptr, result);
+ EXPECT_EQ(0u, result->value.data);
+}
+
} // namespace aapt
diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp
index 8552f47..aadb00b 100644
--- a/tools/aapt2/StringPool.cpp
+++ b/tools/aapt2/StringPool.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
+#include "StringPool.h"
#include "util/BigBuffer.h"
#include "util/StringPiece.h"
-#include "StringPool.h"
#include "util/Util.h"
#include <algorithm>
@@ -342,7 +342,14 @@
// Encode the actual UTF16 string length.
data = encodeLength(data, entry->value.size());
- strncpy16(data, entry->value.data(), entry->value.size());
+ const size_t byteLength = entry->value.size() * sizeof(char16_t);
+
+ // NOTE: For some reason, strncpy16(data, entry->value.data(), entry->value.size())
+ // truncates the string.
+ memcpy(data, entry->value.data(), byteLength);
+
+ // The null-terminating character is already here due to the block of data being set
+ // to 0s on allocation.
}
}
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
index c722fbe..e93c2fba 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/tools/aapt2/StringPool_test.cpp
@@ -180,6 +180,22 @@
ASSERT_EQ(test.setTo(data.get(), buffer.size()), android::NO_ERROR);
}
+TEST(StringPoolTest, FlattenOddCharactersUtf16) {
+ StringPool pool;
+ pool.makeRef(u"\u093f");
+ BigBuffer buffer(1024);
+ StringPool::flattenUtf16(&buffer, pool);
+
+ std::unique_ptr<uint8_t[]> data = util::copy(buffer);
+ android::ResStringPool test;
+ ASSERT_EQ(test.setTo(data.get(), buffer.size()), android::NO_ERROR);
+ size_t len = 0;
+ const char16_t* str = test.stringAt(0, &len);
+ EXPECT_EQ(1u, len);
+ EXPECT_EQ(u'\u093f', *str);
+ EXPECT_EQ(0u, str[1]);
+}
+
constexpr const char16_t* sLongString = u"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限します。メール、SMSや、同期を使 用するその他のアプリは、起動しても更新されないことがあります。バッテリーセーバーは端末の充電中は自動的にOFFになります。";
TEST(StringPoolTest, FlattenUtf8) {
diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp
index c78670f..689ace6 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -117,7 +117,11 @@
if (!data.configStr.empty()) {
name << "-" << data.configStr;
}
- name << "_" << data.name << "." << data.extension << ".flat";
+ name << "_" << data.name;
+ if (!data.extension.empty()) {
+ name << "." << data.extension;
+ }
+ name << ".flat";
return name.str();
}
@@ -386,16 +390,26 @@
fileExportWriter.getChunkHeader()->size =
util::hostToDevice32(buffer.size() + f.value().getDataLength());
- if (writer->writeEntry(buffer)) {
- if (writer->writeEntry(f.value().getDataPtr(), f.value().getDataLength())) {
- if (writer->finishEntry()) {
- return true;
- }
+ if (!writer->writeEntry(buffer)) {
+ context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
+ return false;
+ }
+
+ // Only write if we have something to write. This is because mmap fails with length of 0,
+ // but we still want to compile the file to get the resource ID.
+ if (f.value().getDataPtr() && f.value().getDataLength() > 0) {
+ if (!writer->writeEntry(f.value().getDataPtr(), f.value().getDataLength())) {
+ context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
+ return false;
}
}
- context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
- return false;
+ if (!writer->finishEntry()) {
+ context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
+ return false;
+ }
+
+ return true;
}
class CompileContext : public IAaptContext {
diff --git a/tools/aapt2/io/Data.h b/tools/aapt2/io/Data.h
index 9081c55..467e604 100644
--- a/tools/aapt2/io/Data.h
+++ b/tools/aapt2/io/Data.h
@@ -79,6 +79,21 @@
size_t mSize;
};
+/**
+ * When mmap fails because the file has length 0, we use the EmptyData to simulate data of length 0.
+ */
+class EmptyData : public IData {
+public:
+ const void* data() const override {
+ static const uint8_t d = 0;
+ return &d;
+ }
+
+ size_t size() const override {
+ return 0u;
+ }
+};
+
} // namespace io
} // namespace aapt
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
index 76f87ae..e758d8a4 100644
--- a/tools/aapt2/io/FileSystem.cpp
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -32,7 +32,10 @@
std::unique_ptr<IData> RegularFile::openAsData() {
android::FileMap map;
if (Maybe<android::FileMap> map = file::mmapPath(mSource.path, nullptr)) {
- return util::make_unique<MmappedData>(std::move(map.value()));
+ if (map.value().getDataPtr() && map.value().getDataLength() > 0) {
+ return util::make_unique<MmappedData>(std::move(map.value()));
+ }
+ return util::make_unique<EmptyData>();
}
return {};
}
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 8a87d96..2a4c020 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -51,16 +51,19 @@
std::vector<std::string> includePaths;
std::vector<std::string> overlayFiles;
Maybe<std::string> generateJavaClassPath;
- std::set<std::string> extraJavaPackages;
+ Maybe<std::u16string> customJavaPackage;
+ std::set<std::u16string> extraJavaPackages;
Maybe<std::string> generateProguardRulesPath;
bool noAutoVersion = false;
bool staticLib = false;
bool verbose = false;
bool outputToDirectory = false;
bool autoAddOverlay = false;
+ bool doNotCompressAnything = false;
+ std::vector<std::string> extensionsToNotCompress;
Maybe<std::u16string> privateSymbols;
- Maybe<std::u16string> minSdkVersionDefault;
- Maybe<std::u16string> targetSdkVersionDefault;
+ ManifestFixerOptions manifestFixerOptions;
+
};
struct LinkContext : public IAaptContext {
@@ -186,7 +189,20 @@
return resFile;
}
- bool copyFileToArchive(io::IFile* file, const std::string& outPath, uint32_t flags,
+ uint32_t getCompressionFlags(const StringPiece& str) {
+ if (mOptions.doNotCompressAnything) {
+ return 0;
+ }
+
+ for (const std::string& extension : mOptions.extensionsToNotCompress) {
+ if (util::stringEndsWith<char>(str, extension)) {
+ return 0;
+ }
+ }
+ return ArchiveEntry::kCompress;
+ }
+
+ bool copyFileToArchive(io::IFile* file, const std::string& outPath,
IArchiveWriter* writer) {
std::unique_ptr<io::IData> data = file->openAsData();
if (!data) {
@@ -202,7 +218,7 @@
return false;
}
- if (writer->startEntry(outPath, flags)) {
+ if (writer->startEntry(outPath, getCompressionFlags(outPath))) {
if (writer->writeEntry(reinterpret_cast<const uint8_t*>(data->data()) + offset,
data->size() - static_cast<size_t>(offset))) {
if (writer->finishEntry()) {
@@ -319,7 +335,6 @@
return false;
}
-
if (writer->startEntry(path, ArchiveEntry::kCompress)) {
if (writer->writeEntry(buffer)) {
if (writer->finishEntry()) {
@@ -520,7 +535,7 @@
const Source& src = file->getSource();
if (util::stringEndsWith<char>(src.path, ".arsc.flat")) {
return mergeResourceTable(file, override);
- } else {
+ } else if (util::stringEndsWith<char>(src.path, ".flat")){
// Try opening the file and looking for an Export header.
std::unique_ptr<io::IData> data = file->openAsData();
if (!data) {
@@ -533,7 +548,11 @@
if (resourceFile) {
return mergeCompiledFile(file, std::move(resourceFile), override);
}
+ } else {
+ // Ignore non .flat files. This could be classes.dex or something else that happens
+ // to be in an archive.
}
+
return false;
}
@@ -646,10 +665,7 @@
bool error = false;
{
- ManifestFixerOptions manifestFixerOptions;
- manifestFixerOptions.minSdkVersionDefault = mOptions.minSdkVersionDefault;
- manifestFixerOptions.targetSdkVersionDefault = mOptions.targetSdkVersionDefault;
- ManifestFixer manifestFixer(manifestFixerOptions);
+ ManifestFixer manifestFixer(mOptions.manifestFixerOptions);
if (!manifestFixer.consume(&mContext, manifestXml.get())) {
error = true;
}
@@ -786,7 +802,7 @@
mContext.getDiagnostics()->note(DiagMessage() << "copying " << path);
}
- if (!copyFileToArchive(fileToMerge.file, fileToMerge.dstPath, 0,
+ if (!copyFileToArchive(fileToMerge.file, fileToMerge.dstPath,
archiveWriter.get())) {
error = true;
}
@@ -813,12 +829,18 @@
if (mOptions.generateJavaClassPath) {
JavaClassGeneratorOptions options;
+ options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
+
if (mOptions.staticLib) {
options.useFinal = false;
}
- StringPiece16 actualPackage = mContext.getCompilationPackage();
+ const StringPiece16 actualPackage = mContext.getCompilationPackage();
StringPiece16 outputPackage = mContext.getCompilationPackage();
+ if (mOptions.customJavaPackage) {
+ // Override the output java package to the custom one.
+ outputPackage = mOptions.customJavaPackage.value();
+ }
if (mOptions.privateSymbols) {
// If we defined a private symbols package, we only emit Public symbols
@@ -826,7 +848,7 @@
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
if (!writeJavaFile(&mFinalTable, mContext.getCompilationPackage(),
- mContext.getCompilationPackage(), options)) {
+ outputPackage, options)) {
return 1;
}
@@ -838,9 +860,8 @@
return 1;
}
- for (const std::string& extraPackage : mOptions.extraJavaPackages) {
- if (!writeJavaFile(&mFinalTable, actualPackage, util::utf8ToUtf16(extraPackage),
- options)) {
+ for (const std::u16string& extraPackage : mOptions.extraJavaPackages) {
+ if (!writeJavaFile(&mFinalTable, actualPackage, extraPackage, options)) {
return 1;
}
}
@@ -877,13 +898,16 @@
LinkOptions options;
Maybe<std::string> privateSymbolsPackage;
Maybe<std::string> minSdkVersion, targetSdkVersion;
+ Maybe<std::string> renameManifestPackage, renameInstrumentationTargetPackage;
+ Maybe<std::string> versionCode, versionName;
+ Maybe<std::string> customJavaPackage;
std::vector<std::string> extraJavaPackages;
Flags flags = Flags()
.requiredFlag("-o", "Output path", &options.outputPath)
.requiredFlag("--manifest", "Path to the Android manifest to build",
&options.manifestPath)
.optionalFlagList("-I", "Adds an Android APK to link against", &options.includePaths)
- .optionalFlagList("-R", "Compilation unit to link, using `overlay` semantics. "
+ .optionalFlagList("-R", "Compilation unit to link, using `overlay` semantics.\n"
"The last conflicting resource given takes precedence.",
&options.overlayFiles)
.optionalFlag("--java", "Directory in which to generate R.java",
@@ -900,15 +924,29 @@
"AndroidManifest.xml", &minSdkVersion)
.optionalFlag("--target-sdk-version", "Default target SDK version to use for "
"AndroidManifest.xml", &targetSdkVersion)
+ .optionalFlag("--version-code", "Version code (integer) to inject into the "
+ "AndroidManifest.xml if none is present", &versionCode)
+ .optionalFlag("--version-name", "Version name to inject into the AndroidManifest.xml "
+ "if none is present", &versionName)
.optionalSwitch("--static-lib", "Generate a static Android library", &options.staticLib)
.optionalFlag("--private-symbols", "Package name to use when generating R.java for "
"private symbols.\n"
"If not specified, public and private symbols will use the application's "
"package name", &privateSymbolsPackage)
+ .optionalFlag("--custom-package", "Custom Java package under which to generate R.java",
+ &customJavaPackage)
.optionalFlagList("--extra-packages", "Generate the same R.java but with different "
"package names", &extraJavaPackages)
.optionalSwitch("--auto-add-overlay", "Allows the addition of new resources in "
"overlays without <add-resource> tags", &options.autoAddOverlay)
+ .optionalFlag("--rename-manifest-package", "Renames the package in AndroidManifest.xml",
+ &renameManifestPackage)
+ .optionalFlag("--rename-instrumentation-target-package",
+ "Changes the name of the target package for instrumentation. Most useful "
+ "when used\nin conjunction with --rename-manifest-package",
+ &renameInstrumentationTargetPackage)
+ .optionalFlagList("-0", "File extensions not to compress",
+ &options.extensionsToNotCompress)
.optionalSwitch("-v", "Enables verbose logging", &options.verbose);
if (!flags.parse("aapt2 link", args, &std::cerr)) {
@@ -920,18 +958,42 @@
}
if (minSdkVersion) {
- options.minSdkVersionDefault = util::utf8ToUtf16(minSdkVersion.value());
+ options.manifestFixerOptions.minSdkVersionDefault =
+ util::utf8ToUtf16(minSdkVersion.value());
}
if (targetSdkVersion) {
- options.targetSdkVersionDefault = util::utf8ToUtf16(targetSdkVersion.value());
+ options.manifestFixerOptions.targetSdkVersionDefault =
+ util::utf8ToUtf16(targetSdkVersion.value());
+ }
+
+ if (renameManifestPackage) {
+ options.manifestFixerOptions.renameManifestPackage =
+ util::utf8ToUtf16(renameManifestPackage.value());
+ }
+
+ if (renameInstrumentationTargetPackage) {
+ options.manifestFixerOptions.renameInstrumentationTargetPackage =
+ util::utf8ToUtf16(renameInstrumentationTargetPackage.value());
+ }
+
+ if (versionCode) {
+ options.manifestFixerOptions.versionCodeDefault = util::utf8ToUtf16(versionCode.value());
+ }
+
+ if (versionName) {
+ options.manifestFixerOptions.versionNameDefault = util::utf8ToUtf16(versionName.value());
+ }
+
+ if (customJavaPackage) {
+ options.customJavaPackage = util::utf8ToUtf16(customJavaPackage.value());
}
// Populate the set of extra packages for which to generate R.java.
for (std::string& extraPackage : extraJavaPackages) {
// A given package can actually be a colon separated list of packages.
for (StringPiece package : util::split(extraPackage, ':')) {
- options.extraJavaPackages.insert(package.toString());
+ options.extraJavaPackages.insert(util::utf8ToUtf16(package));
}
}
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 2034c57..9baf1d8 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -22,25 +22,43 @@
namespace aapt {
static bool verifyManifest(IAaptContext* context, const Source& source, xml::Element* manifestEl) {
- bool error = false;
-
xml::Attribute* attr = manifestEl->findAttribute({}, u"package");
if (!attr) {
context->getDiagnostics()->error(DiagMessage(source.withLine(manifestEl->lineNumber))
<< "missing 'package' attribute");
- error = true;
} else if (ResourceUtils::isReference(attr->value)) {
context->getDiagnostics()->error(DiagMessage(source.withLine(manifestEl->lineNumber))
<< "value for attribute 'package' must not be a "
"reference");
- error = true;
} else if (!util::isJavaPackageName(attr->value)) {
context->getDiagnostics()->error(DiagMessage(source.withLine(manifestEl->lineNumber))
<< "invalid package name '" << attr->value << "'");
- error = true;
+ } else {
+ return true;
+ }
+ return false;
+}
+
+static bool includeVersionName(IAaptContext* context, const Source& source,
+ const StringPiece16& versionName, xml::Element* manifestEl) {
+ if (manifestEl->findAttribute(xml::kSchemaAndroid, u"versionName")) {
+ return true;
}
- return !error;
+ manifestEl->attributes.push_back(xml::Attribute{
+ xml::kSchemaAndroid, u"versionName", versionName.toString() });
+ return true;
+}
+
+static bool includeVersionCode(IAaptContext* context, const Source& source,
+ const StringPiece16& versionCode, xml::Element* manifestEl) {
+ if (manifestEl->findAttribute(xml::kSchemaAndroid, u"versionCode")) {
+ return true;
+ }
+
+ manifestEl->attributes.push_back(xml::Attribute{
+ xml::kSchemaAndroid, u"versionCode", versionCode.toString() });
+ return true;
}
static bool fixUsesSdk(IAaptContext* context, const Source& source, xml::Element* el,
@@ -62,6 +80,76 @@
return true;
}
+class FullyQualifiedClassNameVisitor : public xml::Visitor {
+public:
+ using xml::Visitor::visit;
+
+ FullyQualifiedClassNameVisitor(const StringPiece16& package) : mPackage(package) {
+ }
+
+ void visit(xml::Element* el) override {
+ for (xml::Attribute& attr : el->attributes) {
+ if (Maybe<std::u16string> newValue =
+ util::getFullyQualifiedClassName(mPackage, attr.value)) {
+ attr.value = std::move(newValue.value());
+ }
+ }
+
+ // Super implementation to iterate over the children.
+ xml::Visitor::visit(el);
+ }
+
+private:
+ StringPiece16 mPackage;
+};
+
+static bool renameManifestPackage(IAaptContext* context, const Source& source,
+ const StringPiece16& packageOverride, xml::Element* manifestEl) {
+ if (!util::isJavaPackageName(packageOverride)) {
+ context->getDiagnostics()->error(DiagMessage() << "invalid manifest package override '"
+ << packageOverride << "'");
+ return false;
+ }
+
+ xml::Attribute* attr = manifestEl->findAttribute({}, u"package");
+
+ // We've already verified that the manifest element is present, with a package name specified.
+ assert(attr);
+
+ std::u16string originalPackage = std::move(attr->value);
+ attr->value = packageOverride.toString();
+
+ FullyQualifiedClassNameVisitor visitor(originalPackage);
+ manifestEl->accept(&visitor);
+ return true;
+}
+
+static bool renameInstrumentationTargetPackage(IAaptContext* context, const Source& source,
+ const StringPiece16& packageOverride,
+ xml::Element* manifestEl) {
+ if (!util::isJavaPackageName(packageOverride)) {
+ context->getDiagnostics()->error(DiagMessage()
+ << "invalid instrumentation target package override '"
+ << packageOverride << "'");
+ return false;
+ }
+
+ xml::Element* instrumentationEl = manifestEl->findChild({}, u"instrumentation");
+ if (!instrumentationEl) {
+ // No error if there is no work to be done.
+ return true;
+ }
+
+ xml::Attribute* attr = instrumentationEl->findAttribute(xml::kSchemaAndroid, u"targetPackage");
+ if (!attr) {
+ // No error if there is no work to be done.
+ return true;
+ }
+
+ attr->value = packageOverride.toString();
+ return true;
+}
+
bool ManifestFixer::consume(IAaptContext* context, xml::XmlResource* doc) {
xml::Element* root = xml::findRootElement(doc->root.get());
if (!root || !root->namespaceUri.empty() || root->name != u"manifest") {
@@ -74,6 +162,36 @@
return false;
}
+ if (mOptions.versionCodeDefault) {
+ if (!includeVersionCode(context, doc->file.source, mOptions.versionCodeDefault.value(),
+ root)) {
+ return false;
+ }
+ }
+
+ if (mOptions.versionNameDefault) {
+ if (!includeVersionName(context, doc->file.source, mOptions.versionNameDefault.value(),
+ root)) {
+ return false;
+ }
+ }
+
+ if (mOptions.renameManifestPackage) {
+ // Rename manifest package.
+ if (!renameManifestPackage(context, doc->file.source,
+ mOptions.renameManifestPackage.value(), root)) {
+ return false;
+ }
+ }
+
+ if (mOptions.renameInstrumentationTargetPackage) {
+ if (!renameInstrumentationTargetPackage(context, doc->file.source,
+ mOptions.renameInstrumentationTargetPackage.value(),
+ root)) {
+ return false;
+ }
+ }
+
bool foundUsesSdk = false;
for (xml::Element* el : root->getChildElements()) {
if (!el->namespaceUri.empty()) {
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index a77e6d5..b8d9c83 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -28,6 +28,10 @@
struct ManifestFixerOptions {
Maybe<std::u16string> minSdkVersionDefault;
Maybe<std::u16string> targetSdkVersionDefault;
+ Maybe<std::u16string> renameManifestPackage;
+ Maybe<std::u16string> renameInstrumentationTargetPackage;
+ Maybe<std::u16string> versionNameDefault;
+ Maybe<std::u16string> versionCodeDefault;
};
/**
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index f6bf895..f40fbfb 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -82,8 +82,6 @@
EXPECT_EQ(nullptr, verify("<manifest package=\"@string/str\" />"));
}
-
-
TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
ManifestFixerOptions options = { std::u16string(u"8"), std::u16string(u"22") };
@@ -97,7 +95,7 @@
xml::Element* el;
xml::Attribute* attr;
- el = xml::findRootElement(doc->root.get());
+ el = xml::findRootElement(doc.get());
ASSERT_NE(nullptr, el);
el = el->findChild({}, u"uses-sdk");
ASSERT_NE(nullptr, el);
@@ -115,7 +113,7 @@
</manifest>)EOF", options);
ASSERT_NE(nullptr, doc);
- el = xml::findRootElement(doc->root.get());
+ el = xml::findRootElement(doc.get());
ASSERT_NE(nullptr, el);
el = el->findChild({}, u"uses-sdk");
ASSERT_NE(nullptr, el);
@@ -133,7 +131,7 @@
</manifest>)EOF", options);
ASSERT_NE(nullptr, doc);
- el = xml::findRootElement(doc->root.get());
+ el = xml::findRootElement(doc.get());
ASSERT_NE(nullptr, el);
el = el->findChild({}, u"uses-sdk");
ASSERT_NE(nullptr, el);
@@ -149,7 +147,7 @@
package="android" />)EOF", options);
ASSERT_NE(nullptr, doc);
- el = xml::findRootElement(doc->root.get());
+ el = xml::findRootElement(doc.get());
ASSERT_NE(nullptr, el);
el = el->findChild({}, u"uses-sdk");
ASSERT_NE(nullptr, el);
@@ -161,4 +159,98 @@
EXPECT_EQ(u"22", attr->value);
}
+TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) {
+ ManifestFixerOptions options;
+ options.renameManifestPackage = std::u16string(u"com.android");
+
+ std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application name=".MainApplication" text="hello">
+ <activity name=".activity.Start" />
+ <receiver name="com.google.android.Receiver" />
+ </application>
+ </manifest>)EOF", options);
+ ASSERT_NE(nullptr, doc);
+
+ xml::Element* manifestEl = xml::findRootElement(doc.get());
+ ASSERT_NE(nullptr, manifestEl);
+
+ xml::Attribute* attr = nullptr;
+
+ attr = manifestEl->findAttribute({}, u"package");
+ ASSERT_NE(nullptr, attr);
+ EXPECT_EQ(std::u16string(u"com.android"), attr->value);
+
+ xml::Element* applicationEl = manifestEl->findChild({}, u"application");
+ ASSERT_NE(nullptr, applicationEl);
+
+ attr = applicationEl->findAttribute({}, u"name");
+ ASSERT_NE(nullptr, attr);
+ EXPECT_EQ(std::u16string(u"android.MainApplication"), attr->value);
+
+ attr = applicationEl->findAttribute({}, u"text");
+ ASSERT_NE(nullptr, attr);
+ EXPECT_EQ(std::u16string(u"hello"), attr->value);
+
+ xml::Element* el;
+ el = applicationEl->findChild({}, u"activity");
+ ASSERT_NE(nullptr, el);
+
+ attr = el->findAttribute({}, u"name");
+ ASSERT_NE(nullptr, el);
+ EXPECT_EQ(std::u16string(u"android.activity.Start"), attr->value);
+
+ el = applicationEl->findChild({}, u"receiver");
+ ASSERT_NE(nullptr, el);
+
+ attr = el->findAttribute({}, u"name");
+ ASSERT_NE(nullptr, el);
+ EXPECT_EQ(std::u16string(u"com.google.android.Receiver"), attr->value);
+}
+
+TEST_F(ManifestFixerTest, RenameManifestInstrumentationPackageAndFullyQualifyTarget) {
+ ManifestFixerOptions options;
+ options.renameInstrumentationTargetPackage = std::u16string(u"com.android");
+
+ std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <instrumentation android:targetPackage="android" />
+ </manifest>)EOF", options);
+ ASSERT_NE(nullptr, doc);
+
+ xml::Element* manifestEl = xml::findRootElement(doc.get());
+ ASSERT_NE(nullptr, manifestEl);
+
+ xml::Element* instrumentationEl = manifestEl->findChild({}, u"instrumentation");
+ ASSERT_NE(nullptr, instrumentationEl);
+
+ xml::Attribute* attr = instrumentationEl->findAttribute(xml::kSchemaAndroid, u"targetPackage");
+ ASSERT_NE(nullptr, attr);
+ EXPECT_EQ(std::u16string(u"com.android"), attr->value);
+}
+
+TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) {
+ ManifestFixerOptions options;
+ options.versionNameDefault = std::u16string(u"Beta");
+ options.versionCodeDefault = std::u16string(u"0x10000000");
+
+ std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android" />)EOF", options);
+ ASSERT_NE(nullptr, doc);
+
+ xml::Element* manifestEl = xml::findRootElement(doc.get());
+ ASSERT_NE(nullptr, manifestEl);
+
+ xml::Attribute* attr = manifestEl->findAttribute(xml::kSchemaAndroid, u"versionName");
+ ASSERT_NE(nullptr, attr);
+ EXPECT_EQ(std::u16string(u"Beta"), attr->value);
+
+ attr = manifestEl->findAttribute(xml::kSchemaAndroid, u"versionCode");
+ ASSERT_NE(nullptr, attr);
+ EXPECT_EQ(std::u16string(u"0x10000000"), attr->value);
+}
+
} // namespace aapt
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index a81dc7b..04e8199 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -163,6 +163,11 @@
}
android::FileMap fileMap;
+ if (fileStats.st_size == 0) {
+ // mmap doesn't like a length of 0. Instead we return an empty FileMap.
+ return std::move(fileMap);
+ }
+
if (!fileMap.create(path.data(), fd, 0, fileStats.st_size, true)) {
if (outError) *outError = strerror(errno);
return {};
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index 9ecc974..7b0c71d 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -175,10 +175,11 @@
return {};
}
- std::u16string result(package.data(), package.size());
if (className.data()[0] != u'.') {
- result += u'.';
+ return {};
}
+
+ std::u16string result(package.data(), package.size());
result.append(className.data(), className.size());
if (!isJavaClassName(result)) {
return {};
diff --git a/tools/aapt2/util/Util_test.cpp b/tools/aapt2/util/Util_test.cpp
index 9208e07..1e0c7fa 100644
--- a/tools/aapt2/util/Util_test.cpp
+++ b/tools/aapt2/util/Util_test.cpp
@@ -144,8 +144,7 @@
TEST(UtilTest, FullyQualifiedClassName) {
Maybe<std::u16string> res = util::getFullyQualifiedClassName(u"android", u"asdf");
- AAPT_ASSERT_TRUE(res);
- EXPECT_EQ(res.value(), u"android.asdf");
+ AAPT_ASSERT_FALSE(res);
res = util::getFullyQualifiedClassName(u"android", u".asdf");
AAPT_ASSERT_TRUE(res);
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 01ee18b..9f0153a 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -19,6 +19,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import com.android.internal.app.IAssistScreenshotReceiver;
+import com.android.internal.os.IResultReceiver;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -550,4 +551,8 @@
public void setResizeDimLayer(boolean visible, int targetStackId, float alpha)
throws RemoteException {
}
+
+ @Override
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver) throws RemoteException {
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/view/WindowCallback.java b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
index d691c8e..411417c 100644
--- a/tools/layoutlib/bridge/src/android/view/WindowCallback.java
+++ b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
@@ -16,10 +16,13 @@
package android.view;
+import android.annotation.Nullable;
import android.view.ActionMode.Callback;
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
+import java.util.List;
+
/**
* An empty implementation of {@link Window.Callback} that always returns null/false.
*/
@@ -138,4 +141,9 @@
public void onActionModeFinished(ActionMode mode) {
}
+
+ @Override
+ public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, @Nullable Menu menu) {
+
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index 3662573..48012db 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -16,6 +16,8 @@
package com.android.layoutlib.bridge.android;
+import com.android.internal.os.IResultReceiver;
+
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
@@ -95,6 +97,10 @@
}
@Override
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver) throws RemoteException {
+ }
+
+ @Override
public IBinder asBinder() {
// pass for now.
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
index 7e5ae8d..d417eb7 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
@@ -63,4 +63,9 @@
public void removeViewImmediate(View arg0) {
// pass
}
+
+ @Override
+ public void requestAppKeyboardShortcuts(
+ KeyboardShortcutsReceiver receiver) {
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index dc329e2..0c06ae8 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -24,15 +24,12 @@
import android.net.StaticIpConfiguration;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.text.TextUtils;
-import android.util.Log;
-import java.util.HashMap;
+import java.util.Arrays;
import java.util.BitSet;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
+import java.util.HashMap;
/**
* A class representing a configured Wi-Fi network, including the
@@ -182,19 +179,6 @@
}
/** @hide */
- public static final int DISABLED_UNKNOWN_REASON = 0;
- /** @hide */
- public static final int DISABLED_DNS_FAILURE = 1;
- /** @hide */
- public static final int DISABLED_DHCP_FAILURE = 2;
- /** @hide */
- public static final int DISABLED_AUTH_FAILURE = 3;
- /** @hide */
- public static final int DISABLED_ASSOCIATION_REJECT = 4;
- /** @hide */
- public static final int DISABLED_BY_WIFI_MANAGER = 5;
-
- /** @hide */
public static final int UNKNOWN_UID = -1;
/**
@@ -206,24 +190,12 @@
/**
* The current status of this network configuration entry.
+ * Fixme We need remove this field to use only Quality network selection status only
* @see Status
*/
public int status;
/**
- * The configuration needs to be written to networkHistory.txt
- * @hide
- */
- public boolean dirty;
-
- /**
- * The code referring to a reason for disabling the network
- * Valid when {@link #status} == Status.DISABLED
- * @hide
- */
- public int disableReason;
-
- /**
* The network's SSID. Can either be an ASCII string,
* which must be enclosed in double quotation marks
* (e.g., {@code "MyNetwork"}, or a string of
@@ -356,6 +328,13 @@
/**
* @hide
+ * This network configuration is visible to and usable by other users on the
+ * same device.
+ */
+ public boolean shared;
+
+ /**
+ * @hide
*/
private IpConfiguration mIpConfiguration;
@@ -421,12 +400,6 @@
/**
* @hide
- * Uid used by autoJoin
- */
- public String autoJoinBSSID;
-
- /**
- * @hide
* Status of user approval for connection
*/
public int userApproved = USER_UNSPECIFIED;
@@ -444,77 +417,6 @@
/** @hide **/
public static int INVALID_RSSI = -127;
- /** @hide **/
- public static int UNWANTED_BLACKLIST_SOFT_RSSI_24 = -80;
-
- /** @hide **/
- public static int UNWANTED_BLACKLIST_SOFT_RSSI_5 = -70;
-
- /** @hide **/
- public static int GOOD_RSSI_24 = -65;
-
- /** @hide **/
- public static int LOW_RSSI_24 = -77;
-
- /** @hide **/
- public static int BAD_RSSI_24 = -87;
-
- /** @hide **/
- public static int GOOD_RSSI_5 = -60;
-
- /** @hide **/
- public static int LOW_RSSI_5 = -72;
-
- /** @hide **/
- public static int BAD_RSSI_5 = -82;
-
- /** @hide **/
- public static int UNWANTED_BLACKLIST_SOFT_BUMP = 4;
-
- /** @hide **/
- public static int UNWANTED_BLACKLIST_HARD_BUMP = 8;
-
- /** @hide **/
- public static int UNBLACKLIST_THRESHOLD_24_SOFT = -77;
-
- /** @hide **/
- public static int UNBLACKLIST_THRESHOLD_24_HARD = -68;
-
- /** @hide **/
- public static int UNBLACKLIST_THRESHOLD_5_SOFT = -63;
-
- /** @hide **/
- public static int UNBLACKLIST_THRESHOLD_5_HARD = -56;
-
- /** @hide **/
- public static int INITIAL_AUTO_JOIN_ATTEMPT_MIN_24 = -80;
-
- /** @hide **/
- public static int INITIAL_AUTO_JOIN_ATTEMPT_MIN_5 = -70;
-
- /** @hide
- * 5GHz band is prefered low over 2.4 if the 5GHz RSSI is higher than this threshold */
- public static int A_BAND_PREFERENCE_RSSI_THRESHOLD = -65;
-
- /** @hide
- * 5GHz band is penalized if the 5GHz RSSI is lower than this threshold **/
- public static int G_BAND_PREFERENCE_RSSI_THRESHOLD = -75;
-
- /** @hide
- * Boost given to RSSI on a home network for the purpose of calculating the score
- * This adds stickiness to home networks, as defined by:
- * - less than 4 known BSSIDs
- * - PSK only
- * - TODO: add a test to verify that all BSSIDs are behind same gateway
- ***/
- public static int HOME_NETWORK_RSSI_BOOST = 5;
-
- /** @hide
- * RSSI boost for configuration which use autoJoinUseAggressiveJoinAttemptThreshold
- * To be more aggressive when initially attempting to auto join
- */
- public static int MAX_INITIAL_AUTO_JOIN_RSSI_BOOST = 8;
-
/**
* @hide
* A summary of the RSSI and Band status for that configuration
@@ -600,38 +502,6 @@
visibility = status;
}
- /** @hide */
- public static final int AUTO_JOIN_ENABLED = 0;
- /**
- * if this is set, the WifiConfiguration cannot use linkages so as to bump
- * it's relative priority.
- * - status between and 128 indicate various level of blacklisting depending
- * on the severity or frequency of the connection error
- * - deleted status indicates that the user is deleting the configuration, and so
- * although it may have been self added we will not re-self-add it, ignore it,
- * not return it to applications, and not connect to it
- * */
-
- /** @hide
- * network was temporary disabled due to bad connection, most likely due
- * to weak RSSI */
- public static final int AUTO_JOIN_TEMPORARY_DISABLED = 1;
- /** @hide
- * network was temporary disabled due to bad connection, which cant be attributed
- * to weak RSSI */
- public static final int AUTO_JOIN_TEMPORARY_DISABLED_LINK_ERRORS = 32;
- /** @hide */
- public static final int AUTO_JOIN_TEMPORARY_DISABLED_AT_SUPPLICANT = 64;
- /** @hide */
- public static final int AUTO_JOIN_DISABLED_ON_AUTH_FAILURE = 128;
- /** @hide */
- public static final int AUTO_JOIN_DISABLED_NO_CREDENTIALS = 160;
- /** @hide */
- public static final int AUTO_JOIN_DISABLED_USER_ACTION = 161;
-
- /** @hide */
- public static final int AUTO_JOIN_DELETED = 200;
-
// States for the userApproved field
/**
* @hide
@@ -656,29 +526,6 @@
/**
* @hide
- */
- public int autoJoinStatus;
-
- /**
- * @hide
- * Number of connection failures
- */
- public int numConnectionFailures;
-
- /**
- * @hide
- * Number of IP config failures
- */
- public int numIpConfigFailures;
-
- /**
- * @hide
- * Number of Auth failures
- */
- public int numAuthFailures;
-
- /**
- * @hide
* Number of reports indicating no Internet Access
*/
public int numNoInternetAccessReports;
@@ -715,12 +562,6 @@
/**
* @hide
- * Last time we blacklisted the configuration
- */
- public long blackListTimestamp;
-
- /**
- * @hide
* Last time the system was connected to this configuration.
*/
public long lastConnected;
@@ -795,18 +636,6 @@
/**
* @hide
- * Indicate that we didn't auto-join because rssi was too low
- */
- public boolean autoJoinBailedDueToLowRssi;
-
- /**
- * @hide
- * AutoJoin even though RSSI is 10dB below threshold
- */
- public int autoJoinUseAggressiveJoinAttemptThreshold;
-
- /**
- * @hide
* Number of time the scorer overrode a the priority based choice, when comparing two
* WifiConfigurations, note that since comparing WifiConfiguration happens very often
* potentially at every scan, this number might become very large, even on an idle
@@ -892,6 +721,361 @@
*/
public HashMap<String, Integer> connectChoices;
+ /** @hide
+ * Boost given to RSSI on a home network for the purpose of calculating the score
+ * This adds stickiness to home networks, as defined by:
+ * - less than 4 known BSSIDs
+ * - PSK only
+ * - TODO: add a test to verify that all BSSIDs are behind same gateway
+ ***/
+ public static final int HOME_NETWORK_RSSI_BOOST = 5;
+
+ /**
+ * @hide
+ * This class is used to contain all the information and API used for quality network selection
+ */
+ public static class NetworkSelectionStatus {
+ /**
+ * Quality Network Selection Status enable, temporary disabled, permanently disabled
+ */
+ /**
+ * This network is allowed to join Quality Network Selection
+ */
+ public static final int NETWORK_SELECTION_ENABLED = 0;
+ /**
+ * network was temporary disabled. Can be re-enabled after a time period expire
+ */
+ public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1;
+ /**
+ * network was permanently disabled.
+ */
+ public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2;
+ /**
+ * Maximum Network selection status
+ */
+ public static final int NETWORK_SELECTION_STATUS_MAX = 3;
+
+ /**
+ * Quality network selection status String (for debug purpose). Use Quality network
+ * selection status value as index to extec the corresponding debug string
+ */
+ private static final String[] QUALITY_NETWORK_SELECTION_STATUS = {
+ "NETWORK_SELECTION_ENABLED", "NETWORK_SELECTION_TEMPORARY_DISABLED",
+ "NETWORK_SELECTION_PERMANENTLY_DISABLED"};
+
+ //Quality Network disabled reasons
+ /**
+ * Default value. Means not disabled
+ */
+ public static final int NETWORK_SELECTION_ENABLE = 0;
+ /**
+ * This network is disabled because higher layer (>2) network is bad
+ */
+ public static final int DISABLED_BAD_LINK = 1;
+ /**
+ * This network is disabled because multiple association rejects
+ */
+ public static final int DISABLED_ASSOCIATION_REJECTION = 2;
+ /**
+ * This network is disabled because multiple authentication failure
+ */
+ public static final int DISABLED_AUTHENTICATION_FAILURE = 3;
+ /**
+ * This network is disabled because multiple DHCP failure
+ */
+ public static final int DISABLED_DHCP_FAILURE = 4;
+ /**
+ * This network is disabled because of security network but no credentials
+ */
+ public static final int DISABLED_DNS_FAILURE = 5;
+ /**
+ * This network is disabled because EAP-TLS failure
+ */
+ public static final int DISABLED_TLS_VERSION_MISMATCH = 6;
+ /**
+ * This network is disabled due to WifiManager disable it explicitly
+ */
+ public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 7;
+ /**
+ * This network is disabled because no Internet connected and user do not want
+ */
+ public static final int DISABLED_NO_INTERNET = 8;
+ /**
+ * This network is disabled due to WifiManager disable it explicitly
+ */
+ public static final int DISABLED_BY_WIFI_MANAGER = 9;
+ /**
+ * This Maximum disable reason value
+ */
+ public static final int NETWORK_SELECTION_DISABLED_MAX = 10;
+
+ /**
+ * Quality network selection disable reason String (for debug purpose)
+ */
+ private static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = {
+ "NETWORK_SELECTION_ENABLE", "NETWORK_SELECTION_DISABLED_BAD_LINK",
+ "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",
+ "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE",
+ "NETWORK_SELECTION_DISABLED_DHCP_FAILURE",
+ "NETWORK_SELECTION_DISABLED_DNS_FAILURE", "NETWORK_SELECTION_DISABLED_TLS_VERSION",
+ "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS",
+ "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER"};
+
+ /**
+ * Invalid time stamp for network selection disable
+ */
+ public static final long INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP = -1L;
+
+ // fields for QualityNetwork Selection
+ /**
+ * Network selection status, should be in one of three status: enable, temporaily disabled
+ * or permanently disabled
+ */
+ private int mStatus;
+
+ /**
+ * Reason for disable this network
+ */
+ private int mNetworkSelectionDisableReason;
+
+ /**
+ * Last time we temporarily disabled the configuration
+ */
+ private long mTemporarilyDisabledTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
+
+ /**
+ * counter for each Network selection disable reason
+ */
+ private int[] mNetworkSeclectionDisableCounter = new int[NETWORK_SELECTION_DISABLED_MAX];
+
+ /**
+ * return current Quality network selection status in String (for debug purpose)
+ */
+ public String getNetworkStatusString() {
+ return QUALITY_NETWORK_SELECTION_STATUS[mStatus];
+ }
+
+ private NetworkSelectionStatus() {};
+
+ /**
+ * @param reason specific error reason
+ * @return corresponding network disable reason String (for debug purpose)
+ */
+ public static String getNetworkDisableReasonString(int reason) {
+ if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
+ return QUALITY_NETWORK_SELECTION_DISABLE_REASON[reason];
+ } else {
+ return null;
+ }
+ }
+ /**
+ * @return current network disable reason in String (for debug purpose)
+ */
+ public String getNetworkDisableReasonString() {
+ return QUALITY_NETWORK_SELECTION_DISABLE_REASON[mNetworkSelectionDisableReason];
+ }
+
+ /**
+ * get current network network selection status
+ */
+ public int getNetworkSelectionStatus() {
+ return mStatus;
+ }
+ /**
+ * @return whether current network is enabled to join network selection
+ */
+ public boolean isNetworkEnabled() {
+ return mStatus == NETWORK_SELECTION_ENABLED;
+ }
+
+ /**
+ * @return whether current network is temporary disabled
+ */
+ public boolean isNetworkTemporaryDisabled() {
+ return mStatus == NETWORK_SELECTION_TEMPORARY_DISABLED;
+ }
+
+ /**
+ * return whether current network is permanently disabled
+ */
+ public boolean isNetworkPermanentlyDisabled() {
+ return mStatus == NETWORK_SELECTION_PERMANENTLY_DISABLED;
+ }
+ /**
+ * @param status network selection status to set
+ */
+ public void setNetworkSelectionStatus(int status) {
+ if (status >= 0 && status < NETWORK_SELECTION_STATUS_MAX) {
+ mStatus = status;
+ }
+ }
+ /**
+ * @return current network's disable reason
+ */
+ public int getNetworkSelectionDisableReason() {
+ return mNetworkSelectionDisableReason;
+ }
+
+ /**
+ * @param reason Network disable reason
+ */
+ public void setNetworkSelectionDisableReason(int reason) {
+ if (reason >= 0 && reason < NETWORK_SELECTION_DISABLED_MAX) {
+ mNetworkSelectionDisableReason = reason;
+ } else {
+ throw new IllegalArgumentException("Illegal reason value: " + reason);
+ }
+ }
+ /**
+ * @param reason whether current network is disabled by this reason
+ */
+ public boolean isDisabledByReason(int reason) {
+ return mNetworkSelectionDisableReason == reason;
+ }
+ /**
+ * @param timeStamp Set when current network is disabled in millisecond since January 1,
+ * 1970 00:00:00.0 UTC
+ */
+ public void setDisableTime(long timeStamp) {
+ mTemporarilyDisabledTimestamp = timeStamp;
+ }
+
+ /**
+ * @return Get when current network is disabled in millisecond since January 1,
+ * 1970 00:00:00.0 UTC
+ */
+ public long getDisableTime() {
+ return mTemporarilyDisabledTimestamp;
+ }
+
+ /**
+ * @param reason specific failure reason
+ * @exception throw IllegalArgumentException for illegal input
+ * @return counter number for specific error reason.
+ */
+ public int getDisableReasonCounter(int reason) {
+ if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
+ return mNetworkSeclectionDisableCounter[reason];
+ } else {
+ throw new IllegalArgumentException("Illegal reason value: " + reason);
+ }
+ }
+
+ /**
+ * set the counter of a specific failure reason
+ * @param reason reason for disable error
+ * @param value the counter value for this specific reason
+ * @exception throw IllegalArgumentException for illegal input
+ */
+ public void setDisableReasonCounter(int reason, int value) {
+ if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
+ mNetworkSeclectionDisableCounter[reason] = value;
+ } else {
+ throw new IllegalArgumentException("Illegal reason value: " + reason);
+ }
+ }
+
+ /**
+ * increment the counter of a specific failure reason
+ * @param reason a specific failure reason
+ * @exception throw IllegalArgumentException for illegal input
+ */
+ public void incrementDisableReasonCounter(int reason) {
+ if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
+ mNetworkSeclectionDisableCounter[reason]++;
+ } else {
+ throw new IllegalArgumentException("Illegal reason value: " + reason);
+ }
+ }
+ /**
+ * clear the counter of a specific failure reason
+ * @hide
+ * @param reason a specific failure reason
+ * @exception throw IllegalArgumentException for illegal input
+ */
+ public void clearDisableReasonCounter(int reason) {
+ if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
+ mNetworkSeclectionDisableCounter[reason] = NETWORK_SELECTION_ENABLE;
+ } else {
+ throw new IllegalArgumentException("Illegal reason value: " + reason);
+ }
+ }
+ /**
+ * clear all the failure reason counters
+ */
+ public void clearDisableReasonCounter() {
+ Arrays.fill(mNetworkSeclectionDisableCounter, NETWORK_SELECTION_ENABLE);
+ }
+
+ /**
+ * BSSID for connection to this network (through network selection procedure)
+ */
+ private String mNetworkSelectionBSSID;
+
+ /**
+ * get current network Selection BSSID
+ * @return current network Selection BSSID
+ */
+ public String getNetworkSelectionBSSID() {
+ return mNetworkSelectionBSSID;
+ }
+
+ /**
+ * set network Selection BSSID
+ * @param bssid The target BSSID for assocaition
+ */
+ public void setNetworkSelectionBSSID(String bssid) {
+ mNetworkSelectionBSSID = bssid;
+ }
+
+ public void copy(NetworkSelectionStatus source) {
+ mStatus = source.mStatus;
+ mNetworkSelectionDisableReason = source.mNetworkSelectionDisableReason;
+ for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
+ index++) {
+ mNetworkSeclectionDisableCounter[index] =
+ source.mNetworkSeclectionDisableCounter[index];
+ }
+ mTemporarilyDisabledTimestamp = source.mTemporarilyDisabledTimestamp;
+ mNetworkSelectionBSSID = source.mNetworkSelectionBSSID;
+ }
+
+ public void writeToParcel(Parcel dest) {
+ dest.writeInt(getNetworkSelectionStatus());
+ dest.writeInt(getNetworkSelectionDisableReason());
+ for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
+ index++) {
+ dest.writeInt(getDisableReasonCounter(index));
+ }
+ dest.writeLong(getDisableTime());
+ dest.writeString(getNetworkSelectionBSSID());
+ }
+
+ public void readFromParcel(Parcel in) {
+ setNetworkSelectionStatus(in.readInt());
+ setNetworkSelectionDisableReason(in.readInt());
+ for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
+ index++) {
+ setDisableReasonCounter(index, in.readInt());
+ }
+ setDisableTime(in.readLong());
+ setNetworkSelectionBSSID(in.readString());
+ }
+ }
+
+ /**
+ * @hide
+ * network selection related member
+ */
+ private final NetworkSelectionStatus mNetworkSelectionStatus = new NetworkSelectionStatus();
+
+ /**
+ * @hide
+ * @return network selection status
+ */
+ public NetworkSelectionStatus getNetworkSelectionStatus() {
+ return mNetworkSelectionStatus;
+ }
/**
* @hide
* Linked Configurations: represent the set of Wificonfigurations that are equivalent
@@ -910,7 +1094,6 @@
roamingConsortiumIds = new long[0];
priority = 0;
hiddenSSID = false;
- disableReason = DISABLED_UNKNOWN_REASON;
allowedKeyManagement = new BitSet();
allowedProtocols = new BitSet();
allowedAuthAlgorithms = new BitSet();
@@ -921,7 +1104,6 @@
wepKeys[i] = null;
}
enterpriseConfig = new WifiEnterpriseConfig();
- autoJoinStatus = AUTO_JOIN_ENABLED;
selfAdded = false;
didSelfAdd = false;
ephemeral = false;
@@ -929,6 +1111,7 @@
mIpConfiguration = new IpConfiguration();
lastUpdateUid = -1;
creatorUid = -1;
+ shared = true;
}
/**
@@ -946,10 +1129,12 @@
* @hide
*/
public boolean isLinked(WifiConfiguration config) {
- if (config.linkedConfigurations != null && linkedConfigurations != null) {
- if (config.linkedConfigurations.get(configKey()) != null
- && linkedConfigurations.get(config.configKey()) != null) {
- return true;
+ if (config != null) {
+ if (config.linkedConfigurations != null && linkedConfigurations != null) {
+ if (config.linkedConfigurations.get(configKey()) != null
+ && linkedConfigurations.get(config.configKey()) != null) {
+ return true;
+ }
}
}
return false;
@@ -964,20 +1149,6 @@
allowedKeyManagement.get(KeyMgmt.IEEE8021X);
}
- /** @hide **/
- public void setAutoJoinStatus(int status) {
- if (status < 0) status = 0;
- if (status == 0) {
- blackListTimestamp = 0;
- } else if (status > autoJoinStatus) {
- blackListTimestamp = System.currentTimeMillis();
- }
- if (status != autoJoinStatus) {
- autoJoinStatus = status;
- dirty = true;
- }
- }
-
@Override
public String toString() {
StringBuilder sbuf = new StringBuilder();
@@ -988,24 +1159,28 @@
}
sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
- append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN).
- append(" PRIO: ").append(this.priority).
- append('\n');
- if (this.numConnectionFailures > 0) {
- sbuf.append(" numConnectFailures ").append(this.numConnectionFailures).append("\n");
+ append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN)
+ .append(" PRIO: ").append(this.priority)
+ .append('\n');
+
+
+ sbuf.append(" NetworkSelectionStatus ")
+ .append(mNetworkSelectionStatus.getNetworkStatusString() + "\n");
+ if (mNetworkSelectionStatus.getNetworkSelectionDisableReason() > 0) {
+ sbuf.append(" mNetworkSelectionDisableReason ")
+ .append(mNetworkSelectionStatus.getNetworkDisableReasonString() + "\n");
+
+ for (int index = mNetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
+ index < mNetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; index++) {
+ if (mNetworkSelectionStatus.getDisableReasonCounter(index) != 0) {
+ sbuf.append(NetworkSelectionStatus.getNetworkDisableReasonString(index)
+ + " counter:" + mNetworkSelectionStatus.getDisableReasonCounter(index)
+ + "\n");
+ }
+ }
}
- if (this.numIpConfigFailures > 0) {
- sbuf.append(" numIpConfigFailures ").append(this.numIpConfigFailures).append("\n");
- }
- if (this.numAuthFailures > 0) {
- sbuf.append(" numAuthFailures ").append(this.numAuthFailures).append("\n");
- }
- if (this.autoJoinStatus > 0) {
- sbuf.append(" autoJoinStatus ").append(this.autoJoinStatus).append("\n");
- }
- if (this.disableReason > 0) {
- sbuf.append(" disableReason ").append(this.disableReason).append("\n");
- }
+
+
if (this.numAssociation > 0) {
sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
}
@@ -1094,11 +1269,15 @@
sbuf.append("IP config:\n");
sbuf.append(mIpConfiguration.toString());
- if (this.autoJoinBSSID != null) sbuf.append(" autoJoinBSSID=" + autoJoinBSSID);
+ if (mNetworkSelectionStatus.getNetworkSelectionBSSID() != null) {
+ sbuf.append(" networkSelectionBSSID="
+ + mNetworkSelectionStatus.getNetworkSelectionBSSID());
+ }
long now_ms = System.currentTimeMillis();
- if (this.blackListTimestamp != 0) {
+ if (mNetworkSelectionStatus.getDisableTime() != NetworkSelectionStatus
+ .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP) {
sbuf.append('\n');
- long diff = now_ms - this.blackListTimestamp;
+ long diff = now_ms - mNetworkSelectionStatus.getDisableTime();
if (diff <= 0) {
sbuf.append(" blackListed since <incorrect>");
} else {
@@ -1172,11 +1351,6 @@
sbuf.append('\n');
sbuf.append("triggeredJoin: ").append(this.numUserTriggeredJoinAttempts);
sbuf.append('\n');
- sbuf.append("autoJoinBailedDueToLowRssi: ").append(this.autoJoinBailedDueToLowRssi);
- sbuf.append('\n');
- sbuf.append("autoJoinUseAggressiveJoinAttemptThreshold: ");
- sbuf.append(this.autoJoinUseAggressiveJoinAttemptThreshold);
- sbuf.append('\n');
return sbuf.toString();
}
@@ -1323,6 +1497,9 @@
key = mCachedConfigKey;
} else if (providerFriendlyName != null) {
key = FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+ if (!shared) {
+ key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
+ }
} else {
if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
key = SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
@@ -1334,6 +1511,9 @@
} else {
key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
}
+ if (!shared) {
+ key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
+ }
mCachedConfigKey = key;
}
return key;
@@ -1346,27 +1526,6 @@
return configKey(false);
}
- /** @hide
- * return the config key string based on a scan result
- */
- static public String configKey(ScanResult result) {
- String key = "\"" + result.SSID + "\"";
-
- if (result.capabilities.contains("WEP")) {
- key = key + "-WEP";
- }
-
- if (result.capabilities.contains("PSK")) {
- key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK];
- }
-
- if (result.capabilities.contains("EAP")) {
- key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP];
- }
-
- return key;
- }
-
/** @hide */
public IpConfiguration getIpConfiguration() {
return mIpConfiguration;
@@ -1428,13 +1587,16 @@
return 0;
}
+ /** @hide */
+ public boolean isVisibleToUser(int userId) {
+ return shared || (UserHandle.getUserId(creatorUid) == userId);
+ }
+
/** copy constructor {@hide} */
public WifiConfiguration(WifiConfiguration source) {
if (source != null) {
networkId = source.networkId;
status = source.status;
- disableReason = source.disableReason;
- disableReason = source.disableReason;
SSID = source.SSID;
BSSID = source.BSSID;
FQDN = source.FQDN;
@@ -1442,6 +1604,7 @@
providerFriendlyName = source.providerFriendlyName;
preSharedKey = source.preSharedKey;
+ mNetworkSelectionStatus.copy(source.getNetworkSelectionStatus());
apBand = source.apBand;
apChannel = source.apChannel;
@@ -1458,7 +1621,6 @@
allowedAuthAlgorithms = (BitSet) source.allowedAuthAlgorithms.clone();
allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone();
allowedGroupCiphers = (BitSet) source.allowedGroupCiphers.clone();
-
enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
defaultGwMacAddress = source.defaultGwMacAddress;
@@ -1476,7 +1638,6 @@
linkedConfigurations.putAll(source.linkedConfigurations);
}
mCachedConfigKey = null; //force null configKey
- autoJoinStatus = source.autoJoinStatus;
selfAdded = source.selfAdded;
validatedInternetAccess = source.validatedInternetAccess;
ephemeral = source.ephemeral;
@@ -1492,16 +1653,13 @@
creatorName = source.creatorName;
lastUpdateName = source.lastUpdateName;
peerWifiConfiguration = source.peerWifiConfiguration;
- blackListTimestamp = source.blackListTimestamp;
+
lastConnected = source.lastConnected;
lastDisconnected = source.lastDisconnected;
lastConnectionFailure = source.lastConnectionFailure;
lastRoamingFailure = source.lastRoamingFailure;
lastRoamingFailureReason = source.lastRoamingFailureReason;
roamingFailureBlackListTimeMilli = source.roamingFailureBlackListTimeMilli;
- numConnectionFailures = source.numConnectionFailures;
- numIpConfigFailures = source.numIpConfigFailures;
- numAuthFailures = source.numAuthFailures;
numScorerOverride = source.numScorerOverride;
numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork;
numAssociation = source.numAssociation;
@@ -1512,16 +1670,12 @@
numTicksAtBadRSSI = source.numTicksAtBadRSSI;
numTicksAtNotHighRSSI = source.numTicksAtNotHighRSSI;
numUserTriggeredJoinAttempts = source.numUserTriggeredJoinAttempts;
- autoJoinBSSID = source.autoJoinBSSID;
- autoJoinUseAggressiveJoinAttemptThreshold
- = source.autoJoinUseAggressiveJoinAttemptThreshold;
- autoJoinBailedDueToLowRssi = source.autoJoinBailedDueToLowRssi;
- dirty = source.dirty;
userApproved = source.userApproved;
numNoInternetAccessReports = source.numNoInternetAccessReports;
noInternetAccessExpected = source.noInternetAccessExpected;
creationTime = source.creationTime;
updateTime = source.updateTime;
+ shared = source.shared;
}
}
@@ -1535,12 +1689,11 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(networkId);
dest.writeInt(status);
- dest.writeInt(disableReason);
+ mNetworkSelectionStatus.writeToParcel(dest);
dest.writeString(SSID);
dest.writeString(BSSID);
dest.writeInt(apBand);
dest.writeInt(apChannel);
- dest.writeString(autoJoinBSSID);
dest.writeString(FQDN);
dest.writeString(providerFriendlyName);
dest.writeInt(roamingConsortiumIds.length);
@@ -1568,7 +1721,6 @@
dest.writeParcelable(mIpConfiguration, flags);
dest.writeString(dhcpServer);
dest.writeString(defaultGwMacAddress);
- dest.writeInt(autoJoinStatus);
dest.writeInt(selfAdded ? 1 : 0);
dest.writeInt(didSelfAdd ? 1 : 0);
dest.writeInt(validatedInternetAccess ? 1 : 0);
@@ -1578,14 +1730,10 @@
dest.writeInt(lastUpdateUid);
dest.writeString(creatorName);
dest.writeString(lastUpdateName);
- dest.writeLong(blackListTimestamp);
dest.writeLong(lastConnectionFailure);
dest.writeLong(lastRoamingFailure);
dest.writeInt(lastRoamingFailureReason);
dest.writeLong(roamingFailureBlackListTimeMilli);
- dest.writeInt(numConnectionFailures);
- dest.writeInt(numIpConfigFailures);
- dest.writeInt(numAuthFailures);
dest.writeInt(numScorerOverride);
dest.writeInt(numScorerOverrideAndSwitchedNetwork);
dest.writeInt(numAssociation);
@@ -1596,11 +1744,10 @@
dest.writeInt(numTicksAtBadRSSI);
dest.writeInt(numTicksAtNotHighRSSI);
dest.writeInt(numUserTriggeredJoinAttempts);
- dest.writeInt(autoJoinUseAggressiveJoinAttemptThreshold);
- dest.writeInt(autoJoinBailedDueToLowRssi ? 1 : 0);
dest.writeInt(userApproved);
dest.writeInt(numNoInternetAccessReports);
dest.writeInt(noInternetAccessExpected ? 1 : 0);
+ dest.writeInt(shared ? 1 : 0);
}
/** Implement the Parcelable interface {@hide} */
@@ -1610,12 +1757,11 @@
WifiConfiguration config = new WifiConfiguration();
config.networkId = in.readInt();
config.status = in.readInt();
- config.disableReason = in.readInt();
+ config.mNetworkSelectionStatus.readFromParcel(in);
config.SSID = in.readString();
config.BSSID = in.readString();
config.apBand = in.readInt();
config.apChannel = in.readInt();
- config.autoJoinBSSID = in.readString();
config.FQDN = in.readString();
config.providerFriendlyName = in.readString();
int numRoamingConsortiumIds = in.readInt();
@@ -1640,11 +1786,9 @@
config.allowedGroupCiphers = readBitSet(in);
config.enterpriseConfig = in.readParcelable(null);
-
config.mIpConfiguration = in.readParcelable(null);
config.dhcpServer = in.readString();
config.defaultGwMacAddress = in.readString();
- config.autoJoinStatus = in.readInt();
config.selfAdded = in.readInt() != 0;
config.didSelfAdd = in.readInt() != 0;
config.validatedInternetAccess = in.readInt() != 0;
@@ -1654,14 +1798,10 @@
config.lastUpdateUid = in.readInt();
config.creatorName = in.readString();
config.lastUpdateName = in.readString();
- config.blackListTimestamp = in.readLong();
config.lastConnectionFailure = in.readLong();
config.lastRoamingFailure = in.readLong();
config.lastRoamingFailureReason = in.readInt();
config.roamingFailureBlackListTimeMilli = in.readLong();
- config.numConnectionFailures = in.readInt();
- config.numIpConfigFailures = in.readInt();
- config.numAuthFailures = in.readInt();
config.numScorerOverride = in.readInt();
config.numScorerOverrideAndSwitchedNetwork = in.readInt();
config.numAssociation = in.readInt();
@@ -1672,11 +1812,10 @@
config.numTicksAtBadRSSI = in.readInt();
config.numTicksAtNotHighRSSI = in.readInt();
config.numUserTriggeredJoinAttempts = in.readInt();
- config.autoJoinUseAggressiveJoinAttemptThreshold = in.readInt();
- config.autoJoinBailedDueToLowRssi = in.readInt() != 0;
config.userApproved = in.readInt();
config.numNoInternetAccessReports = in.readInt();
config.noInternetAccessExpected = in.readInt() != 0;
+ config.shared = in.readInt() != 0;
return config;
}