summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/accounts/AccountManager.java26
-rw-r--r--core/java/android/app/ActivityManager.java54
-rw-r--r--core/java/android/app/ActivityManagerNative.java49
-rw-r--r--core/java/android/app/ActivityThread.java64
-rw-r--r--core/java/android/app/ActivityView.java170
-rw-r--r--core/java/android/app/AlarmManager.java8
-rw-r--r--core/java/android/app/AppOpsManager.java370
-rw-r--r--core/java/android/app/ApplicationPackageManager.java95
-rw-r--r--core/java/android/app/ComposedIconInfo.aidl19
-rw-r--r--core/java/android/app/ComposedIconInfo.java149
-rw-r--r--core/java/android/app/ContextImpl.java77
-rw-r--r--core/java/android/app/DownloadManager.java40
-rw-r--r--core/java/android/app/IActivityManager.java10
-rw-r--r--core/java/android/app/IAlarmManager.aidl2
-rw-r--r--[-rwxr-xr-x]core/java/android/app/IBatteryService.aidl (renamed from core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl)18
-rw-r--r--core/java/android/app/INotificationManager.aidl3
-rw-r--r--core/java/android/app/IWallpaperManager.aidl19
-rw-r--r--core/java/android/app/IWallpaperManagerCallback.aidl5
-rw-r--r--core/java/android/app/IconPackHelper.java1071
-rw-r--r--core/java/android/app/Instrumentation.java7
-rw-r--r--core/java/android/app/LoadedApk.java5
-rw-r--r--core/java/android/app/Notification.java50
-rw-r--r--core/java/android/app/NotificationGroup.aidl19
-rw-r--r--core/java/android/app/NotificationGroup.java201
-rw-r--r--core/java/android/app/NotificationManager.java11
-rw-r--r--core/java/android/app/ResourcesManager.java492
-rw-r--r--core/java/android/app/StatusBarManager.java1
-rw-r--r--core/java/android/app/SystemServiceRegistry.java4
-rw-r--r--core/java/android/app/WallpaperManager.java202
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java20
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rw-r--r--core/java/android/app/backup/FullBackup.java15
-rwxr-xr-x[-rw-r--r--]core/java/android/bluetooth/BluetoothA2dpSink.java83
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java148
-rw-r--r--core/java/android/bluetooth/BluetoothAvrcpController.java87
-rw-r--r--core/java/android/bluetooth/BluetoothAvrcpInfo.aidl34
-rw-r--r--core/java/android/bluetooth/BluetoothAvrcpInfo.java306
-rwxr-xr-x[-rw-r--r--]core/java/android/bluetooth/BluetoothClass.java17
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java34
-rw-r--r--core/java/android/bluetooth/BluetoothDevicePicker.java8
-rw-r--r--core/java/android/bluetooth/BluetoothDun.java296
-rw-r--r--core/java/android/bluetooth/BluetoothHeadset.java158
-rw-r--r--core/java/android/bluetooth/BluetoothHeadsetClient.java54
-rw-r--r--core/java/android/bluetooth/BluetoothHeadsetClientCall.java34
-rw-r--r--core/java/android/bluetooth/BluetoothHidDevice.java502
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl21
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java72
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl21
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java99
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl21
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java82
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceCallback.java128
-rw-r--r--core/java/android/bluetooth/BluetoothInputDevice.java61
-rw-r--r--core/java/android/bluetooth/BluetoothProfile.java12
-rw-r--r--core/java/android/bluetooth/BluetoothSocket.java56
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl8
-rwxr-xr-x[-rw-r--r--]core/java/android/bluetooth/IBluetoothA2dpSink.aidl3
-rw-r--r--core/java/android/bluetooth/IBluetoothAvrcpController.aidl8
-rw-r--r--core/java/android/bluetooth/IBluetoothDun.aidl45
-rwxr-xr-xcore/java/android/bluetooth/IBluetoothHeadset.aidl2
-rw-r--r--core/java/android/bluetooth/IBluetoothHeadsetClient.aidl2
-rw-r--r--core/java/android/bluetooth/IBluetoothHidDevice.aidl39
-rw-r--r--core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl33
-rw-r--r--core/java/android/bluetooth/IBluetoothInputDevice.aidl8
-rw-r--r--core/java/android/bluetooth/IBluetoothManager.aidl6
-rw-r--r--core/java/android/content/BroadcastReceiver.java12
-rw-r--r--core/java/android/content/ContentResolver.java5
-rw-r--r--core/java/android/content/Context.java23
-rw-r--r--core/java/android/content/ContextWrapper.java21
-rw-r--r--core/java/android/content/Intent.java204
-rw-r--r--core/java/android/content/ThemeVersion.java75
-rw-r--r--core/java/android/content/pm/ActivityInfo.java13
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java20
-rw-r--r--core/java/android/content/pm/BaseThemeInfo.java111
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl14
-rw-r--r--core/java/android/content/pm/PackageInfo.java48
-rw-r--r--core/java/android/content/pm/PackageInfoLite.java3
-rw-r--r--core/java/android/content/pm/PackageItemInfo.java14
-rw-r--r--core/java/android/content/pm/PackageManager.java102
-rw-r--r--core/java/android/content/pm/PackageParser.java242
-rw-r--r--core/java/android/content/pm/PackageUserState.java6
-rw-r--r--core/java/android/content/pm/PermissionInfo.java11
-rw-r--r--core/java/android/content/pm/ThemeInfo.aidl3
-rw-r--r--core/java/android/content/pm/ThemeInfo.java65
-rw-r--r--core/java/android/content/pm/ThemeUtils.java154
-rw-r--r--core/java/android/content/res/AssetManager.java227
-rw-r--r--core/java/android/content/res/CompatibilityInfo.java3
-rw-r--r--core/java/android/content/res/Configuration.java94
-rw-r--r--core/java/android/content/res/Resources.java385
-rw-r--r--core/java/android/content/res/ResourcesKey.java19
-rw-r--r--core/java/android/content/res/ThemeConfig.java579
-rw-r--r--core/java/android/database/sqlite/SQLiteConnection.java2
-rw-r--r--core/java/android/hardware/Camera.java1545
-rw-r--r--core/java/android/hardware/SystemSensorManager.java2
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java17
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java4
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java4
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestThreadManager.java8
-rw-r--r--core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java14
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java34
-rw-r--r--core/java/android/net/ConnectivityManager.java25
-rw-r--r--core/java/android/net/IConnectivityManager.aidl5
-rw-r--r--core/java/android/net/INetworkManagementEventObserver.aidl7
-rw-r--r--core/java/android/net/INetworkPolicyManager.aidl3
-rw-r--r--core/java/android/net/INetworkStatsService.aidl1
-rw-r--r--core/java/android/net/LinkProperties.java45
-rw-r--r--core/java/android/net/NetworkPolicyManager.java55
-rw-r--r--core/java/android/net/wimax/WimaxHelper.java188
-rw-r--r--core/java/android/nfc/INfcAdapter.aidl5
-rw-r--r--core/java/android/nfc/NfcActivityManager.java64
-rw-r--r--core/java/android/nfc/cardemulation/AidGroup.java11
-rw-r--r--core/java/android/nfc/cardemulation/ApduServiceInfo.java20
-rw-r--r--core/java/android/nfc/tech/MifareClassic.java6
-rw-r--r--core/java/android/nfc/tech/NfcA.java13
-rw-r--r--core/java/android/os/BatteryManager.java160
-rw-r--r--core/java/android/os/BatteryManagerInternal.java21
-rw-r--r--core/java/android/os/BatteryProperties.java54
-rw-r--r--core/java/android/os/Environment.java11
-rw-r--r--core/java/android/os/IBatteryPropertiesRegistrar.aidl2
-rw-r--r--core/java/android/os/IDeviceIdleController.aidl1
-rw-r--r--core/java/android/os/INetworkManagementService.aidl3
-rw-r--r--core/java/android/os/IPowerManager.aidl10
-rw-r--r--core/java/android/os/PowerManager.java82
-rw-r--r--core/java/android/os/PowerManagerInternal.java13
-rw-r--r--core/java/android/os/Process.java7
-rw-r--r--core/java/android/os/RecoverySystem.java70
-rw-r--r--core/java/android/os/StrictMode.java4
-rw-r--r--core/java/android/os/UserManager.java14
-rw-r--r--core/java/android/os/storage/DiskInfo.java6
-rw-r--r--core/java/android/os/storage/IMountService.java39
-rw-r--r--core/java/android/os/storage/StorageVolume.java13
-rw-r--r--core/java/android/preference/DialogPreference.java29
-rwxr-xr-x[-rw-r--r--]core/java/android/preference/MultiSelectListPreference.java17
-rw-r--r--core/java/android/preference/Preference.java10
-rw-r--r--core/java/android/preference/PreferenceFragment.java3
-rw-r--r--core/java/android/preference/PreferenceGroup.java9
-rw-r--r--core/java/android/preference/RingtonePreference.java58
-rw-r--r--core/java/android/preference/SeekBarVolumizer.java22
-rw-r--r--core/java/android/provider/Browser.java6
-rw-r--r--core/java/android/provider/CalendarContract.java8
-rw-r--r--core/java/android/provider/CallLog.java30
-rw-r--r--core/java/android/provider/ContactsContract.java17
-rw-r--r--core/java/android/provider/Downloads.java5
-rw-r--r--core/java/android/provider/Settings.java518
-rw-r--r--core/java/android/service/dreams/DreamManagerInternal.java5
-rw-r--r--core/java/android/service/dreams/IDreamManager.aidl3
-rw-r--r--core/java/android/service/gesture/IGestureService.aidl11
-rw-r--r--core/java/android/service/voice/VoiceInteractionServiceInfo.java4
-rw-r--r--core/java/android/speech/SpeechRecognizer.java1
-rw-r--r--core/java/android/text/Layout.java56
-rw-r--r--core/java/android/text/TextLine.java18
-rw-r--r--core/java/android/text/TextUtils.java12
-rwxr-xr-xcore/java/android/text/format/DateFormat.java29
-rw-r--r--core/java/android/text/method/MetaKeyKeyListener.java31
-rw-r--r--core/java/android/util/DisplayMetrics.java43
-rw-r--r--core/java/android/util/Patterns.java40
-rw-r--r--core/java/android/util/SeempLog.java758
-rw-r--r--core/java/android/view/Display.java3
-rw-r--r--core/java/android/view/DisplayInfo.java5
-rw-r--r--core/java/android/view/IWindowManager.aidl20
-rw-r--r--core/java/android/view/IWindowSession.aidl10
-rw-r--r--core/java/android/view/InputDevice.java22
-rw-r--r--core/java/android/view/KeyEvent.java27
-rw-r--r--core/java/android/view/MotionEvent.java17
-rw-r--r--core/java/android/view/SurfaceControl.java39
-rw-r--r--core/java/android/view/ThreadedRenderer.java5
-rw-r--r--core/java/android/view/View.java15
-rw-r--r--core/java/android/view/ViewConfiguration.java2
-rw-r--r--core/java/android/view/ViewRootImpl.java12
-rw-r--r--core/java/android/view/Window.java38
-rw-r--r--core/java/android/view/WindowManager.java85
-rw-r--r--core/java/android/view/WindowManagerImpl.java2
-rw-r--r--core/java/android/view/WindowManagerPolicy.java18
-rw-r--r--core/java/android/view/WindowManagerPolicyControl.java451
-rw-r--r--core/java/android/webkit/WebChromeClient.java4
-rw-r--r--core/java/android/webkit/WebViewFactory.java17
-rw-r--r--core/java/android/widget/AbsSeekBar.java9
-rw-r--r--core/java/android/widget/FastScroller.java1
-rw-r--r--core/java/android/widget/LinearLayout.java22
-rw-r--r--core/java/android/widget/RemoteViews.java56
-rw-r--r--core/java/android/widget/TableRow.java2
-rw-r--r--core/java/android/widget/TextClock.java1
-rw-r--r--core/java/android/widget/Toast.java19
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl8
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl15
-rw-r--r--core/java/com/android/internal/app/LocalePicker.java21
-rw-r--r--core/java/com/android/internal/app/PlatLogoActivity.java9
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java20
-rw-r--r--core/java/com/android/internal/app/ResolverProxy.java146
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java89
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java90
-rw-r--r--core/java/com/android/internal/os/DeviceKeyHandler.java26
-rw-r--r--core/java/com/android/internal/os/DockBatteryStatsImpl.java56
-rw-r--r--core/java/com/android/internal/os/KernelCpuSpeedReader.java13
-rw-r--r--core/java/com/android/internal/os/ProcessCpuTracker.java4
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java5
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java10
-rw-r--r--core/java/com/android/internal/policy/IKeyguardService.aidl1
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java260
-rw-r--r--core/java/com/android/internal/util/StateMachine.java27
-rw-r--r--core/java/com/android/internal/util/cm/ActionUtils.java149
-rw-r--r--core/java/com/android/internal/util/cm/PowerMenuConstants.java50
-rw-r--r--core/java/com/android/internal/util/cm/SpamFilter.java82
-rw-r--r--core/java/com/android/internal/util/cm/palette/ColorCutQuantizer.java516
-rw-r--r--core/java/com/android/internal/util/cm/palette/ColorUtils.java299
-rw-r--r--core/java/com/android/internal/util/cm/palette/DefaultGenerator.java244
-rw-r--r--core/java/com/android/internal/util/cm/palette/Palette.java740
-rw-r--r--core/java/com/android/internal/view/RotationPolicy.java46
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl2
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java114
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java236
-rw-r--r--core/java/com/android/internal/widget/SwipeDismissLayout.java19
-rw-r--r--core/java/com/android/server/BootReceiver.java1
-rw-r--r--core/java/com/android/server/net/BaseNetworkObserver.java5
-rw-r--r--core/java/org/codeaurora/camera/Android.mk30
-rw-r--r--core/java/org/codeaurora/camera/ExtendedFace.java211
-rw-r--r--core/java/org/codeaurora/camera/org.codeaurora.camera.xml35
217 files changed, 16305 insertions, 726 deletions
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 9ef13de..eb59f6b 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -329,6 +329,7 @@ public class AccountManager {
* @return The account's password, null if none or if the account doesn't exist
*/
public String getPassword(final Account account) {
+ android.util.SeempLog.record(22);
if (account == null) throw new IllegalArgumentException("account is null");
try {
return mService.getPassword(account);
@@ -357,6 +358,7 @@ public class AccountManager {
* @return The user data, null if the account or key doesn't exist
*/
public String getUserData(final Account account, final String key) {
+ android.util.SeempLog.record(23);
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
try {
@@ -567,6 +569,7 @@ public class AccountManager {
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
return new Future2Task<String>(handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.getAuthTokenLabel(mResponse, accountType, authTokenType);
}
@@ -612,6 +615,7 @@ public class AccountManager {
if (features == null) throw new IllegalArgumentException("features is null");
return new Future2Task<Boolean>(handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.hasFeatures(mResponse, account, features, mContext.getOpPackageName());
}
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
@@ -664,6 +668,7 @@ public class AccountManager {
if (type == null) throw new IllegalArgumentException("type is null");
return new Future2Task<Account[]>(handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.getAccountsByFeatures(mResponse, type, features,
mContext.getOpPackageName());
}
@@ -707,6 +712,7 @@ public class AccountManager {
* already exists, the account is null, or another error occurs.
*/
public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
+ android.util.SeempLog.record(24);
if (account == null) throw new IllegalArgumentException("account is null");
try {
return mService.addAccountExplicitly(account, password, userdata);
@@ -777,6 +783,7 @@ public class AccountManager {
return new Future2Task<Account>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.renameAccount(mResponse, account, newName);
}
@Override
@@ -837,10 +844,12 @@ public class AccountManager {
@Deprecated
public AccountManagerFuture<Boolean> removeAccount(final Account account,
AccountManagerCallback<Boolean> callback, Handler handler) {
+ android.util.SeempLog.record(25);
if (account == null) throw new IllegalArgumentException("account is null");
return new Future2Task<Boolean>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.removeAccount(mResponse, account, false);
}
@Override
@@ -896,10 +905,12 @@ public class AccountManager {
*/
public AccountManagerFuture<Bundle> removeAccount(final Account account,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
+ android.util.SeempLog.record(28);
if (account == null) throw new IllegalArgumentException("account is null");
return new AmsTask(activity, handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(34);
mService.removeAccount(mResponse, account, activity != null);
}
}.start();
@@ -921,6 +932,7 @@ public class AccountManager {
return new Future2Task<Boolean>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.removeAccountAsUser(mResponse, account, false, userHandle.getIdentifier());
}
@Override
@@ -946,6 +958,7 @@ public class AccountManager {
throw new IllegalArgumentException("userHandle is null");
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(34);
mService.removeAccountAsUser(mResponse, account, activity != null,
userHandle.getIdentifier());
}
@@ -1062,6 +1075,7 @@ public class AccountManager {
* @param password The password to set, null to clear the password
*/
public void setPassword(final Account account, final String password) {
+ android.util.SeempLog.record(26);
if (account == null) throw new IllegalArgumentException("account is null");
try {
mService.setPassword(account, password);
@@ -1091,6 +1105,7 @@ public class AccountManager {
* @param account The account whose password to clear
*/
public void clearPassword(final Account account) {
+ android.util.SeempLog.record(27);
if (account == null) throw new IllegalArgumentException("account is null");
try {
mService.clearPassword(account);
@@ -1119,6 +1134,7 @@ public class AccountManager {
* @param value String value to set, {@code null} to clear this user data key
*/
public void setUserData(final Account account, final String key, final String value) {
+ android.util.SeempLog.record(28);
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
try {
@@ -1270,6 +1286,7 @@ public class AccountManager {
optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.getAuthToken(mResponse, account, authTokenType,
false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
optionsIn);
@@ -1438,6 +1455,7 @@ public class AccountManager {
optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
return new AmsTask(null, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.getAuthToken(mResponse, account, authTokenType,
notifyAuthFailure, false /* expectActivityLaunch */, optionsIn);
}
@@ -1498,6 +1516,7 @@ public class AccountManager {
final String authTokenType, final String[] requiredFeatures,
final Bundle addAccountOptions,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
+ android.util.SeempLog.record(29);
if (accountType == null) throw new IllegalArgumentException("accountType is null");
final Bundle optionsIn = new Bundle();
if (addAccountOptions != null) {
@@ -1507,6 +1526,7 @@ public class AccountManager {
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.addAccount(mResponse, accountType, authTokenType,
requiredFeatures, activity != null, optionsIn);
}
@@ -1531,6 +1551,7 @@ public class AccountManager {
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.addAccountAsUser(mResponse, accountType, authTokenType,
requiredFeatures, activity != null, optionsIn, userHandle.getIdentifier());
}
@@ -1578,6 +1599,7 @@ public class AccountManager {
return new Future2Task<Boolean>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(34);
mService.copyAccountToUser(
mResponse, account, UserHandle.USER_OWNER, user.getIdentifier());
}
@@ -1705,6 +1727,7 @@ public class AccountManager {
final int userId = userHandle.getIdentifier();
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.confirmCredentialsAsUser(mResponse, account, options, activity != null,
userId);
}
@@ -1817,9 +1840,11 @@ public class AccountManager {
public AccountManagerFuture<Bundle> editProperties(final String accountType,
final Activity activity, final AccountManagerCallback<Bundle> callback,
final Handler handler) {
+ android.util.SeempLog.record(30);
if (accountType == null) throw new IllegalArgumentException("accountType is null");
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.editProperties(mResponse, accountType, activity != null);
}
}.start();
@@ -2175,6 +2200,7 @@ public class AccountManager {
private volatile int mNumAccounts = 0;
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
getAccountsByTypeAndFeatures(mAccountType, mFeatures,
new AccountManagerCallback<Account[]>() {
public void run(AccountManagerFuture<Account[]> future) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 87c9efc2..0ae9187 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -41,6 +41,7 @@ import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
@@ -59,6 +60,7 @@ import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Size;
import android.util.Slog;
+
import org.xmlpull.v1.XmlSerializer;
import java.io.FileDescriptor;
@@ -525,8 +527,16 @@ public class ActivityManager {
* @hide
*/
static public boolean isHighEndGfx() {
- return !isLowRamDeviceStatic() &&
- !Resources.getSystem().getBoolean(com.android.internal.R.bool.config_avoidGfxAccel);
+ return (!isLowRamDeviceStatic() &&
+ !Resources.getSystem().getBoolean(com.android.internal.R.bool.config_avoidGfxAccel))
+ || isForcedHighEndGfx();
+ }
+
+ /**
+ * @hide
+ */
+ public static boolean isForcedHighEndGfx() {
+ return SystemProperties.getBoolean("persist.sys.force_highendgfx", false);
}
/**
@@ -1316,6 +1326,23 @@ public class ActivityManager {
}
/**
+ * Check whether the current foreground tasks belongs to a given package.
+ *
+ * @param packageName Name of the package to check for
+ *
+ * @return Whether the current foreground tasks belongs to the given package
+ * @hide
+ */
+ public boolean isPackageInForeground(String packageName) {
+ try {
+ return ActivityManagerNative.getDefault().isPackageInForeground(packageName);
+ } catch (RemoteException e) {
+ // System dead, we will be dead too soon!
+ return false;
+ }
+ }
+
+ /**
* Completely remove the given task.
*
* @param taskId Identifier of the task to be removed.
@@ -2298,6 +2325,16 @@ public class ActivityManager {
return null;
}
}
+ /**
+ * @hide
+ */
+ public Configuration getConfiguration() {
+ try {
+ return ActivityManagerNative.getDefault().getConfiguration();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
/**
* Sets the memory trim mode for a process and schedules a memory trim operation.
@@ -2988,4 +3025,17 @@ public class ActivityManager {
}
}
}
+
+ /**
+ * @throws SecurityException Throws SecurityException if the caller does
+ * not hold the {@link android.Manifest.permission#CHANGE_CONFIGURATION} permission.
+ *
+ * @hide
+ */
+ public void updateConfiguration(Configuration values) throws SecurityException {
+ try {
+ ActivityManagerNative.getDefault().updateConfiguration(values);
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index f6e0735..ff06b74 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -577,6 +577,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case GET_CALLING_PACKAGE_FOR_BROADCAST_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ boolean foreground = data.readInt() == 1 ? true : false;
+ String res = getCallingPackageForBroadcast(foreground);
+ reply.writeNoException();
+ reply.writeString(res);
+ return true;
+ }
+
case GET_CALLING_ACTIVITY_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -638,6 +647,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case IS_PACKAGE_IN_FOREGROUND_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String packageName = data.readString();
+ boolean result = isPackageInForeground(packageName);
+ reply.writeNoException();
+ reply.writeInt(result ? 1 : 0);
+ return true;
+ }
+
case GET_RECENT_TASKS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int maxNum = data.readInt();
@@ -2096,7 +2114,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
case KEYGUARD_GOING_AWAY_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
- keyguardGoingAway(data.readInt() != 0, data.readInt() != 0);
+ keyguardGoingAway(data.readInt() != 0, data.readInt() != 0, data.readInt() != 0);
reply.writeNoException();
return true;
}
@@ -3192,6 +3210,19 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
return res;
}
+ public String getCallingPackageForBroadcast(boolean foreground) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(foreground ? 1 : 0);
+ mRemote.transact(GET_CALLING_PACKAGE_FOR_BROADCAST_TRANSACTION, data, reply, 0);
+ reply.readException();
+ String res = reply.readString();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
public ComponentName getCallingActivity(IBinder token)
throws RemoteException {
Parcel data = Parcel.obtain();
@@ -3278,6 +3309,18 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
return list;
}
+ public boolean isPackageInForeground(String packageName) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(packageName);
+ mRemote.transact(IS_PACKAGE_IN_FOREGROUND_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean result = reply.readInt() != 0;
+ data.recycle();
+ reply.recycle();
+ return result;
+ }
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
int flags, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
@@ -5263,12 +5306,14 @@ class ActivityManagerProxy implements IActivityManager
}
public void keyguardGoingAway(boolean disableWindowAnimations,
- boolean keyguardGoingToNotificationShade) throws RemoteException {
+ boolean keyguardGoingToNotificationShade,
+ boolean keyguardShowingMedia) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(disableWindowAnimations ? 1 : 0);
data.writeInt(keyguardGoingToNotificationShade ? 1 : 0);
+ data.writeInt(keyguardShowingMedia ? 1 : 0);
mRemote.transact(KEYGUARD_GOING_AWAY_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index da21eaf..782dc46 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -46,6 +46,7 @@ import android.database.sqlite.SQLiteDebug;
import android.database.sqlite.SQLiteDebug.DbStats;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Typeface;
import android.hardware.display.DisplayManagerGlobal;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
@@ -78,6 +79,7 @@ import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.security.NetworkSecurityPolicy;
+import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
@@ -90,6 +92,7 @@ import android.util.Slog;
import android.util.SuperNotCalledException;
import android.view.Display;
import android.view.HardwareRenderer;
+import android.view.InflateException;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewManager;
@@ -893,9 +896,25 @@ public final class ActivityThread {
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState) throws RemoteException {
- updateProcessState(processState, false);
- receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
- sticky, sendingUser);
+ RemoteException remoteException = null;
+ if (!Binder.isProxy(receiver)) {
+ updateProcessState(processState, false);
+ try {
+ receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
+ sticky, sendingUser);
+ return;
+ } catch (RemoteException e) {
+ remoteException = e;
+ }
+ }
+ if (ordered) {
+ Slog.w(TAG, receiver + " is no longer alive");
+ ActivityManagerNative.getDefault().finishReceiver(receiver.asBinder(),
+ resultCode, dataStr, extras, true, intent.getFlags());
+ if (remoteException != null) {
+ throw remoteException;
+ }
+ }
}
@Override
@@ -1697,9 +1716,21 @@ public final class ActivityThread {
*/
Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
String[] libDirs, int displayId, Configuration overrideConfiguration,
- LoadedApk pkgInfo) {
+ LoadedApk pkgInfo, Context context, String pkgName) {
return mResourcesManager.getTopLevelResources(resDir, splitResDirs, overlayDirs, libDirs,
- displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo());
+ displayId, pkgName, overrideConfiguration, pkgInfo.getCompatibilityInfo(), context,
+ pkgInfo.getApplicationInfo().isThemeable);
+ }
+
+ /**
+ * Creates the top level resources for the given package.
+ */
+ Resources getTopLevelThemedResources(String resDir, int displayId,
+ Configuration overrideConfiguration, LoadedApk pkgInfo,
+ String pkgName, String themePkgName) {
+ return mResourcesManager.getTopLevelThemedResources(resDir, displayId, pkgName,
+ themePkgName, pkgInfo.getCompatibilityInfo(),
+ pkgInfo.getApplicationInfo().isThemeable);
}
final Handler getHandler() {
@@ -1817,8 +1848,7 @@ public final class ActivityThread {
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
- if (packageInfo == null || (packageInfo.mResources != null
- && !packageInfo.mResources.getAssets().isUpToDate())) {
+ if (packageInfo == null) {
if (localLOGV) Slog.v(TAG, (includeCode ? "Loading code package "
: "Loading resource-only package ") + aInfo.packageName
+ " (in " + (mBoundApplication != null
@@ -1844,6 +1874,10 @@ public final class ActivityThread {
new WeakReference<LoadedApk>(packageInfo));
}
}
+ if (packageInfo.mResources != null
+ && !packageInfo.mResources.getAssets().isUpToDate()) {
+ packageInfo.mResources = null;
+ }
return packageInfo;
}
}
@@ -4235,6 +4269,11 @@ public final class ActivityThread {
configDiff = mConfiguration.updateFrom(config);
config = applyCompatConfiguration(mCurDefaultDisplayDpi);
+
+ final Theme systemTheme = getSystemContext().getTheme();
+ if ((systemTheme.getChangingConfigurations() & configDiff) != 0) {
+ systemTheme.rebase();
+ }
}
ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);
@@ -4253,8 +4292,12 @@ public final class ActivityThread {
if (configDiff != 0) {
// Ask text layout engine to free its caches if there is a locale change
boolean hasLocaleConfigChange = ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0);
- if (hasLocaleConfigChange) {
+ boolean hasFontConfigChange = ((configDiff & ActivityInfo.CONFIG_THEME_FONT) != 0);
+ if (hasLocaleConfigChange || hasFontConfigChange) {
Canvas.freeTextLayoutCaches();
+ if (hasFontConfigChange) {
+ Typeface.recreateDefaults();
+ }
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Cleared TextLayout Caches");
}
}
@@ -4423,7 +4466,7 @@ public final class ActivityThread {
+ DisplayMetrics.DENSITY_DEVICE + " to "
+ mCurDefaultDisplayDpi);
DisplayMetrics.DENSITY_DEVICE = mCurDefaultDisplayDpi;
- Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
+ Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEVICE);
}
}
@@ -4523,7 +4566,8 @@ public final class ActivityThread {
}
- final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
+ final boolean is24Hr = android.text.format.DateFormat.is24HourFormat(
+ mCoreSettings.getString(Settings.System.TIME_12_24), data.config.locale);
DateFormat.set24HourTimePref(is24Hr);
View.mDebugViewAttributes =
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 9c0d931..c075ed6 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -24,8 +24,6 @@ import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.graphics.SurfaceTexture;
-import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.OperationCanceledException;
@@ -45,6 +43,17 @@ import android.view.WindowManager;
import dalvik.system.CloseGuard;
import java.lang.ref.WeakReference;
+import java.util.ArrayDeque;
+import java.util.concurrent.Executor;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.android.internal.annotations.GuardedBy;
+
/** @hide */
public class ActivityView extends ViewGroup {
@@ -53,9 +62,64 @@ public class ActivityView extends ViewGroup {
private static final int MSG_SET_SURFACE = 1;
- DisplayMetrics mMetrics = new DisplayMetrics();
+ private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
+ private static final int MINIMUM_POOL_SIZE = 1;
+ private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
+ private static final int KEEP_ALIVE = 1;
+
+ private static final ThreadFactory sThreadFactory = new ThreadFactory() {
+ private final AtomicInteger mCount = new AtomicInteger(1);
+
+ public Thread newThread(Runnable r) {
+ return new Thread(r, "ActivityView #" + mCount.getAndIncrement());
+ }
+ };
+
+ private static final BlockingQueue<Runnable> sPoolWorkQueue =
+ new LinkedBlockingQueue<Runnable>(128);
+
+ /**
+ * An {@link Executor} that can be used to execute tasks in parallel.
+ */
+ private static final Executor sExecutor = new ThreadPoolExecutor(MINIMUM_POOL_SIZE,
+ MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
+
+
+ private static class SerialExecutor implements Executor {
+ private final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
+ private Runnable mActive;
+
+ public synchronized void execute(final Runnable r) {
+ mTasks.offer(new Runnable() {
+ public void run() {
+ try {
+ r.run();
+ } finally {
+ scheduleNext();
+ }
+ }
+ });
+ if (mActive == null) {
+ scheduleNext();
+ }
+ }
+
+ protected synchronized void scheduleNext() {
+ if ((mActive = mTasks.poll()) != null) {
+ sExecutor.execute(mActive);
+ }
+ }
+ }
+
+ private final SerialExecutor mExecutor = new SerialExecutor();
+
+ private final int mDensityDpi;
private final TextureView mTextureView;
+
+ @GuardedBy("mActivityContainerLock")
private ActivityContainerWrapper mActivityContainer;
+ private Object mActivityContainerLock = new Object();
+
private Activity mActivity;
private int mWidth;
private int mHeight;
@@ -63,8 +127,6 @@ public class ActivityView extends ViewGroup {
private int mLastVisibility;
private ActivityViewCallback mActivityViewCallback;
- private HandlerThread mThread = new HandlerThread("ActivityViewThread");
- private Handler mHandler;
public ActivityView(Context context) {
this(context, null);
@@ -97,28 +159,14 @@ public class ActivityView extends ViewGroup {
+ e);
}
- mThread.start();
- mHandler = new Handler(mThread.getLooper()) {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- if (msg.what == MSG_SET_SURFACE) {
- try {
- mActivityContainer.setSurface((Surface) msg.obj, msg.arg1, msg.arg2,
- mMetrics.densityDpi);
- } catch (RemoteException e) {
- throw new RuntimeException(
- "ActivityView: Unable to set surface of ActivityContainer. " + e);
- }
- }
- }
- };
mTextureView = new TextureView(context);
mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener());
addView(mTextureView);
WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE);
- wm.getDefaultDisplay().getMetrics(mMetrics);
+ DisplayMetrics metrics = new DisplayMetrics();
+ wm.getDefaultDisplay().getMetrics(metrics);
+ mDensityDpi = metrics.densityDpi;
mLastVisibility = getVisibility();
@@ -131,15 +179,13 @@ public class ActivityView extends ViewGroup {
}
@Override
- protected void onVisibilityChanged(View changedView, int visibility) {
+ protected void onVisibilityChanged(View changedView, final int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (mSurface != null && (visibility == View.GONE || mLastVisibility == View.GONE)) {
- Message msg = Message.obtain(mHandler, MSG_SET_SURFACE);
- msg.obj = (visibility == View.GONE) ? null : mSurface;
- msg.arg1 = mWidth;
- msg.arg2 = mHeight;
- mHandler.sendMessage(msg);
+ if (DEBUG) Log.v(TAG, "visibility changed; enqueing runnable");
+ final Surface surface = (visibility == View.GONE) ? null : mSurface;
+ setSurfaceAsync(surface, mWidth, mHeight, mDensityDpi, false);
}
mLastVisibility = visibility;
}
@@ -230,8 +276,10 @@ public class ActivityView extends ViewGroup {
Log.e(TAG, "Duplicate call to release");
return;
}
- mActivityContainer.release();
- mActivityContainer = null;
+ synchronized (mActivityContainerLock) {
+ mActivityContainer.release();
+ mActivityContainer = null;
+ }
if (mSurface != null) {
mSurface.release();
@@ -241,21 +289,37 @@ public class ActivityView extends ViewGroup {
mTextureView.setSurfaceTextureListener(null);
}
- private void attachToSurfaceWhenReady() {
- final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
- if (surfaceTexture == null || mSurface != null) {
- // Either not ready to attach, or already attached.
- return;
- }
-
- mSurface = new Surface(surfaceTexture);
- try {
- mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi);
- } catch (RemoteException e) {
- mSurface.release();
- mSurface = null;
- throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " + e);
- }
+ private void setSurfaceAsync(final Surface surface, final int width, final int height,
+ final int densityDpi, final boolean callback) {
+ mExecutor.execute(new Runnable() {
+ public void run() {
+ try {
+ synchronized (mActivityContainerLock) {
+ if (mActivityContainer != null) {
+ mActivityContainer.setSurface(surface, width, height, densityDpi);
+ }
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException(
+ "ActivityView: Unable to set surface of ActivityContainer. ",
+ e);
+ }
+ if (callback) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ if (mActivityViewCallback != null) {
+ if (surface != null) {
+ mActivityViewCallback.onSurfaceAvailable(ActivityView.this);
+ } else {
+ mActivityViewCallback.onSurfaceDestroyed(ActivityView.this);
+ }
+ }
+ }
+ });
+ }
+ }
+ });
}
/**
@@ -306,10 +370,8 @@ public class ActivityView extends ViewGroup {
+ height);
mWidth = width;
mHeight = height;
- attachToSurfaceWhenReady();
- if (mActivityViewCallback != null) {
- mActivityViewCallback.onSurfaceAvailable(ActivityView.this);
- }
+ mSurface = new Surface(surfaceTexture);
+ setSurfaceAsync(mSurface, mWidth, mHeight, mDensityDpi, true);
}
@Override
@@ -329,15 +391,7 @@ public class ActivityView extends ViewGroup {
if (DEBUG) Log.d(TAG, "onSurfaceTextureDestroyed");
mSurface.release();
mSurface = null;
- try {
- mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi);
- } catch (RemoteException e) {
- throw new RuntimeException(
- "ActivityView: Unable to set surface of ActivityContainer. " + e);
- }
- if (mActivityViewCallback != null) {
- mActivityViewCallback.onSurfaceDestroyed(ActivityView.this);
- }
+ setSurfaceAsync(null, mWidth, mHeight, mDensityDpi, true);
return true;
}
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 330d730..b0afe7c 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -100,6 +100,14 @@ public class AlarmManager {
*/
public static final int ELAPSED_REALTIME = 3;
+ /** @hide
+ * Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
+ * (wall clock time in UTC), which will wake up the device when
+ * it goes off. And it will power on the devices when it shuts down.
+ * Set as 5 to make it be compatible with android_alarm_type.
+ */
+ public static final int RTC_POWEROFF_WAKEUP = 5;
+
/**
* Broadcast Action: Sent after the value returned by
* {@link #getNextAlarmClock()} has changed.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 09c0a6e..11a5ee8 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,6 +31,7 @@ import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.SystemProperties;
import android.os.UserManager;
import android.util.ArrayMap;
@@ -69,6 +73,10 @@ public class AppOpsManager {
* will do this for you).
*/
+ /** {@hide */
+ public static final String ACTION_SU_SESSION_CHANGED =
+ "android.intent.action.SU_SESSION_CHANGED";
+
final Context mContext;
final IAppOpsService mService;
final ArrayMap<OnOpChangedListener, IAppOpsCallback> mModeWatchers
@@ -103,9 +111,18 @@ public class AppOpsManager {
*/
public static final int MODE_DEFAULT = 3;
+ /**
+ * @hide Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}:
+ * AppOps Service should show a dialog box on screen to get user
+ * permission.
+ */
+ public static final int MODE_ASK = 4;
+
// when adding one of these:
// - increment _NUM_OP
- // - add rows to sOpToSwitch, sOpToString, sOpNames, sOpPerms, sOpDefaultMode
+ // - add rows to sOpToSwitch, sOpToString, sOpNames, sOpPerms, sOpDefaultMode, sOpDefaultStrictMode,
+ // sOpToOpString, sOpStrictMode.
+ // - add descriptive strings to frameworks/base/core/res/res/values/config.xml
// - add descriptive strings to Settings/res/values/arrays.xml
// - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)
@@ -237,8 +254,20 @@ public class AppOpsManager {
public static final int OP_TURN_SCREEN_ON = 61;
/** @hide Get device accounts. */
public static final int OP_GET_ACCOUNTS = 62;
+ /** @hide Wifi state change **/
+ public static final int OP_WIFI_CHANGE = 63;
+ /** @hide */
+ public static final int OP_BLUETOOTH_CHANGE = 64;
/** @hide */
- public static final int _NUM_OP = 63;
+ public static final int OP_BOOT_COMPLETED = 65;
+ /** @hide */
+ public static final int OP_NFC_CHANGE = 66;
+ /** @hide */
+ public static final int OP_DATA_CONNECT_CHANGE = 67;
+ /** @hide */
+ public static final int OP_SU = 68;
+ /** @hide */
+ public static final int _NUM_OP = 69;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -336,6 +365,19 @@ public class AppOpsManager {
/** @hide Get device accounts. */
public static final String OPSTR_GET_ACCOUNTS
= "android:get_accounts";
+ /** @hide **/
+ private static final String OPSTR_WIFI_CHANGE =
+ "android:wifi_change";
+ private static final String OPSTR_BLUETOOTH_CHANGE =
+ "android:bluetooth_change";
+ private static final String OPSTR_BOOT_COMPLETED =
+ "android:boot_completed";
+ private static final String OPSTR_NFC_CHANGE =
+ "android:nfc_change";
+ private static final String OPSTR_DATA_CONNECT_CHANGE =
+ "android:data_connect_change";
+ private static final String OPSTR_SU =
+ "android:su";
/**
* This maps each operation to the operation that serves as the
@@ -356,7 +398,7 @@ public class AppOpsManager {
OP_WRITE_CALL_LOG,
OP_READ_CALENDAR,
OP_WRITE_CALENDAR,
- OP_COARSE_LOCATION,
+ OP_WIFI_SCAN,
OP_POST_NOTIFICATION,
OP_COARSE_LOCATION,
OP_CALL_PHONE,
@@ -409,6 +451,12 @@ public class AppOpsManager {
OP_WRITE_EXTERNAL_STORAGE,
OP_TURN_SCREEN_ON,
OP_GET_ACCOUNTS,
+ OP_WIFI_CHANGE,
+ OP_BLUETOOTH_CHANGE,
+ OP_BOOT_COMPLETED,
+ OP_NFC_CHANGE,
+ OP_DATA_CONNECT_CHANGE,
+ OP_SU
};
/**
@@ -478,7 +526,13 @@ public class AppOpsManager {
OPSTR_READ_EXTERNAL_STORAGE,
OPSTR_WRITE_EXTERNAL_STORAGE,
null,
- OPSTR_GET_ACCOUNTS
+ OPSTR_GET_ACCOUNTS,
+ OPSTR_WIFI_CHANGE,
+ OPSTR_BLUETOOTH_CHANGE,
+ OPSTR_BOOT_COMPLETED,
+ OPSTR_NFC_CHANGE,
+ OPSTR_DATA_CONNECT_CHANGE,
+ OPSTR_SU,
};
/**
@@ -549,6 +603,12 @@ public class AppOpsManager {
"WRITE_EXTERNAL_STORAGE",
"TURN_ON_SCREEN",
"GET_ACCOUNTS",
+ "WIFI_CHANGE",
+ "BLUETOOTH_CHANGE",
+ "BOOT_COMPLETED",
+ "NFC_CHANGE",
+ "DATA_CONNECT_CHANGE",
+ "SU",
};
/**
@@ -566,7 +626,7 @@ public class AppOpsManager {
android.Manifest.permission.WRITE_CALL_LOG,
android.Manifest.permission.READ_CALENDAR,
android.Manifest.permission.WRITE_CALENDAR,
- android.Manifest.permission.ACCESS_WIFI_STATE,
+ null, // no permission for wifi scan available
null, // no permission required for notifications
null, // neighboring cells shares the coarse location perm
android.Manifest.permission.CALL_PHONE,
@@ -618,7 +678,13 @@ public class AppOpsManager {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
null, // no permission for turning the screen on
- Manifest.permission.GET_ACCOUNTS
+ Manifest.permission.GET_ACCOUNTS,
+ Manifest.permission.CHANGE_WIFI_STATE,
+ null,
+ Manifest.permission.RECEIVE_BOOT_COMPLETED,
+ Manifest.permission.NFC,
+ Manifest.permission.MODIFY_PHONE_STATE,
+ null,
};
/**
@@ -690,6 +756,12 @@ public class AppOpsManager {
null, // WRITE_EXTERNAL_STORAGE
null, // TURN_ON_SCREEN
null, // GET_ACCOUNTS
+ null, //WIFI_CHANGE
+ null, //BLUETOOTH_CHANGE
+ null, //BOOT_COMPLETED
+ null, //NFC_CHANGE
+ null, //DATA_CONNECT_CHANGE
+ UserManager.DISALLOW_SU, //SU TODO: this should really be investigated.
};
/**
@@ -760,6 +832,12 @@ public class AppOpsManager {
false, // WRITE_EXTERNAL_STORAGE
false, // TURN_ON_SCREEN
false, // GET_ACCOUNTS
+ true, // WIFI_CHANGE
+ true, // BLUETOOTH_CHANGE
+ true, // BOOT_COMPLETED
+ true, // NFC_CHANGE
+ true, //DATA_CONNECT_CHANGE
+ false, //SU
};
/**
@@ -829,6 +907,163 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED, // OP_TURN_ON_SCREEN
AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED, // OP_WIFI_CHANGE
+ AppOpsManager.MODE_ALLOWED, // OP_BLUETOOTH_CHANGE
+ AppOpsManager.MODE_ALLOWED, // OP_BOOT_COMPLETED
+ AppOpsManager.MODE_ALLOWED, // OP_NFC_CHANGE
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ASK, // OP_SU
+ };
+
+ /**
+ * This specifies the default mode for each strict operation.
+ */
+
+ private static int[] sOpDefaultStrictMode = new int[] {
+ AppOpsManager.MODE_ASK, // OP_COARSE_LOCATION
+ AppOpsManager.MODE_ASK, // OP_FINE_LOCATION
+ AppOpsManager.MODE_ASK, // OP_GPS
+ AppOpsManager.MODE_ALLOWED, // OP_VIBRATE
+ AppOpsManager.MODE_ASK, // OP_READ_CONTACTS
+ AppOpsManager.MODE_ASK, // OP_WRITE_CONTACTS
+ AppOpsManager.MODE_ASK, // OP_READ_CALL_LOG
+ AppOpsManager.MODE_ASK, // OP_WRITE_CALL_LOG
+ AppOpsManager.MODE_ALLOWED, // OP_READ_CALENDAR
+ AppOpsManager.MODE_ALLOWED, // OP_WRITE_CALENDAR
+ AppOpsManager.MODE_ASK, // OP_WIFI_SCAN
+ AppOpsManager.MODE_ALLOWED, // OP_POST_NOTIFICATION
+ AppOpsManager.MODE_ALLOWED, // OP_NEIGHBORING_CELLS
+ AppOpsManager.MODE_ASK, // OP_CALL_PHONE
+ AppOpsManager.MODE_ASK, // OP_READ_SMS
+ AppOpsManager.MODE_ASK, // OP_WRITE_SMS
+ AppOpsManager.MODE_ASK, // OP_RECEIVE_SMS
+ AppOpsManager.MODE_ALLOWED, // OP_RECEIVE_EMERGECY_SMS
+ AppOpsManager.MODE_ASK, // OP_RECEIVE_MMS
+ AppOpsManager.MODE_ALLOWED, // OP_RECEIVE_WAP_PUSH
+ AppOpsManager.MODE_ASK, // OP_SEND_SMS
+ AppOpsManager.MODE_ALLOWED, // OP_READ_ICC_SMS
+ AppOpsManager.MODE_ALLOWED, // OP_WRITE_ICC_SMS
+ AppOpsManager.MODE_ALLOWED, // OP_WRITE_SETTINGS
+ AppOpsManager.MODE_ALLOWED, // OP_SYSTEM_ALERT_WINDOW
+ AppOpsManager.MODE_ALLOWED, // OP_ACCESS_NOTIFICATIONS
+ AppOpsManager.MODE_ASK, // OP_CAMERA
+ AppOpsManager.MODE_ASK, // OP_RECORD_AUDIO
+ AppOpsManager.MODE_ALLOWED, // OP_PLAY_AUDIO
+ AppOpsManager.MODE_ALLOWED, // OP_READ_CLIPBOARD
+ AppOpsManager.MODE_ALLOWED, // OP_WRITE_CLIPBOARD
+ AppOpsManager.MODE_ALLOWED, // OP_TAKE_MEDIA_BUTTONS
+ AppOpsManager.MODE_ALLOWED, // OP_TAKE_AUDIO_FOCUS
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_MASTER_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_VOICE_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_RING_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_MEDIA_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_ALARM_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_NOTIFICATION_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_AUDIO_BLUETOOTH_VOLUME
+ AppOpsManager.MODE_ALLOWED, // OP_WAKE_LOCK
+ AppOpsManager.MODE_ALLOWED, // OP_MONITOR_LOCATION
+ AppOpsManager.MODE_ASK, // OP_MONITOR_HIGH_POWER_LOCATION
+ AppOpsManager.MODE_DEFAULT, // OP_GET_USAGE_STATS
+ AppOpsManager.MODE_ALLOWED, // OP_MUTE_MICROPHONE
+ AppOpsManager.MODE_ALLOWED, // OP_TOAST_WINDOW
+ AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA
+ AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN
+ AppOpsManager.MODE_ALLOWED, // OP WALLPAPER
+ AppOpsManager.MODE_ALLOWED, // OP_ASSIST_STRUCTURE
+ AppOpsManager.MODE_ALLOWED, // OP_ASSIST_SCREENSHOT
+ AppOpsManager.MODE_ALLOWED, // OP_READ_PHONE_STATE
+ AppOpsManager.MODE_ALLOWED, // OP_ADD_VOICEMAIL
+ AppOpsManager.MODE_ALLOWED, // OP_USE_SIP
+ AppOpsManager.MODE_ALLOWED, // OP_PROCESS_OUTGOING_CALLS
+ AppOpsManager.MODE_ALLOWED, // OP_USE_FINGERPRINT
+ AppOpsManager.MODE_ALLOWED, // OP_BODY_SENSORS
+ AppOpsManager.MODE_ALLOWED, // OP_READ_CELL_BROADCASTS
+ AppOpsManager.MODE_ERRORED, // OP_MOCK_LOCATION
+ AppOpsManager.MODE_ALLOWED, // OP_READ_EXTERNAL_STORAGE
+ AppOpsManager.MODE_ALLOWED, // OP_WRITE_EXTERNAL_STORAGE
+ AppOpsManager.MODE_ALLOWED, // OP_TURN_ON_SCREEN
+ AppOpsManager.MODE_ALLOWED, // OP_GET_ACCOUNTS
+ AppOpsManager.MODE_ASK, // OP_WIFI_CHANGE
+ AppOpsManager.MODE_ASK, // OP_BLUETOOTH_CHANGE
+ AppOpsManager.MODE_ALLOWED, // OP_BOOT_COMPLETED
+ AppOpsManager.MODE_ASK, // OP_NFC_CHANGE
+ AppOpsManager.MODE_ASK, // OP_DATA_CONNECT_CHANGE
+ AppOpsManager.MODE_ASK, // OP_SU
+ };
+
+ /**
+ * This specifies if operation is in strict mode.
+ */
+ private final static boolean[] sOpStrictMode = new boolean[] {
+ true, // OP_COARSE_LOCATION
+ true, // OP_FINE_LOCATION
+ true, // OP_GPS
+ false, // OP_VIBRATE
+ true, // OP_READ_CONTACTS
+ true, // OP_WRITE_CONTACTS
+ true, // OP_READ_CALL_LOG
+ true, // OP_WRITE_CALL_LOG
+ false, // OP_READ_CALENDAR
+ false, // OP_WRITE_CALENDAR
+ true, // OP_WIFI_SCAN
+ false, // OP_POST_NOTIFICATION
+ false, // OP_NEIGHBORING_CELLS
+ true, // OP_CALL_PHONE
+ true, // OP_READ_SMS
+ true, // OP_WRITE_SMS
+ false, // OP_RECEIVE_SMS
+ false, // OP_RECEIVE_EMERGECY_SMS
+ true, // OP_RECEIVE_MMS
+ false, // OP_RECEIVE_WAP_PUSH
+ true, // OP_SEND_SMS
+ false, // OP_READ_ICC_SMS
+ false, // OP_WRITE_ICC_SMS
+ false, // OP_WRITE_SETTINGS
+ false, // OP_SYSTEM_ALERT_WINDOW
+ false, // OP_ACCESS_NOTIFICATIONS
+ true, // OP_CAMERA
+ true, // OP_RECORD_AUDIO
+ false, // OP_PLAY_AUDIO
+ false, // OP_READ_CLIPBOARD
+ false, // OP_WRITE_CLIPBOARD
+ false, // OP_TAKE_MEDIA_BUTTONS
+ false, // OP_TAKE_AUDIO_FOCUS
+ false, // OP_AUDIO_MASTER_VOLUME
+ false, // OP_AUDIO_VOICE_VOLUME
+ false, // OP_AUDIO_RING_VOLUME
+ false, // OP_AUDIO_MEDIA_VOLUME
+ false, // OP_AUDIO_ALARM_VOLUME
+ false, // OP_AUDIO_NOTIFICATION_VOLUME
+ false, // OP_AUDIO_BLUETOOTH_VOLUME
+ false, // OP_WAKE_LOCK
+ false, // OP_MONITOR_LOCATION
+ true, // OP_MONITOR_HIGH_POWER_LOCATION
+ false, // OP_GET_USAGE_STATS
+ false, // OP_MUTE_MICROPHONE
+ false, // OP_TOAST_WINDOW
+ false, // OP_PROJECT_MEDIA
+ false, // OP_ACTIVATE_VPN
+ true, // OP WALLPAPER
+ false, //ASSIST_STRUCTURE
+ false, //ASSIST_SCREENSHOT
+ false, //READ_PHONE_STATE
+ false, //ADD_VOICEMAIL
+ false, // USE_SIP
+ false, // PROCESS_OUTGOING_CALLS
+ false, // USE_FINGERPRINT
+ false, // BODY_SENSORS
+ false, // READ_CELL_BROADCASTS
+ false, // MOCK_LOCATION
+ true, // READ_EXTERNAL_STORAGE
+ true, // WRITE_EXTERNAL_STORAGE
+ false, // TURN_ON_SCREEN
+ false, // GET_ACCOUNTS
+ true, // OP_WIFI_CHANGE
+ true, // OP_BLUETOOTH_CHANGE
+ false, // OP_BOOT_COMPLETED
+ true, // OP_NFC_CHANGE
+ true, // OP_DATA_CONNECT_CHANGE
+ true, // OP_SU
};
/**
@@ -901,7 +1136,13 @@ public class AppOpsManager {
false,
false,
false,
- false
+ false,
+ false, // OP_WIFI_CHANGE
+ false, // OP_BLUETOOTH_CHANGE
+ false, // OP_BOOT_COMPLETED
+ false, // OP_NFC_CHANGE
+ false, // OP_DATA_CONNECT_CHANGE
+ false, // OP_SU
};
/**
@@ -914,6 +1155,8 @@ public class AppOpsManager {
*/
private static HashMap<String, Integer> sPermToOp = new HashMap<>();
+ private static HashMap<String, Integer> sNameToOp = new HashMap<String, Integer>();
+
static {
if (sOpToSwitch.length != _NUM_OP) {
throw new IllegalStateException("sOpToSwitch length " + sOpToSwitch.length
@@ -935,6 +1178,10 @@ public class AppOpsManager {
throw new IllegalStateException("sOpDefaultMode length " + sOpDefaultMode.length
+ " should be " + _NUM_OP);
}
+ if (sOpDefaultStrictMode.length != _NUM_OP) {
+ throw new IllegalStateException("sOpDefaultStrictMode length " + sOpDefaultStrictMode.length
+ + " should be " + _NUM_OP);
+ }
if (sOpDisableReset.length != _NUM_OP) {
throw new IllegalStateException("sOpDisableReset length " + sOpDisableReset.length
+ " should be " + _NUM_OP);
@@ -947,6 +1194,10 @@ public class AppOpsManager {
throw new IllegalStateException("sOpAllowSYstemRestrictionsBypass length "
+ sOpRestrictions.length + " should be " + _NUM_OP);
}
+ if (sOpStrictMode.length != _NUM_OP) {
+ throw new IllegalStateException("sOpStrictMode length "
+ + sOpStrictMode.length + " should be " + _NUM_OP);
+ }
for (int i=0; i<_NUM_OP; i++) {
if (sOpToString[i] != null) {
sOpStrToOp.put(sOpToString[i], i);
@@ -957,6 +1208,9 @@ public class AppOpsManager {
sPermToOp.put(sOpPerms[i], i);
}
}
+ for (int i=0; i<_NUM_OP; i++) {
+ sNameToOp.put(sOpNames[i], i);
+ }
}
/**
@@ -989,6 +1243,15 @@ public class AppOpsManager {
}
/**
+ * Map a non-localized name for the operation back to the Op number
+ * @hide
+ */
+ public static int nameToOp(String name) {
+ Integer val = sNameToOp.get(name);
+ return val != null ? val : OP_NONE;
+ }
+
+ /**
* Retrieve the permission associated with an operation, or null if there is not one.
* @hide
*/
@@ -1026,7 +1289,9 @@ public class AppOpsManager {
* Retrieve the default mode for the operation.
* @hide
*/
- public static int opToDefaultMode(int op) {
+ public static int opToDefaultMode(int op, boolean isStrict) {
+ if (isStrict)
+ return sOpDefaultStrictMode[op];
return sOpDefaultMode[op];
}
@@ -1113,9 +1378,11 @@ public class AppOpsManager {
private final int mDuration;
private final int mProxyUid;
private final String mProxyPackageName;
+ private final int mAllowedCount;
+ private final int mIgnoredCount;
public OpEntry(int op, int mode, long time, long rejectTime, int duration,
- int proxyUid, String proxyPackage) {
+ int proxyUid, String proxyPackage, int allowedCount, int ignoredCount) {
mOp = op;
mMode = mode;
mTime = time;
@@ -1123,6 +1390,8 @@ public class AppOpsManager {
mDuration = duration;
mProxyUid = proxyUid;
mProxyPackageName = proxyPackage;
+ mAllowedCount = allowedCount;
+ mIgnoredCount = ignoredCount;
}
public int getOp() {
@@ -1157,6 +1426,14 @@ public class AppOpsManager {
return mProxyPackageName;
}
+ public int getAllowedCount() {
+ return mAllowedCount;
+ }
+
+ public int getIgnoredCount() {
+ return mIgnoredCount;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -1171,6 +1448,8 @@ public class AppOpsManager {
dest.writeInt(mDuration);
dest.writeInt(mProxyUid);
dest.writeString(mProxyPackageName);
+ dest.writeInt(mAllowedCount);
+ dest.writeInt(mIgnoredCount);
}
OpEntry(Parcel source) {
@@ -1181,6 +1460,8 @@ public class AppOpsManager {
mDuration = source.readInt();
mProxyUid = source.readInt();
mProxyPackageName = source.readString();
+ mAllowedCount = source.readInt();
+ mIgnoredCount = source.readInt();
}
public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
@@ -1753,4 +2034,75 @@ public class AppOpsManager {
public void finishOp(int op) {
finishOp(op, Process.myUid(), mContext.getOpPackageName());
}
+
+ /** @hide */
+ public static boolean isStrictEnable() {
+ return SystemProperties.getBoolean("persist.sys.strict_op_enable", false);
+ }
+
+ /**
+ * Check if op in strict mode
+ * @hide
+ */
+ public static boolean isStrictOp(int code) {
+ return sOpStrictMode[code];
+ }
+
+
+ /** @hide */
+ public static int stringToMode(String permission) {
+ if ("allowed".equalsIgnoreCase(permission)) {
+ return AppOpsManager.MODE_ALLOWED;
+ } else if ("ignored".equalsIgnoreCase(permission)) {
+ return AppOpsManager.MODE_IGNORED;
+ } else if ("ask".equalsIgnoreCase(permission)) {
+ return AppOpsManager.MODE_ASK;
+ }
+ return AppOpsManager.MODE_ERRORED;
+ }
+
+ /** @hide */
+ public static int stringOpToOp (String op) {
+ Integer val = sOpStrToOp.get(op);
+ if (val == null) {
+ val = OP_NONE;
+ }
+ return val;
+ }
+
+ /** @hide */
+ public boolean isControlAllowed(int op, String packageName) {
+ boolean isShow = true;
+ try {
+ isShow = mService.isControlAllowed(op, packageName);
+ } catch (RemoteException e) {
+ }
+ return isShow;
+ }
+
+ /** @hide */
+ public boolean getPrivacyGuardSettingForPackage(int uid, String packageName) {
+ try {
+ return mService.getPrivacyGuardSettingForPackage(uid, packageName);
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
+
+ /** @hide */
+ public void setPrivacyGuardSettingForPackage(int uid, String packageName,
+ boolean state) {
+ try {
+ mService.setPrivacyGuardSettingForPackage(uid, packageName, state);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /** @hide */
+ public void resetCounters() {
+ try {
+ mService.resetCounters();
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7cae745..c829daa 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -23,6 +23,7 @@ import android.annotation.StringRes;
import android.annotation.XmlRes;
import android.content.ComponentName;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
@@ -1028,12 +1029,13 @@ final class ApplicationPackageManager extends PackageManager {
if (app.packageName.equals("system")) {
return mContext.mMainThread.getSystemContext().getResources();
}
+
final boolean sameUid = (app.uid == Process.myUid());
final Resources r = mContext.mMainThread.getTopLevelResources(
sameUid ? app.sourceDir : app.publicSourceDir,
sameUid ? app.splitSourceDirs : app.splitPublicSourceDirs,
app.resourceDirs, app.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
- null, mContext.mPackageInfo);
+ null, mContext.mPackageInfo, mContext, app.packageName);
if (r != null) {
return r;
}
@@ -1069,6 +1071,49 @@ final class ApplicationPackageManager extends PackageManager {
throw new NameNotFoundException("Package " + appPackageName + " doesn't exist");
}
+ /** @hide */
+ @Override public Resources getThemedResourcesForApplication(
+ ApplicationInfo app, String themePkgName) throws NameNotFoundException {
+ if (app.packageName.equals("system")) {
+ return mContext.mMainThread.getSystemContext().getResources();
+ }
+
+ Resources r = mContext.mMainThread.getTopLevelThemedResources(
+ app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir,
+ Display.DEFAULT_DISPLAY, null, mContext.mPackageInfo, app.packageName,
+ themePkgName);
+ if (r != null) {
+ return r;
+ }
+ throw new NameNotFoundException("Unable to open " + app.publicSourceDir);
+ }
+
+ /** @hide */
+ @Override public Resources getThemedResourcesForApplication(
+ String appPackageName, String themePkgName) throws NameNotFoundException {
+ return getThemedResourcesForApplication(
+ getApplicationInfo(appPackageName, 0), themePkgName);
+ }
+
+ /** @hide */
+ @Override
+ public Resources getThemedResourcesForApplicationAsUser(String appPackageName,
+ String themePackageName, int userId) throws NameNotFoundException {
+ if (userId < 0) {
+ throw new IllegalArgumentException(
+ "Call does not support special user #" + userId);
+ }
+ try {
+ ApplicationInfo ai = mPM.getApplicationInfo(appPackageName, 0, userId);
+ if (ai != null) {
+ return getThemedResourcesForApplication(ai, themePackageName);
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ throw new NameNotFoundException("Package " + appPackageName + " doesn't exist");
+ }
+
int mCachedSafeMode = -1;
@Override public boolean isSafeMode() {
try {
@@ -1993,6 +2038,28 @@ final class ApplicationPackageManager extends PackageManager {
}
@Override
+ public void setComponentProtectedSetting(ComponentName componentName, boolean newState) {
+ try {
+ mPM.setComponentProtectedSetting(componentName, newState, mContext.getUserId());
+ } catch (RemoteException re) {
+ Log.e(TAG, "Failed to set component protected setting", re);
+ }
+ }
+
+ /** @hide */
+ @Override
+ public boolean isComponentProtected(String callingPackage, int callingUid,
+ ComponentName componentName) {
+ try {
+ return mPM.isComponentProtected(callingPackage, callingUid, componentName,
+ mContext.getUserId());
+ } catch (RemoteException re) {
+ Log.e(TAG, "Failed to get component protected setting", re);
+ return false;
+ }
+ }
+
+ @Override
public PackageInstaller getPackageInstaller() {
synchronized (mLock) {
if (mInstaller == null) {
@@ -2240,4 +2307,30 @@ final class ApplicationPackageManager extends PackageManager {
return false;
}
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public void updateIconMaps(String pkgName) {
+ try {
+ mPM.updateIconMapping(pkgName);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Failed to update icon maps", re);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int processThemeResources(String themePkgName) {
+ try {
+ return mPM.processThemeResources(themePkgName);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to process theme resources for " + themePkgName, e);
+ }
+
+ return 0;
+ }
}
diff --git a/core/java/android/app/ComposedIconInfo.aidl b/core/java/android/app/ComposedIconInfo.aidl
new file mode 100644
index 0000000..8a1bab5
--- /dev/null
+++ b/core/java/android/app/ComposedIconInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+/** @hide */
+parcelable ComposedIconInfo;
diff --git a/core/java/android/app/ComposedIconInfo.java b/core/java/android/app/ComposedIconInfo.java
new file mode 100644
index 0000000..f49c230
--- /dev/null
+++ b/core/java/android/app/ComposedIconInfo.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class ComposedIconInfo implements Parcelable {
+ public int iconUpon, iconMask;
+ public int[] iconBacks;
+ public float iconScale;
+ public float iconRotation;
+ // value used to provide some randomization to the angle of rotation
+ public float iconRotationVariance;
+ public float iconTranslationX;
+ public float iconTranslationY;
+ public int iconDensity;
+ public int iconSize;
+ public float[] colorFilter;
+
+ // Palettized background items
+ public int iconPaletteBack;
+ public SwatchType swatchType;
+ public int[] defaultSwatchColors;
+
+ public ComposedIconInfo() {
+ super();
+ iconPaletteBack = 0;
+ swatchType = SwatchType.None;
+ iconRotation = 0;
+ iconTranslationX = 0;
+ iconTranslationY = 0;
+ iconScale = 1f;
+ }
+
+ private ComposedIconInfo(Parcel source) {
+ iconScale = source.readFloat();
+ iconRotation = source.readFloat();
+ iconRotationVariance = source.readFloat();
+ iconTranslationX = source.readFloat();
+ iconTranslationY = source.readFloat();
+ iconDensity = source.readInt();
+ iconSize = source.readInt();
+ int backCount = source.readInt();
+ if (backCount > 0) {
+ iconBacks = new int[backCount];
+ for (int i = 0; i < backCount; i++) {
+ iconBacks[i] = source.readInt();
+ }
+ }
+ iconMask = source.readInt();
+ iconUpon = source.readInt();
+ int colorFilterSize = source.readInt();
+ if (colorFilterSize > 0) {
+ colorFilter = new float[colorFilterSize];
+ for (int i = 0; i < colorFilterSize; i++) {
+ colorFilter[i] = source.readFloat();
+ }
+ }
+ iconPaletteBack = source.readInt();
+ swatchType = SwatchType.values()[source.readInt()];
+ int numDefaultColors = source.readInt();
+ if (numDefaultColors > 0) {
+ defaultSwatchColors = new int[numDefaultColors];
+ for (int i = 0; i < numDefaultColors; i++) {
+ defaultSwatchColors[i] = source.readInt();
+ }
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeFloat(iconScale);
+ dest.writeFloat(iconRotation);
+ dest.writeFloat(iconRotationVariance);
+ dest.writeFloat(iconTranslationX);
+ dest.writeFloat(iconTranslationY);
+ dest.writeInt(iconDensity);
+ dest.writeInt(iconSize);
+ dest.writeInt(iconBacks != null ? iconBacks.length : 0);
+ if (iconBacks != null) {
+ for (int resId : iconBacks) {
+ dest.writeInt(resId);
+ }
+ }
+ dest.writeInt(iconMask);
+ dest.writeInt(iconUpon);
+ if (colorFilter != null) {
+ dest.writeInt(colorFilter.length);
+ for (float val : colorFilter) {
+ dest.writeFloat(val);
+ }
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeInt(iconPaletteBack);
+ dest.writeInt(swatchType.ordinal());
+ if (defaultSwatchColors != null) {
+ dest.writeInt(defaultSwatchColors.length);
+ for (int color : defaultSwatchColors) {
+ dest.writeInt(color);
+ }
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ public static final Creator<ComposedIconInfo> CREATOR
+ = new Creator<ComposedIconInfo>() {
+ @Override
+ public ComposedIconInfo createFromParcel(Parcel source) {
+ return new ComposedIconInfo(source);
+ }
+
+ @Override
+ public ComposedIconInfo[] newArray(int size) {
+ return new ComposedIconInfo[0];
+ }
+ };
+
+ public enum SwatchType {
+ None,
+ Vibrant,
+ VibrantLight,
+ VibrantDark,
+ Muted,
+ MutedLight,
+ MutedDark
+ }
+}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 235f294..6896c21 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -74,6 +74,7 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
class ReceiverRestrictedContext extends ContextWrapper {
ReceiverRestrictedContext(Context base) {
@@ -269,6 +270,15 @@ class ContextImpl extends Context {
}
@Override
+ public void recreateTheme() {
+ if (mTheme != null) {
+ Resources.Theme newTheme = mResources.newTheme();
+ newTheme.applyStyle(mThemeResource, true);
+ mTheme.setTo(newTheme);
+ }
+ }
+
+ @Override
public ClassLoader getClassLoader() {
return mPackageInfo != null ?
mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader();
@@ -1657,13 +1667,19 @@ class ContextImpl extends Context {
@Override
public Context createApplicationContext(ApplicationInfo application, int flags)
throws NameNotFoundException {
+ return createApplicationContext(application, null, flags);
+ }
+
+ @Override
+ public Context createApplicationContext(ApplicationInfo application, String themePackageName,
+ int flags) throws NameNotFoundException {
LoadedApk pi = mMainThread.getPackageInfo(application, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE);
if (pi != null) {
final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
new UserHandle(UserHandle.getUserId(application.uid)), restricted,
- mDisplay, null, Display.INVALID_DISPLAY);
+ mDisplay, null, Display.INVALID_DISPLAY, themePackageName);
if (c.mResources != null) {
return c;
}
@@ -1676,24 +1692,30 @@ class ContextImpl extends Context {
@Override
public Context createPackageContext(String packageName, int flags)
throws NameNotFoundException {
- return createPackageContextAsUser(packageName, flags,
+ return createPackageContextAsUser(packageName, null, flags,
mUser != null ? mUser : Process.myUserHandle());
}
@Override
public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
throws NameNotFoundException {
+ return createPackageContextAsUser(packageName, null, flags, user);
+ }
+
+ @Override
+ public Context createPackageContextAsUser(String packageName, String themePackageName,
+ int flags, UserHandle user) throws NameNotFoundException {
final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
if (packageName.equals("system") || packageName.equals("android")) {
return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
- user, restricted, mDisplay, null, Display.INVALID_DISPLAY);
+ user, restricted, mDisplay, null, Display.INVALID_DISPLAY, themePackageName);
}
LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
if (pi != null) {
ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
- user, restricted, mDisplay, null, Display.INVALID_DISPLAY);
+ user, restricted, mDisplay, null, Display.INVALID_DISPLAY, themePackageName);
if (c.mResources != null) {
return c;
}
@@ -1774,7 +1796,7 @@ class ContextImpl extends Context {
static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread);
ContextImpl context = new ContextImpl(null, mainThread,
- packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY);
+ packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY, null);
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetricsLocked());
return context;
@@ -1783,19 +1805,27 @@ class ContextImpl extends Context {
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
return new ContextImpl(null, mainThread,
- packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY);
+ packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY, null);
}
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, int displayId, Configuration overrideConfiguration) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
return new ContextImpl(null, mainThread, packageInfo, null, null, false,
- null, overrideConfiguration, displayId);
+ null, overrideConfiguration, displayId, null);
}
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
Display display, Configuration overrideConfiguration, int createDisplayWithId) {
+ this(container, mainThread, packageInfo, activityToken, user, restricted, display,
+ overrideConfiguration, createDisplayWithId, null);
+ }
+
+ private ContextImpl(ContextImpl container, ActivityThread mainThread,
+ LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
+ Display display, Configuration overrideConfiguration, int createDisplayWithId,
+ String themePackageName) {
mOuterContext = this;
mMainThread = mainThread;
@@ -1829,16 +1859,27 @@ class ContextImpl extends Context {
mDisplay = (createDisplayWithId == Display.INVALID_DISPLAY) ? display
: ResourcesManager.getInstance().getAdjustedDisplay(displayId, mDisplayAdjustments);
+ // We need to create the content resolver before all the context resources creation because
+ // the content resolver is reference by the outer context while the theme information
+ // is created.
+ mContentResolver = new ApplicationContentResolver(this, mainThread, user);
+
Resources resources = packageInfo.getResources(mainThread);
if (resources != null) {
if (displayId != Display.DEFAULT_DISPLAY
+ || themePackageName != null
|| overrideConfiguration != null
|| (compatInfo != null && compatInfo.applicationScale
!= resources.getCompatibilityInfo().applicationScale)) {
- resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
- packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
+ resources = themePackageName == null ? mResourcesManager.getTopLevelResources(
+ packageInfo.getResDir(), packageInfo.getSplitResDirs(),
+ packageInfo.getOverlayDirs(),
packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
- overrideConfiguration, compatInfo);
+ packageInfo.getAppDir(), overrideConfiguration, compatInfo, mOuterContext,
+ packageInfo.getApplicationInfo().isThemeable) :
+ mResourcesManager.getTopLevelThemedResources(packageInfo.getResDir(), displayId,
+ packageInfo.getPackageName(), themePackageName, compatInfo,
+ packageInfo.getApplicationInfo().isThemeable);
}
}
mResources = resources;
@@ -1859,8 +1900,6 @@ class ContextImpl extends Context {
mOpPackageName = mBasePackageName;
}
}
-
- mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}
void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
@@ -1950,9 +1989,12 @@ class ContextImpl extends Context {
* unable to create, they are filtered by replacing with {@code null}.
*/
private File[] ensureDirsExistOrFilter(File[] dirs) {
- File[] result = new File[dirs.length];
+ ArrayList<File> result = new ArrayList<File>(dirs.length);
for (int i = 0; i < dirs.length; i++) {
File dir = dirs[i];
+ if (Environment.MEDIA_REMOVED.equals(Environment.getStorageState(dir))) {
+ continue;
+ }
if (!dir.exists()) {
if (!dir.mkdirs()) {
// recheck existence in case of cross-process race
@@ -1974,9 +2016,14 @@ class ContextImpl extends Context {
}
}
}
- result[i] = dir;
+ result.add(dir);
+ }
+
+ // Make sure there is at least one element, let the callers handle that
+ if (result.size() == 0) {
+ result.add(null);
}
- return result;
+ return result.toArray(new File[result.size()]);
}
// ----------------------------------------------------------------------
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index fb0e79b..682ab97 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -266,6 +266,13 @@ public class DownloadManager {
*/
public final static int PAUSED_UNKNOWN = 4;
+ /**
+ * Value of {@link #COLUMN_REASON} when the download is paused by manual.
+ *
+ * @hide
+ */
+ public final static int PAUSED_BY_MANUAL = 5;
+
/**
* Broadcast intent action sent by the download manager when a download completes.
*/
@@ -865,6 +872,7 @@ public class DownloadManager {
parts.add(statusClause("=", Downloads.Impl.STATUS_WAITING_TO_RETRY));
parts.add(statusClause("=", Downloads.Impl.STATUS_WAITING_FOR_NETWORK));
parts.add(statusClause("=", Downloads.Impl.STATUS_QUEUED_FOR_WIFI));
+ parts.add(statusClause("=", Downloads.Impl.STATUS_PAUSED_BY_MANUAL));
}
if ((mStatusFlags & STATUS_SUCCESSFUL) != 0) {
parts.add(statusClause("=", Downloads.Impl.STATUS_SUCCESS));
@@ -1100,6 +1108,34 @@ public class DownloadManager {
}
/**
+ * Pause the given running download by manual.
+ *
+ * @param id the ID of the download to be paused
+ * @return the number of downloads actually updated
+ * @hide
+ */
+ public int pauseDownload(long id) {
+ ContentValues values = new ContentValues();
+ values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PAUSED_BY_MANUAL);
+
+ return mResolver.update(ContentUris.withAppendedId(mBaseUri, id), values, null, null);
+ }
+
+ /**
+ * Resume the given paused download by manual.
+ *
+ * @param id the ID of the download to be resumed
+ * @return the number of downloads actually updated
+ * @hide
+ */
+ public int resumeDownload(long id) {
+ ContentValues values = new ContentValues();
+ values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_RUNNING);
+
+ return mResolver.update(ContentUris.withAppendedId(mBaseUri, id), values, null, null);
+ }
+
+ /**
* Returns maximum size, in bytes, of downloads that may go over a mobile connection; or null if
* there's no limit
*
@@ -1335,6 +1371,9 @@ public class DownloadManager {
case Downloads.Impl.STATUS_QUEUED_FOR_WIFI:
return PAUSED_QUEUED_FOR_WIFI;
+ case Downloads.Impl.STATUS_PAUSED_BY_MANUAL:
+ return PAUSED_BY_MANUAL;
+
default:
return PAUSED_UNKNOWN;
}
@@ -1390,6 +1429,7 @@ public class DownloadManager {
case Downloads.Impl.STATUS_WAITING_TO_RETRY:
case Downloads.Impl.STATUS_WAITING_FOR_NETWORK:
case Downloads.Impl.STATUS_QUEUED_FOR_WIFI:
+ case Downloads.Impl.STATUS_PAUSED_BY_MANUAL:
return STATUS_PAUSED;
case Downloads.Impl.STATUS_SUCCESS:
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index ef121ce..6370268 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -122,12 +122,14 @@ public interface IActivityManager extends IInterface {
public void activitySlept(IBinder token) throws RemoteException;
public void activityDestroyed(IBinder token) throws RemoteException;
public String getCallingPackage(IBinder token) throws RemoteException;
+ public String getCallingPackageForBroadcast(boolean foreground) throws RemoteException;
public ComponentName getCallingActivity(IBinder token) throws RemoteException;
public List<IAppTask> getAppTasks(String callingPackage) throws RemoteException;
public int addAppTask(IBinder activityToken, Intent intent,
ActivityManager.TaskDescription description, Bitmap thumbnail) throws RemoteException;
public Point getAppTaskThumbnailSize() throws RemoteException;
public List<RunningTaskInfo> getTasks(int maxNum, int flags) throws RemoteException;
+ public boolean isPackageInForeground(String packageName) throws RemoteException;
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
int flags, int userId) throws RemoteException;
public ActivityManager.TaskThumbnail getTaskThumbnail(int taskId) throws RemoteException;
@@ -411,7 +413,8 @@ public interface IActivityManager extends IInterface {
public void keyguardWaitingForActivityDrawn() throws RemoteException;
public void keyguardGoingAway(boolean disableWindowAnimations,
- boolean keyguardGoingToNotificationShade) throws RemoteException;
+ boolean keyguardGoingToNotificationShade,
+ boolean keyguardShowingMedia) throws RemoteException;
public boolean shouldUpRecreateTask(IBinder token, String destAffinity)
throws RemoteException;
@@ -839,6 +842,10 @@ public interface IActivityManager extends IInterface {
int START_IN_PLACE_ANIMATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+240;
int CHECK_PERMISSION_WITH_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+241;
int REGISTER_TASK_STACK_LISTENER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+242;
+ // 243: Available
+
+ // start of CM transactions
+ int GET_CALLING_PACKAGE_FOR_BROADCAST_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+244;
// Start of M transactions
int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+280;
@@ -864,4 +871,5 @@ public interface IActivityManager extends IInterface {
= IBinder.FIRST_CALL_TRANSACTION+299;
int SHOW_ASSIST_FROM_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+300;
int IS_ROOT_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+301;
+ int IS_PACKAGE_IN_FOREGROUND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+302;
}
diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl
index 327c00b..4fdbfaa 100644
--- a/core/java/android/app/IAlarmManager.aidl
+++ b/core/java/android/app/IAlarmManager.aidl
@@ -35,6 +35,8 @@ interface IAlarmManager {
void remove(in PendingIntent operation);
long getNextWakeFromIdleTime();
AlarmManager.AlarmClockInfo getNextAlarmClock(int userId);
+ // update the uids being synchronized by network socket request manager
+ void updateBlockedUids(int uid, boolean isBlocked);
}
diff --git a/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl b/core/java/android/app/IBatteryService.aidl
index 96c59e2..196159b 100755..100644
--- a/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
+++ b/core/java/android/app/IBatteryService.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
+/**
+ * Copyright (c) 2016, The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -14,17 +14,13 @@
* limitations under the License.
*/
-package android.bluetooth;
-
-import android.content.ComponentName;
-import android.os.IBinder;
+package android.app;
/**
- * Callback for bluetooth profile connections.
+ * System private API for talking with the battery service.
*
* {@hide}
*/
-interface IBluetoothProfileServiceConnection {
- void onServiceConnected(in ComponentName comp, in IBinder service);
- void onServiceDisconnected(in ComponentName comp);
+interface IBatteryService {
+ boolean isDockBatterySupported();
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index f78fb47..e749d0a 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -55,6 +55,9 @@ interface INotificationManager
void setPackageVisibilityOverride(String pkg, int uid, int visibility);
int getPackageVisibilityOverride(String pkg, int uid);
+ void setShowNotificationForPackageOnKeyguard(String pkg, int uid, int status);
+ int getShowNotificationForPackageOnKeyguard(String pkg, int uid);
+
// TODO: Remove this when callers have been migrated to the equivalent
// INotificationListener method.
StatusBarNotification[] getActiveNotifications(String callingPkg);
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index ccba250..c717459 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -30,6 +30,12 @@ interface IWallpaperManager {
* Set the wallpaper.
*/
ParcelFileDescriptor setWallpaper(String name, in String callingPackage);
+
+ /**
+ * Set the keyguard wallpaper.
+ * @hide
+ */
+ ParcelFileDescriptor setKeyguardWallpaper(String name, in String callingPackage);
/**
* Set the live wallpaper.
@@ -46,6 +52,13 @@ interface IWallpaperManager {
*/
ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
out Bundle outParams);
+
+ /**
+ * Get the keyguard wallpaper.
+ * @hide
+ */
+ ParcelFileDescriptor getKeyguardWallpaper(IWallpaperManagerCallback cb,
+ out Bundle outParams);
/**
* Get information about a live wallpaper.
@@ -57,6 +70,12 @@ interface IWallpaperManager {
*/
void clearWallpaper(in String callingPackage);
+ /*
+ * Clear the keyguard wallpaper.
+ * @hide
+ */
+ void clearKeyguardWallpaper();
+
/**
* Return whether there is a wallpaper set with the given name.
*/
diff --git a/core/java/android/app/IWallpaperManagerCallback.aidl b/core/java/android/app/IWallpaperManagerCallback.aidl
index 991b2bc..b217318 100644
--- a/core/java/android/app/IWallpaperManagerCallback.aidl
+++ b/core/java/android/app/IWallpaperManagerCallback.aidl
@@ -28,4 +28,9 @@ oneway interface IWallpaperManagerCallback {
* Called when the wallpaper has changed
*/
void onWallpaperChanged();
+
+ /**
+ * Called when the keygaurd wallpaper has changed
+ */
+ void onKeyguardWallpaperChanged();
}
diff --git a/core/java/android/app/IconPackHelper.java b/core/java/android/app/IconPackHelper.java
new file mode 100644
index 0000000..9c71ddd
--- /dev/null
+++ b/core/java/android/app/IconPackHelper.java
@@ -0,0 +1,1071 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import android.content.pm.PackageInfo;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.PaintDrawable;
+import android.graphics.drawable.VectorDrawable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.util.TypedValue;
+
+import com.android.internal.util.cm.palette.Palette;
+
+import org.cyanogenmod.internal.themes.IIconCacheManager;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ThemeUtils;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+
+/** @hide */
+public class IconPackHelper {
+ private static final String TAG = IconPackHelper.class.getSimpleName();
+
+ private static final boolean DEBUG = false;
+
+ private static final String ICON_MASK_TAG = "iconmask";
+ private static final String ICON_BACK_TAG = "iconback";
+ private static final String ICON_UPON_TAG = "iconupon";
+ private static final String ICON_SCALE_TAG = "scale";
+ private static final String ICON_ROTATE_TAG = "rotate";
+ private static final String ICON_TRANSLATE_TAG = "translate";
+ private static final String ICON_BACK_FORMAT = "iconback%d";
+
+ // Palettized icon background constants
+ private static final String ICON_PALETTIZED_BACK_TAG = "paletteback";
+ private static final String IMG_ATTR = "img";
+ private static final String SWATCH_TYPE_ATTR = "swatchType";
+ private static final String DEFAULT_SWATCH_COLOR_ATTR = "defaultSwatchColor";
+ private static final String VIBRANT_VALUE = "vibrant";
+ private static final String VIBRANT_LIGHT_VALUE = "vibrantLight";
+ private static final String VIBRANT_DARK_VALUE = "vibrantDark";
+ private static final String MUTED_VALUE = "muted";
+ private static final String MUTED_LIGHT_VALUE = "mutedLight";
+ private static final String MUTED_DARK_VALUE = "mutedDark";
+ private static final int NUM_PALETTE_COLORS = 32;
+
+ // Rotation and translation constants
+ private static final String ANGLE_ATTR = "angle";
+ private static final String ANGLE_VARIANCE = "plusMinus";
+ private static final String TRANSLATE_X_ATTR = "xOffset";
+ private static final String TRANSLATE_Y_ATTR = "yOffset";
+
+ private static final ComponentName ICON_BACK_COMPONENT;
+ private static final ComponentName ICON_MASK_COMPONENT;
+ private static final ComponentName ICON_UPON_COMPONENT;
+ private static final ComponentName ICON_SCALE_COMPONENT;
+
+ private static final float DEFAULT_SCALE = 1.0f;
+ private static final int COMPOSED_ICON_COOKIE = 128;
+
+ private static final String ICON_CACHE_SERVICE = "cmiconcache";
+
+ public static final String SYSTEM_THEME_PATH = "/data/system/theme";
+ public static final String SYSTEM_THEME_ICON_CACHE_DIR = SYSTEM_THEME_PATH
+ + File.separator + "icons";
+
+ private final Context mContext;
+ private Map<ComponentName, String> mIconPackResourceMap;
+ private String mLoadedIconPackName;
+ private Resources mLoadedIconPackResource;
+ private ComposedIconInfo mComposedIconInfo;
+ private int mIconBackCount = 0;
+ private ColorFilterUtils.Builder mFilterBuilder;
+
+ static {
+ ICON_BACK_COMPONENT = new ComponentName(ICON_BACK_TAG, "");
+ ICON_MASK_COMPONENT = new ComponentName(ICON_MASK_TAG, "");
+ ICON_UPON_COMPONENT = new ComponentName(ICON_UPON_TAG, "");
+ ICON_SCALE_COMPONENT = new ComponentName(ICON_SCALE_TAG, "");
+ }
+
+ public IconPackHelper(Context context) {
+ mContext = context;
+ mIconPackResourceMap = new HashMap<ComponentName, String>();
+ ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ mComposedIconInfo = new ComposedIconInfo();
+ mComposedIconInfo.iconSize = am.getLauncherLargeIconSize();
+ mComposedIconInfo.iconDensity = am.getLauncherLargeIconDensity();
+ mFilterBuilder = new ColorFilterUtils.Builder();
+ }
+
+ private void loadResourcesFromXmlParser(XmlPullParser parser,
+ Map<ComponentName, String> iconPackResources)
+ throws XmlPullParserException, IOException {
+ mIconBackCount = 0;
+ int eventType = parser.getEventType();
+ do {
+
+ if (eventType != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if (parseComposedIconComponent(parser, iconPackResources)) {
+ continue;
+ }
+
+ if (ColorFilterUtils.parseIconFilter(parser, mFilterBuilder)) {
+ continue;
+ }
+
+ if (parser.getName().equalsIgnoreCase(ICON_SCALE_TAG)) {
+ String factor = parser.getAttributeValue(null, "factor");
+ if (factor == null) {
+ if (parser.getAttributeCount() == 1) {
+ factor = parser.getAttributeValue(0);
+ }
+ }
+ iconPackResources.put(ICON_SCALE_COMPONENT, factor);
+ continue;
+ }
+
+ if (parseRotationComponent(parser, mComposedIconInfo)) {
+ continue;
+ }
+
+ if (parseTranslationComponent(parser, mComposedIconInfo)) {
+ continue;
+ }
+
+ if (!parser.getName().equalsIgnoreCase("item")) {
+ continue;
+ }
+
+ String component = parser.getAttributeValue(null, "component");
+ String drawable = parser.getAttributeValue(null, "drawable");
+
+ // Validate component/drawable exist
+ if (TextUtils.isEmpty(component) || TextUtils.isEmpty(drawable)) {
+ continue;
+ }
+
+ // Validate format/length of component
+ if (!component.startsWith("ComponentInfo{") || !component.endsWith("}")
+ || component.length() < 16 || drawable.length() == 0) {
+ continue;
+ }
+
+ // Sanitize stored value
+ component = component.substring(14, component.length() - 1).toLowerCase();
+
+ ComponentName name = null;
+ if (!component.contains("/")) {
+ // Package icon reference
+ name = new ComponentName(component.toLowerCase(), "");
+ } else {
+ name = ComponentName.unflattenFromString(component);
+ }
+
+ if (name != null) {
+ iconPackResources.put(name, drawable);
+ }
+ } while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT);
+ }
+
+ private boolean isComposedIconComponent(String tag) {
+ return ICON_MASK_TAG.equalsIgnoreCase(tag) ||
+ ICON_BACK_TAG.equalsIgnoreCase(tag) ||
+ ICON_UPON_TAG.equalsIgnoreCase(tag) ||
+ ICON_PALETTIZED_BACK_TAG.equalsIgnoreCase(tag);
+ }
+
+ private boolean parseComposedIconComponent(XmlPullParser parser,
+ Map<ComponentName, String> iconPackResources) {
+ String icon;
+ String tag = parser.getName();
+ if (!isComposedIconComponent(tag)) {
+ return false;
+ }
+
+ if (parser.getAttributeCount() >= 1) {
+ if (ICON_BACK_TAG.equalsIgnoreCase(tag)) {
+ mIconBackCount = parser.getAttributeCount();
+ for (int i = 0; i < mIconBackCount; i++) {
+ tag = String.format(ICON_BACK_FORMAT, i);
+ icon = parser.getAttributeValue(i);
+ iconPackResources.put(new ComponentName(tag, ""), icon);
+ }
+ } else if (ICON_PALETTIZED_BACK_TAG.equalsIgnoreCase(tag)) {
+ parsePalettizedBackground(parser, mComposedIconInfo);
+ } else {
+ icon = parser.getAttributeValue(0);
+ iconPackResources.put(new ComponentName(tag, ""),
+ icon);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ private void parsePalettizedBackground(XmlPullParser parser, ComposedIconInfo iconInfo) {
+ int attrCount = parser.getAttributeCount();
+ ArrayList<Integer> convertedColors = new ArrayList<Integer>();
+ for (int i = 0; i < attrCount; i++) {
+ String name = parser.getAttributeName(i);
+ String value = parser.getAttributeValue(i);
+ if (TextUtils.isEmpty(name)) {
+ Log.w(TAG, "Attribute name cannot be empty or null");
+ continue;
+ }
+ if (TextUtils.isEmpty(value)) {
+ Log.w(TAG, "Attribute value cannot be empty or null");
+ continue;
+ }
+ if (IMG_ATTR.equalsIgnoreCase(name)) {
+ iconInfo.iconPaletteBack = getResourceIdForDrawable(value);
+ if (DEBUG) {
+ Log.d(TAG, String.format("img=%s, resId=%d", value,
+ iconInfo.iconPaletteBack));
+ }
+ } else if (SWATCH_TYPE_ATTR.equalsIgnoreCase(name)) {
+ ComposedIconInfo.SwatchType type = ComposedIconInfo.SwatchType.None;
+ if (VIBRANT_VALUE.equalsIgnoreCase(value)) {
+ type = ComposedIconInfo.SwatchType.Vibrant;
+ } else if (VIBRANT_LIGHT_VALUE.equalsIgnoreCase(value)) {
+ type = ComposedIconInfo.SwatchType.VibrantLight;
+ } else if (VIBRANT_DARK_VALUE.equalsIgnoreCase(value)) {
+ type = ComposedIconInfo.SwatchType.VibrantDark;
+ } else if (MUTED_VALUE.equalsIgnoreCase(value)) {
+ type = ComposedIconInfo.SwatchType.Muted;
+ } else if (MUTED_LIGHT_VALUE.equalsIgnoreCase(value)) {
+ type = ComposedIconInfo.SwatchType.MutedLight;
+ } else if (MUTED_DARK_VALUE.equalsIgnoreCase(value)) {
+ type = ComposedIconInfo.SwatchType.MutedDark;
+ }
+ if (type != ComposedIconInfo.SwatchType.None) {
+ iconInfo.swatchType = type;
+ if (DEBUG) Log.d(TAG, "PaletteType=" + type);
+ }
+ } else if (name.startsWith(DEFAULT_SWATCH_COLOR_ATTR)) {
+ try {
+ // ensure alpha is always 0xff
+ convertedColors.add(Color.parseColor(value) | 0xff000000);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Invalid color format", e);
+ }
+ }
+ if (convertedColors.size() > 0) {
+ iconInfo.defaultSwatchColors = new int[convertedColors.size()];
+ for (int j = 0; j < convertedColors.size(); j++) {
+ iconInfo.defaultSwatchColors[j] = convertedColors.get(j);
+ }
+ }
+ }
+ }
+
+ private boolean parseRotationComponent(XmlPullParser parser, ComposedIconInfo iconInfo) {
+ if (!parser.getName().equalsIgnoreCase(ICON_ROTATE_TAG)) return false;
+ String angle = parser.getAttributeValue(null, ANGLE_ATTR);
+ String variance = parser.getAttributeValue(null, ANGLE_VARIANCE);
+ if (angle != null) {
+ try {
+ iconInfo.iconRotation = Float.valueOf(angle);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Error parsing " + ANGLE_ATTR, e);
+ }
+ }
+ if (variance != null) {
+ try {
+ iconInfo.iconRotationVariance = Float.valueOf(variance);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Error parsing " + ANGLE_VARIANCE, e);
+ }
+ }
+ return true;
+ }
+
+ private boolean parseTranslationComponent(XmlPullParser parser, ComposedIconInfo iconInfo) {
+ if (!parser.getName().equalsIgnoreCase(ICON_TRANSLATE_TAG)) return false;
+
+ final float density = mContext.getResources().getDisplayMetrics().density;
+ String translateX = parser.getAttributeValue(null, TRANSLATE_X_ATTR);
+ String translateY = parser.getAttributeValue(null, TRANSLATE_Y_ATTR);
+ if (translateX != null) {
+ try {
+ iconInfo.iconTranslationX = Float.valueOf(translateX) * density;
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Error parsing " + TRANSLATE_X_ATTR, e);
+ }
+ }
+ if (translateY != null) {
+ try {
+ iconInfo.iconTranslationY = Float.valueOf(translateY) * density;
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Error parsing " + TRANSLATE_Y_ATTR, e);
+ }
+ }
+ return true;
+ }
+
+ public void loadIconPack(String packageName) throws NameNotFoundException {
+ if (packageName == null) {
+ mLoadedIconPackResource = null;
+ mLoadedIconPackName = null;
+ mComposedIconInfo.iconBacks = null;
+ mComposedIconInfo.iconMask = mComposedIconInfo.iconUpon = 0;
+ mComposedIconInfo.iconScale = 0;
+ mComposedIconInfo.iconRotation = 0;
+ mComposedIconInfo.iconTranslationX = 0;
+ mComposedIconInfo.iconTranslationY = 0;
+ mComposedIconInfo.colorFilter = null;
+ mComposedIconInfo.iconPaletteBack = 0;
+ mComposedIconInfo.swatchType = ComposedIconInfo.SwatchType.None;
+ } else {
+ mIconBackCount = 0;
+ Resources res = createIconResource(mContext, packageName);
+ mLoadedIconPackResource = res;
+ mLoadedIconPackName = packageName;
+ mIconPackResourceMap = getIconResMapFromXml(res, packageName);
+ loadComposedIconComponents();
+ ColorMatrix cm = mFilterBuilder.build();
+ if (cm != null) {
+ mComposedIconInfo.colorFilter = cm.getArray().clone();
+ }
+ }
+ }
+
+ public ComposedIconInfo getComposedIconInfo() {
+ return mComposedIconInfo;
+ }
+
+ private void loadComposedIconComponents() {
+ mComposedIconInfo.iconMask = getResourceIdForName(ICON_MASK_COMPONENT);
+ mComposedIconInfo.iconUpon = getResourceIdForName(ICON_UPON_COMPONENT);
+
+ // Take care of loading iconback which can have multiple images
+ if (mIconBackCount > 0) {
+ mComposedIconInfo.iconBacks = new int[mIconBackCount];
+ for (int i = 0; i < mIconBackCount; i++) {
+ mComposedIconInfo.iconBacks[i] =
+ getResourceIdForName(
+ new ComponentName(String.format(ICON_BACK_FORMAT, i), ""));
+ }
+ }
+
+ // Get the icon scale from this pack
+ String scale = mIconPackResourceMap.get(ICON_SCALE_COMPONENT);
+ if (scale != null) {
+ try {
+ mComposedIconInfo.iconScale = Float.valueOf(scale);
+ } catch (NumberFormatException e) {
+ mComposedIconInfo.iconScale = DEFAULT_SCALE;
+ }
+ } else {
+ mComposedIconInfo.iconScale = DEFAULT_SCALE;
+ }
+ }
+
+ private int getResourceIdForName(ComponentName component) {
+ String item = mIconPackResourceMap.get(component);
+ if (!TextUtils.isEmpty(item)) {
+ return getResourceIdForDrawable(item);
+ }
+ return 0;
+ }
+
+ public static Resources createIconResource(Context context, String packageName)
+ throws NameNotFoundException {
+ PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
+ String themeApk = info.applicationInfo.publicSourceDir;
+
+ String prefixPath;
+ String iconApkPath;
+ if (info.isLegacyIconPackApk) {
+ iconApkPath = "";
+ prefixPath = "";
+ } else {
+ prefixPath = ThemeUtils.ICONS_PATH; //path inside APK
+ iconApkPath = ThemeUtils.getIconPackApkPath(packageName);
+ }
+
+ AssetManager assets = new AssetManager();
+ assets.addIconPath(themeApk, iconApkPath,
+ prefixPath, Resources.THEME_ICON_PKG_ID);
+
+ DisplayMetrics dm = context.getResources().getDisplayMetrics();
+ Configuration config = context.getResources().getConfiguration();
+ Resources res = new Resources(assets, dm, config);
+ return res;
+ }
+
+ public Map<ComponentName, String> getIconResMapFromXml(Resources res, String packageName) {
+ XmlPullParser parser = null;
+ InputStream inputStream = null;
+ Map<ComponentName, String> iconPackResources = new HashMap<ComponentName, String>();
+
+ try {
+ inputStream = res.getAssets().open("appfilter.xml");
+ XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ parser = factory.newPullParser();
+ parser.setInput(inputStream, "UTF-8");
+ } catch (Exception e) {
+ // Catch any exception since we want to fall back to parsing the xml/
+ // resource in all cases
+ int resId = res.getIdentifier("appfilter", "xml", packageName);
+ if (resId != 0) {
+ parser = res.getXml(resId);
+ }
+ }
+
+ if (parser != null) {
+ try {
+ loadResourcesFromXmlParser(parser, iconPackResources);
+ return iconPackResources;
+ } catch (XmlPullParserException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ // Cleanup resources
+ if (parser instanceof XmlResourceParser) {
+ ((XmlResourceParser) parser).close();
+ } else if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ // Application uses a different theme format (most likely launcher pro)
+ int arrayId = res.getIdentifier("theme_iconpack", "array", packageName);
+ if (arrayId == 0) {
+ arrayId = res.getIdentifier("icon_pack", "array", packageName);
+ }
+
+ if (arrayId != 0) {
+ String[] iconPack = res.getStringArray(arrayId);
+ ComponentName compName = null;
+ for (String entry : iconPack) {
+
+ if (TextUtils.isEmpty(entry)) {
+ continue;
+ }
+
+ String icon = entry;
+ entry = entry.replaceAll("_", ".");
+
+ compName = new ComponentName(entry.toLowerCase(), "");
+ iconPackResources.put(compName, icon);
+
+ int activityIndex = entry.lastIndexOf(".");
+ if (activityIndex <= 0 || activityIndex == entry.length() - 1) {
+ continue;
+ }
+
+ String iconPackage = entry.substring(0, activityIndex);
+ if (TextUtils.isEmpty(iconPackage)) {
+ continue;
+ }
+
+ String iconActivity = entry.substring(activityIndex + 1);
+ if (TextUtils.isEmpty(iconActivity)) {
+ continue;
+ }
+
+ // Store entries as lower case to ensure match
+ iconPackage = iconPackage.toLowerCase();
+ iconActivity = iconActivity.toLowerCase();
+
+ iconActivity = iconPackage + "." + iconActivity;
+ compName = new ComponentName(iconPackage, iconActivity);
+ iconPackResources.put(compName, icon);
+ }
+ }
+ return iconPackResources;
+ }
+
+ boolean isIconPackLoaded() {
+ return mLoadedIconPackResource != null &&
+ mLoadedIconPackName != null &&
+ mIconPackResourceMap != null;
+ }
+
+ private int getResourceIdForDrawable(String resource) {
+ int resId =
+ mLoadedIconPackResource.getIdentifier(resource, "drawable",mLoadedIconPackName);
+ return resId;
+ }
+
+ public int getResourceIdForActivityIcon(ActivityInfo info) {
+ if (!isIconPackLoaded()) {
+ return 0;
+ }
+ ComponentName compName = new ComponentName(info.packageName.toLowerCase(),
+ info.name.toLowerCase());
+ String drawable = mIconPackResourceMap.get(compName);
+ if (drawable != null) {
+ int resId = getResourceIdForDrawable(drawable);
+ if (resId != 0) return resId;
+ }
+
+ // Icon pack doesn't have an icon for the activity, fallback to package icon
+ compName = new ComponentName(info.packageName.toLowerCase(), "");
+ drawable = mIconPackResourceMap.get(compName);
+ if (drawable == null) {
+ return 0;
+ }
+ return getResourceIdForDrawable(drawable);
+ }
+
+ public int getResourceIdForApp(String pkgName) {
+ ActivityInfo info = new ActivityInfo();
+ info.packageName = pkgName;
+ info.name = "";
+ return getResourceIdForActivityIcon(info);
+ }
+
+ public Drawable getDrawableForActivity(ActivityInfo info) {
+ int id = getResourceIdForActivityIcon(info);
+ if (id == 0) return null;
+ return mLoadedIconPackResource.getDrawable(id, null, false);
+ }
+
+ public Drawable getDrawableForActivityWithDensity(ActivityInfo info, int density) {
+ int id = getResourceIdForActivityIcon(info);
+ if (id == 0) return null;
+ return mLoadedIconPackResource.getDrawableForDensity(id, density, null, false);
+ }
+
+ public static boolean shouldComposeIcon(ComposedIconInfo iconInfo) {
+ return iconInfo != null &&
+ (iconInfo.iconBacks != null ||
+ iconInfo.iconMask != 0 ||
+ iconInfo.iconUpon != 0 ||
+ iconInfo.colorFilter != null ||
+ iconInfo.iconPaletteBack != 0 ||
+ iconInfo.iconRotation != 0 ||
+ iconInfo.iconRotationVariance != 0 ||
+ iconInfo.iconTranslationX != 0 ||
+ iconInfo.iconTranslationY != 0 ||
+ iconInfo.iconScale != 1f);
+ }
+
+ public static class IconCustomizer {
+ private static final Random sRandom = new Random();
+ private static final IIconCacheManager sIconCacheManager;
+
+ static {
+ sIconCacheManager = IIconCacheManager.Stub.asInterface(
+ ServiceManager.getService(ICON_CACHE_SERVICE));
+ }
+
+ public static Drawable getComposedIconDrawable(Drawable icon, Context context,
+ ComposedIconInfo iconInfo) {
+ final Resources res = context.getResources();
+ return getComposedIconDrawable(icon, res, iconInfo);
+ }
+
+ public static Drawable getComposedIconDrawable(Drawable icon, Resources res,
+ ComposedIconInfo iconInfo) {
+ if (iconInfo == null) return icon;
+ int back = 0;
+ int defaultSwatchColor = 0;
+ if (iconInfo.swatchType != ComposedIconInfo.SwatchType.None) {
+ back = iconInfo.iconPaletteBack;
+ if (iconInfo.defaultSwatchColors.length > 0) {
+ defaultSwatchColor = iconInfo.defaultSwatchColors[
+ sRandom.nextInt(iconInfo.defaultSwatchColors.length)];
+ }
+ } else if (iconInfo.iconBacks != null && iconInfo.iconBacks.length > 0) {
+ back = iconInfo.iconBacks[sRandom.nextInt(iconInfo.iconBacks.length)];
+ }
+ Bitmap bmp = createIconBitmap(icon, res, back, defaultSwatchColor, iconInfo);
+ return bmp != null ? new BitmapDrawable(res, bmp): null;
+ }
+
+ public static void getValue(Resources res, int resId, TypedValue outValue,
+ Drawable baseIcon) {
+ final String pkgName = res.getAssets().getAppName();
+ final ComposedIconInfo iconInfo = res.getComposedIconInfo();
+ if (iconInfo == null) {
+ // No composed icon info available so return, keeping original value
+ return;
+ }
+ TypedValue tempValue = new TypedValue();
+ tempValue.setTo(outValue);
+ // Catch all exceptions and restore outValue to tempValue if one occurs
+ try {
+ outValue.assetCookie = COMPOSED_ICON_COOKIE;
+ outValue.data = resId & (COMPOSED_ICON_COOKIE << 24 | 0x00ffffff);
+ outValue.string = getCachedIconPath(pkgName, resId, outValue.density);
+ int hashCode = outValue.string.hashCode() & 0x7fffffff;
+ int defaultSwatchColor = 0;
+
+ if (!(new File(outValue.string.toString()).exists())) {
+ // compose the icon and cache it
+ int back = 0;
+ if (iconInfo.swatchType != ComposedIconInfo.SwatchType.None) {
+ back = iconInfo.iconPaletteBack;
+ if (iconInfo.defaultSwatchColors.length > 0) {
+ defaultSwatchColor = iconInfo.defaultSwatchColors[
+ hashCode % iconInfo.defaultSwatchColors.length];
+ }
+ } else if (iconInfo.iconBacks != null && iconInfo.iconBacks.length > 0) {
+ back = iconInfo.iconBacks[hashCode % iconInfo.iconBacks.length];
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Composing icon for " + pkgName);
+ }
+ Bitmap bmp = createIconBitmap(baseIcon, res, back, defaultSwatchColor,
+ iconInfo);
+ if (!cacheComposedIcon(bmp,
+ getCachedIconName(pkgName, resId, outValue.density))) {
+ Log.w(TAG, "Unable to cache icon " + outValue.string);
+ // restore the original TypedValue
+ outValue.setTo(tempValue);
+ }
+ }
+ } catch (Exception e) {
+ // catch all, restore the original value and log it
+ outValue.setTo(tempValue);
+ Log.w(TAG, "getValue failed for " + outValue.string, e);
+ }
+ }
+
+ private static Bitmap createIconBitmap(Drawable icon, Resources res, int iconBack,
+ int defaultSwatchColor, ComposedIconInfo iconInfo) {
+ if (iconInfo.iconSize <= 0) return null;
+
+ final Canvas canvas = new Canvas();
+ canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG,
+ Paint.FILTER_BITMAP_FLAG));
+
+ int width = 0, height = 0;
+ int backTintColor = 0;
+ if (icon instanceof PaintDrawable) {
+ PaintDrawable painter = (PaintDrawable) icon;
+ painter.setIntrinsicWidth(iconInfo.iconSize);
+ painter.setIntrinsicHeight(iconInfo.iconSize);
+
+ // A PaintDrawable does not have an exact size
+ width = iconInfo.iconSize;
+ height = iconInfo.iconSize;
+ } else if (icon instanceof BitmapDrawable) {
+ // Ensure the bitmap has a density.
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
+ Bitmap bitmap = bitmapDrawable.getBitmap();
+ if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
+ bitmapDrawable.setTargetDensity(res.getDisplayMetrics());
+ }
+ canvas.setDensity(bitmap.getDensity());
+
+ // If the original size of the icon isn't greater
+ // than twice the size of recommended large icons
+ // respect the original size of the icon
+ // otherwise enormous icons can easily create
+ // OOM situations.
+ if ((bitmap.getWidth() < (iconInfo.iconSize * 2))
+ && (bitmap.getHeight() < (iconInfo.iconSize * 2))) {
+ width = bitmap.getWidth();
+ height = bitmap.getHeight();
+ } else {
+ width = iconInfo.iconSize;
+ height = iconInfo.iconSize;
+ }
+ if (iconInfo.swatchType != ComposedIconInfo.SwatchType.None) {
+ Palette palette = Palette.generate(bitmap, NUM_PALETTE_COLORS);
+ switch (iconInfo.swatchType) {
+ case Vibrant:
+ backTintColor = palette.getVibrantColor(defaultSwatchColor);
+ break;
+ case VibrantLight:
+ backTintColor = palette.getLightVibrantColor(defaultSwatchColor);
+ break;
+ case VibrantDark:
+ backTintColor = palette.getDarkVibrantColor(defaultSwatchColor);
+ break;
+ case Muted:
+ backTintColor = palette.getMutedColor(defaultSwatchColor);
+ break;
+ case MutedLight:
+ backTintColor = palette.getLightMutedColor(defaultSwatchColor);
+ break;
+ case MutedDark:
+ backTintColor = palette.getDarkMutedColor(defaultSwatchColor);
+ break;
+ }
+ if (DEBUG) {
+ Log.d(TAG, String.format("palette tint color=0x%08x", backTintColor));
+ }
+ }
+ } else if (icon instanceof VectorDrawable) {
+ width = height = iconInfo.iconSize;
+ }
+
+ if (width <= 0 || height <= 0) return null;
+
+ Bitmap bitmap = Bitmap.createBitmap(width, height,
+ Bitmap.Config.ARGB_8888);
+ canvas.setBitmap(bitmap);
+
+ // Scale the original
+ Rect oldBounds = new Rect();
+ oldBounds.set(icon.getBounds());
+ icon.setBounds(0, 0, width, height);
+ canvas.save();
+ final float halfWidth = width / 2f;
+ final float halfHeight = height / 2f;
+ float angle = iconInfo.iconRotation;
+ if (iconInfo.iconRotationVariance != 0) {
+ angle += (sRandom.nextFloat() * (iconInfo.iconRotationVariance * 2))
+ - iconInfo.iconRotationVariance;
+ }
+ canvas.scale(iconInfo.iconScale, iconInfo.iconScale, halfWidth, halfHeight);
+ canvas.translate(iconInfo.iconTranslationX, iconInfo.iconTranslationY);
+ canvas.rotate(angle, halfWidth, halfHeight);
+ if (iconInfo.colorFilter != null) {
+ Paint p = null;
+ if (icon instanceof BitmapDrawable) {
+ p = ((BitmapDrawable) icon).getPaint();
+ } else if (icon instanceof PaintDrawable) {
+ p = ((PaintDrawable) icon).getPaint();
+ }
+ if (p != null) p.setColorFilter(new ColorMatrixColorFilter(iconInfo.colorFilter));
+ }
+ icon.draw(canvas);
+ canvas.restore();
+
+ // Mask off the original if iconMask is not null
+ if (iconInfo.iconMask != 0) {
+ Drawable mask = res.getDrawable(iconInfo.iconMask);
+ if (mask != null) {
+ mask.setBounds(icon.getBounds());
+ ((BitmapDrawable) mask).getPaint().setXfermode(
+ new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+ mask.draw(canvas);
+ }
+ }
+ // Draw the iconBacks if not null and then the original (scaled and masked) icon on top
+ if (iconBack != 0) {
+ Drawable back = res.getDrawable(iconBack);
+ if (back != null) {
+ back.setBounds(icon.getBounds());
+ Paint paint = ((BitmapDrawable) back).getPaint();
+ paint.setXfermode(
+ new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
+ if (backTintColor != 0) {
+ paint.setColorFilter(new PorterDuffColorFilter(backTintColor,
+ PorterDuff.Mode.MULTIPLY));
+ }
+ back.draw(canvas);
+ }
+ }
+ // Finally draw the foreground if one was supplied
+ if (iconInfo.iconUpon != 0) {
+ Drawable upon = res.getDrawable(iconInfo.iconUpon);
+ if (upon != null) {
+ upon.setBounds(icon.getBounds());
+ upon.draw(canvas);
+ }
+ }
+ icon.setBounds(oldBounds);
+ bitmap.setDensity(canvas.getDensity());
+
+ return bitmap;
+ }
+
+ private static boolean cacheComposedIcon(Bitmap bmp, String path) {
+ try {
+ return sIconCacheManager.cacheComposedIcon(bmp, path);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to cache icon.", e);
+ }
+
+ return false;
+ }
+
+ private static String getCachedIconPath(String pkgName, int resId, int density) {
+ return String.format("%s/%s", SYSTEM_THEME_ICON_CACHE_DIR,
+ getCachedIconName(pkgName, resId, density));
+ }
+
+ private static String getCachedIconName(String pkgName, int resId, int density) {
+ return String.format("%s_%08x_%d.png", pkgName, resId, density);
+ }
+ }
+
+ public static class ColorFilterUtils {
+ private static final String TAG_FILTER = "filter";
+ private static final String FILTER_HUE = "hue";
+ private static final String FILTER_SATURATION = "saturation";
+ private static final String FILTER_INVERT = "invert";
+ private static final String FILTER_BRIGHTNESS = "brightness";
+ private static final String FILTER_CONTRAST = "contrast";
+ private static final String FILTER_ALPHA = "alpha";
+ private static final String FILTER_TINT = "tint";
+
+ private static final int MIN_HUE = -180;
+ private static final int MAX_HUE = 180;
+ private static final int MIN_SATURATION = 0;
+ private static final int MAX_SATURATION = 200;
+ private static final int MIN_BRIGHTNESS = 0;
+ private static final int MAX_BRIGHTNESS = 200;
+ private static final int MIN_CONTRAST = -100;
+ private static final int MAX_CONTRAST = 100;
+ private static final int MIN_ALPHA = 0;
+ private static final int MAX_ALPHA = 100;
+
+ public static boolean parseIconFilter(XmlPullParser parser, Builder builder)
+ throws IOException, XmlPullParserException {
+ String tag = parser.getName();
+ if (!TAG_FILTER.equals(tag)) return false;
+
+ int attrCount = parser.getAttributeCount();
+ String attrName;
+ String attr = null;
+ int intValue;
+ while (attrCount-- > 0) {
+ attrName = parser.getAttributeName(attrCount);
+ if (attrName.equals("name")) {
+ attr = parser.getAttributeValue(attrCount);
+ }
+ }
+ String content = parser.nextText();
+ if (attr != null && content != null && content.length() > 0) {
+ content = content.trim();
+ if (FILTER_HUE.equalsIgnoreCase(attr)) {
+ intValue = clampValue(getInt(content, 0),MIN_HUE, MAX_HUE);
+ builder.hue(intValue);
+ } else if (FILTER_SATURATION.equalsIgnoreCase(attr)) {
+ intValue = clampValue(getInt(content, 100),
+ MIN_SATURATION, MAX_SATURATION);
+ builder.saturate(intValue);
+ } else if (FILTER_INVERT.equalsIgnoreCase(attr)) {
+ if ("true".equalsIgnoreCase(content)) {
+ builder.invertColors();
+ }
+ } else if (FILTER_BRIGHTNESS.equalsIgnoreCase(attr)) {
+ intValue = clampValue(getInt(content, 100),
+ MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+ builder.brightness(intValue);
+ } else if (FILTER_CONTRAST.equalsIgnoreCase(attr)) {
+ intValue = clampValue(getInt(content, 0),
+ MIN_CONTRAST, MAX_CONTRAST);
+ builder.contrast(intValue);
+ } else if (FILTER_ALPHA.equalsIgnoreCase(attr)) {
+ intValue = clampValue(getInt(content, 100), MIN_ALPHA, MAX_ALPHA);
+ builder.alpha(intValue);
+ } else if (FILTER_TINT.equalsIgnoreCase(attr)) {
+ try {
+ intValue = Color.parseColor(content);
+ builder.tint(intValue);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Cannot apply tint, invalid argument: " + content);
+ }
+ }
+ }
+ return true;
+ }
+
+ private static int getInt(String value, int defaultValue) {
+ try {
+ return Integer.valueOf(value);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ private static int clampValue(int value, int min, int max) {
+ return Math.min(max, Math.max(min, value));
+ }
+
+ /**
+ * See the following links for reference
+ * http://groups.google.com/group/android-developers/browse_thread/thread/9e215c83c3819953
+ * http://gskinner.com/blog/archives/2007/12/colormatrix_cla.html
+ * @param value
+ */
+ public static ColorMatrix adjustHue(float value) {
+ ColorMatrix cm = new ColorMatrix();
+ value = value / 180 * (float) Math.PI;
+ if (value != 0) {
+ float cosVal = (float) Math.cos(value);
+ float sinVal = (float) Math.sin(value);
+ float lumR = 0.213f;
+ float lumG = 0.715f;
+ float lumB = 0.072f;
+ float[] mat = new float[]{
+ lumR + cosVal * (1 - lumR) + sinVal * (-lumR),
+ lumG + cosVal * (-lumG) + sinVal * (-lumG),
+ lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0, 0,
+ lumR + cosVal * (-lumR) + sinVal * (0.143f),
+ lumG + cosVal * (1 - lumG) + sinVal * (0.140f),
+ lumB + cosVal * (-lumB) + sinVal * (-0.283f), 0, 0,
+ lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)),
+ lumG + cosVal * (-lumG) + sinVal * (lumG),
+ lumB + cosVal * (1 - lumB) + sinVal * (lumB), 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1};
+ cm.set(mat);
+ }
+ return cm;
+ }
+
+ public static ColorMatrix adjustSaturation(float saturation) {
+ saturation = saturation / 100;
+ ColorMatrix cm = new ColorMatrix();
+ cm.setSaturation(saturation);
+
+ return cm;
+ }
+
+ public static ColorMatrix invertColors() {
+ float[] matrix = {
+ -1, 0, 0, 0, 255, //red
+ 0, -1, 0, 0, 255, //green
+ 0, 0, -1, 0, 255, //blue
+ 0, 0, 0, 1, 0 //alpha
+ };
+
+ return new ColorMatrix(matrix);
+ }
+
+ public static ColorMatrix adjustBrightness(float brightness) {
+ brightness = brightness / 100;
+ ColorMatrix cm = new ColorMatrix();
+ cm.setScale(brightness, brightness, brightness, 1);
+
+ return cm;
+ }
+
+ public static ColorMatrix adjustContrast(float contrast) {
+ contrast = contrast / 100 + 1;
+ float o = (-0.5f * contrast + 0.5f) * 255;
+ float[] matrix = {
+ contrast, 0, 0, 0, o, //red
+ 0, contrast, 0, 0, o, //green
+ 0, 0, contrast, 0, o, //blue
+ 0, 0, 0, 1, 0 //alpha
+ };
+
+ return new ColorMatrix(matrix);
+ }
+
+ public static ColorMatrix adjustAlpha(float alpha) {
+ alpha = alpha / 100;
+ ColorMatrix cm = new ColorMatrix();
+ cm.setScale(1, 1, 1, alpha);
+
+ return cm;
+ }
+
+ public static ColorMatrix applyTint(int color) {
+ float alpha = Color.alpha(color) / 255f;
+ float red = Color.red(color) * alpha;
+ float green = Color.green(color) * alpha;
+ float blue = Color.blue(color) * alpha;
+
+ float[] matrix = {
+ 1, 0, 0, 0, red, //red
+ 0, 1, 0, 0, green, //green
+ 0, 0, 1, 0, blue, //blue
+ 0, 0, 0, 1, 0 //alpha
+ };
+
+ return new ColorMatrix(matrix);
+ }
+
+ public static class Builder {
+ private List<ColorMatrix> mMatrixList;
+
+ public Builder() {
+ mMatrixList = new ArrayList<ColorMatrix>();
+ }
+
+ public Builder hue(float value) {
+ mMatrixList.add(adjustHue(value));
+ return this;
+ }
+
+ public Builder saturate(float saturation) {
+ mMatrixList.add(adjustSaturation(saturation));
+ return this;
+ }
+
+ public Builder brightness(float brightness) {
+ mMatrixList.add(adjustBrightness(brightness));
+ return this;
+ }
+
+ public Builder contrast(float contrast) {
+ mMatrixList.add(adjustContrast(contrast));
+ return this;
+ }
+
+ public Builder alpha(float alpha) {
+ mMatrixList.add(adjustAlpha(alpha));
+ return this;
+ }
+
+ public Builder invertColors() {
+ mMatrixList.add(ColorFilterUtils.invertColors());
+ return this;
+ }
+
+ public Builder tint(int color) {
+ mMatrixList.add(applyTint(color));
+ return this;
+ }
+
+ public ColorMatrix build() {
+ if (mMatrixList == null || mMatrixList.size() == 0) return null;
+
+ ColorMatrix colorMatrix = new ColorMatrix();
+ for (ColorMatrix cm : mMatrixList) {
+ colorMatrix.postConcat(cm);
+ }
+ return colorMatrix;
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 69b8b95..cddcd9f 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -374,6 +374,7 @@ public class Instrumentation {
* @see Context#startActivity
*/
public Activity startActivitySync(Intent intent) {
+ android.util.SeempLog.record_str(376, intent.toString());
validateNotAppThread();
synchronized (mSync) {
@@ -1481,6 +1482,7 @@ public class Instrumentation {
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
+ android.util.SeempLog.record_str(377, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
@@ -1541,6 +1543,7 @@ public class Instrumentation {
public void execStartActivitiesAsUser(Context who, IBinder contextThread,
IBinder token, Activity target, Intent[] intents, Bundle options,
int userId) {
+ android.util.SeempLog.record_str(378, intents.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1604,6 +1607,7 @@ public class Instrumentation {
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, String target,
Intent intent, int requestCode, Bundle options) {
+ android.util.SeempLog.record_str(377, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1664,6 +1668,7 @@ public class Instrumentation {
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options, UserHandle user) {
+ android.util.SeempLog.record_str(377, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1703,6 +1708,7 @@ public class Instrumentation {
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options, boolean ignoreTargetSecurity,
int userId) {
+ android.util.SeempLog.record_str(379, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1741,6 +1747,7 @@ public class Instrumentation {
public void execStartActivityFromAppTask(
Context who, IBinder contextThread, IAppTask appTask,
Intent intent, Bundle options) {
+ android.util.SeempLog.record_str(380, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index c2bf28a..76e55b7 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -546,7 +546,8 @@ public final class LoadedApk {
public Resources getResources(ActivityThread mainThread) {
if (mResources == null) {
mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs,
- mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, null, this);
+ mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, null, this,
+ mainThread.getSystemContext(), mPackageName);
}
return mResources;
}
@@ -601,7 +602,7 @@ public final class LoadedApk {
final int N = packageIdentifiers.size();
for (int i = 0; i < N; i++) {
final int id = packageIdentifiers.keyAt(i);
- if (id == 0x01 || id == 0x7f) {
+ if (id == 0x01 || id == 0x7f || id == 0x3f) {
continue;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6a4f6a1..8835a09 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -45,6 +45,7 @@ import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.MathUtils;
+import android.util.SparseArray;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
@@ -62,6 +63,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
/**
* A class that represents how a persistent notification is to be presented to
@@ -520,6 +523,21 @@ public class Notification implements Parcelable
public int priority;
/**
+ * Default.
+ * Show all notifications from an app on keyguard.
+ *
+ * @hide
+ */
+ public static final int SHOW_ALL_NOTI_ON_KEYGUARD = 0x01;
+
+ /**
+ * Show only notifications from an app which are not ongoing ones.
+ *
+ * @hide
+ */
+ public static final int SHOW_NO_ONGOING_NOTI_ON_KEYGUARD = 0x02;
+
+ /**
* Accent color (an ARGB integer like the constants in {@link android.graphics.Color})
* to be applied by the standard Style templates when presenting this notification.
*
@@ -895,6 +913,13 @@ public class Notification implements Parcelable
private Icon mLargeIcon;
/**
+ * Used by light picker in Settings to force
+ * notification lights on when screen is on
+ * @hide
+ */
+ public static final String EXTRA_FORCE_SHOW_LIGHTS = "android.forceShowLights";
+
+ /**
* Structure to encapsulate a named action that can be shown as part of this notification.
* It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
* selected by the user.
@@ -953,6 +978,9 @@ public class Notification implements Parcelable
private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
RemoteInput[] remoteInputs) {
this.mIcon = icon;
+ if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
+ this.icon = icon.getResId();
+ }
this.title = title;
this.actionIntent = intent;
this.mExtras = extras != null ? extras : new Bundle();
@@ -1600,13 +1628,23 @@ public class Notification implements Parcelable
bigContentView = null;
headsUpContentView = null;
mLargeIcon = null;
- if (extras != null) {
- extras.remove(Notification.EXTRA_LARGE_ICON);
- extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
- extras.remove(Notification.EXTRA_PICTURE);
- extras.remove(Notification.EXTRA_BIG_TEXT);
+ if (extras != null && !extras.isEmpty()) {
// Prevent light notifications from being rebuilt.
extras.remove(Builder.EXTRA_NEEDS_REBUILD);
+ final Set<String> keyset = extras.keySet();
+ final int N = keyset.size();
+ final String[] keys = keyset.toArray(new String[N]);
+ for (int i=0; i<N; i++) {
+ final String key = keys[i];
+ final Object obj = extras.get(key);
+ if (obj != null &&
+ ( obj instanceof Parcelable
+ || obj instanceof Parcelable[]
+ || obj instanceof SparseArray
+ || obj instanceof ArrayList)) {
+ extras.remove(key);
+ }
+ }
}
}
@@ -4612,7 +4650,7 @@ public class Notification implements Parcelable
* Size value for use with {@link #setCustomSizePreset} to show this notification with
* default sizing.
* <p>For custom display notifications created using {@link #setDisplayIntent},
- * the default is {@link #SIZE_LARGE}. All other notifications size automatically based
+ * the default is {@link #SIZE_MEDIUM}. All other notifications size automatically based
* on their content.
*/
public static final int SIZE_DEFAULT = 0;
diff --git a/core/java/android/app/NotificationGroup.aidl b/core/java/android/app/NotificationGroup.aidl
new file mode 100644
index 0000000..44b6290
--- /dev/null
+++ b/core/java/android/app/NotificationGroup.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2012, The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+parcelable NotificationGroup;
diff --git a/core/java/android/app/NotificationGroup.java b/core/java/android/app/NotificationGroup.java
new file mode 100644
index 0000000..bcb70d3
--- /dev/null
+++ b/core/java/android/app/NotificationGroup.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+
+/** @hide */
+public class NotificationGroup implements Parcelable {
+ private static final String TAG = "NotificationGroup";
+
+ private String mName;
+ private int mNameResId;
+
+ private UUID mUuid;
+
+ private Set<String> mPackages = new HashSet<String>();
+
+ private boolean mDirty;
+
+ public static final Parcelable.Creator<NotificationGroup> CREATOR = new Parcelable.Creator<NotificationGroup>() {
+ public NotificationGroup createFromParcel(Parcel in) {
+ return new NotificationGroup(in);
+ }
+
+ @Override
+ public NotificationGroup[] newArray(int size) {
+ return new NotificationGroup[size];
+ }
+ };
+
+ public NotificationGroup(String name) {
+ this(name, -1, null);
+ }
+
+ public NotificationGroup(String name, int nameResId, UUID uuid) {
+ mName = name;
+ mNameResId = nameResId;
+ mUuid = (uuid != null) ? uuid : UUID.randomUUID();
+ mDirty = uuid == null;
+ }
+
+ private NotificationGroup(Parcel in) {
+ readFromParcel(in);
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public void setName(String name) {
+ mName = name;
+ mNameResId = -1;
+ mDirty = true;
+ }
+
+ public UUID getUuid() {
+ return mUuid;
+ }
+
+ public void addPackage(String pkg) {
+ mPackages.add(pkg);
+ mDirty = true;
+ }
+
+ public String[] getPackages() {
+ return mPackages.toArray(new String[mPackages.size()]);
+ }
+
+ public void removePackage(String pkg) {
+ mPackages.remove(pkg);
+ mDirty = true;
+ }
+
+ public boolean hasPackage(String pkg) {
+ return mPackages.contains(pkg);
+ }
+
+ public boolean isDirty() {
+ return mDirty;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mName);
+ dest.writeInt(mNameResId);
+ dest.writeInt(mDirty ? 1 : 0);
+ new ParcelUuid(mUuid).writeToParcel(dest, 0);
+ dest.writeStringArray(getPackages());
+ }
+
+ public void readFromParcel(Parcel in) {
+ mName = in.readString();
+ mNameResId = in.readInt();
+ mDirty = in.readInt() != 0;
+ mUuid = ParcelUuid.CREATOR.createFromParcel(in).getUuid();
+ mPackages.addAll(Arrays.asList(in.readStringArray()));
+ }
+
+ public void getXmlString(StringBuilder builder, Context context) {
+ builder.append("<notificationGroup ");
+ if (mNameResId > 0) {
+ builder.append("nameres=\"");
+ builder.append(context.getResources().getResourceEntryName(mNameResId));
+ } else {
+ builder.append("name=\"");
+ builder.append(TextUtils.htmlEncode(getName()));
+ }
+ builder.append("\" uuid=\"");
+ builder.append(TextUtils.htmlEncode(getUuid().toString()));
+ builder.append("\">\n");
+ for (String pkg : mPackages) {
+ builder.append("<package>" + TextUtils.htmlEncode(pkg) + "</package>\n");
+ }
+ builder.append("</notificationGroup>\n");
+ mDirty = false;
+ }
+
+ public static NotificationGroup fromXml(XmlPullParser xpp, Context context)
+ throws XmlPullParserException, IOException {
+ String value = xpp.getAttributeValue(null, "nameres");
+ int nameResId = -1;
+ String name = null;
+ UUID uuid = null;
+
+ if (value != null) {
+ nameResId = context.getResources().getIdentifier(value, "string", "android");
+ if (nameResId > 0) {
+ name = context.getResources().getString(nameResId);
+ }
+ }
+
+ if (name == null) {
+ name = xpp.getAttributeValue(null, "name");
+ }
+
+ value = xpp.getAttributeValue(null, "uuid");
+ if (value != null) {
+ try {
+ uuid = UUID.fromString(value);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "UUID not recognized for " + name + ", using new one.");
+ }
+ }
+
+ NotificationGroup notificationGroup = new NotificationGroup(name, nameResId, uuid);
+ int event = xpp.next();
+ while (event != XmlPullParser.END_TAG || !xpp.getName().equals("notificationGroup")) {
+ if (event == XmlPullParser.START_TAG) {
+ if (xpp.getName().equals("package")) {
+ String pkg = xpp.nextText();
+ notificationGroup.addPackage(pkg);
+ }
+ }
+ event = xpp.next();
+ }
+
+ /* we just loaded from XML, no need to save */
+ notificationGroup.mDirty = false;
+
+ return notificationGroup;
+ }
+}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 605c006..2219e64 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -19,6 +19,7 @@ package android.app;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
+import android.app.Notification;
import android.app.Notification.Builder;
import android.content.ComponentName;
import android.content.Context;
@@ -512,6 +513,16 @@ public class NotificationManager
return new ArraySet<String>();
}
+ /** @hide */
+ public int getShowNotificationForPackageOnKeyguard(String pkg, int uid) {
+ INotificationManager service = getService();
+ try {
+ return getService().getShowNotificationForPackageOnKeyguard(pkg, uid);
+ } catch (RemoteException e) {
+ return Notification.SHOW_ALL_NOTI_ON_KEYGUARD;
+ }
+ }
+
private Context mContext;
private static void checkRequired(String name, Object value) {
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 2117597..c98167d 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -18,22 +18,38 @@ package android.app;
import static android.app.ActivityThread.DEBUG_CONFIGURATION;
+import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ThemeUtils;
import android.content.res.AssetManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
+import android.content.res.ThemeConfig;
import android.content.res.Resources;
import android.content.res.ResourcesKey;
+import android.graphics.Typeface;
import android.hardware.display.DisplayManagerGlobal;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayAdjustments;
import java.lang.ref.WeakReference;
+import java.util.List;
import java.util.Locale;
/** @hide */
@@ -48,9 +64,16 @@ public class ResourcesManager {
new ArrayMap<>();
CompatibilityInfo mResCompatibilityInfo;
+ static IPackageManager sPackageManager;
Configuration mResConfiguration;
+ /**
+ * Number of default assets attached to a Resource object's AssetManager
+ * This currently includes framework and cmsdk resources
+ */
+ private static final int NUM_DEFAULT_ASSETS = 2;
+
public static ResourcesManager getInstance() {
synchronized (ResourcesManager.class) {
if (sResourcesManager == null) {
@@ -156,12 +179,15 @@ public class ResourcesManager {
* @param compatInfo the compatibility info. Must not be null.
*/
Resources getTopLevelResources(String resDir, String[] splitResDirs,
- String[] overlayDirs, String[] libDirs, int displayId,
- Configuration overrideConfiguration, CompatibilityInfo compatInfo) {
+ String[] overlayDirs, String[] libDirs, int displayId, String packageName,
+ Configuration overrideConfiguration, CompatibilityInfo compatInfo, Context context,
+ boolean isThemeable) {
final float scale = compatInfo.applicationScale;
+ ThemeConfig themeConfig = getThemeConfig();
Configuration overrideConfigCopy = (overrideConfiguration != null)
? new Configuration(overrideConfiguration) : null;
- ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfigCopy, scale);
+ ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale,
+ isThemeable, getThemeConfig());
Resources r;
synchronized (this) {
// Resources is app scale dependent.
@@ -184,6 +210,8 @@ public class ResourcesManager {
//}
AssetManager assets = new AssetManager();
+ assets.setAppName(packageName);
+ assets.setThemeSupport(isThemeable);
// resDir can be null if the 'android' package is creating a new Resources object.
// This is fine, since each AssetManager automatically loads the 'android' package
// already.
@@ -203,7 +231,7 @@ public class ResourcesManager {
if (overlayDirs != null) {
for (String idmapPath : overlayDirs) {
- assets.addOverlayPath(idmapPath);
+ assets.addOverlayPath(idmapPath, null, null, null, null);
}
}
@@ -213,7 +241,7 @@ public class ResourcesManager {
// Avoid opening files we know do not have resources,
// like code-only .jar files.
if (assets.addAssetPath(libDir) == 0) {
- Log.w(TAG, "Asset path '" + libDir +
+ Slog.w(TAG, "Asset path '" + libDir +
"' does not exist or contains no resources.");
}
}
@@ -237,10 +265,38 @@ public class ResourcesManager {
} else {
config = getConfiguration();
}
+
+ boolean iconsAttached = false;
+ /* Attach theme information to the resulting AssetManager when appropriate. */
+ if (config != null && !context.getPackageManager().isSafeMode()) {
+ if (themeConfig == null) {
+ try {
+ themeConfig = ThemeConfig.getBootTheme(context.getContentResolver());
+ } catch (Exception e) {
+ Slog.d(TAG, "ThemeConfig.getBootTheme failed, falling back to system theme", e);
+ themeConfig = ThemeConfig.getSystemTheme();
+ }
+ }
+
+ if (isThemeable) {
+ if (themeConfig != null) {
+ attachThemeAssets(assets, themeConfig);
+ attachCommonAssets(assets, themeConfig);
+ iconsAttached = attachIconAssets(assets, themeConfig);
+ }
+ } else if (themeConfig != null &&
+ !ThemeConfig.SYSTEM_DEFAULT.equals(themeConfig.getFontPkgName())) {
+ // use system fonts if not themeable and a theme font is currently in use
+ Typeface.recreateDefaults(true);
+ }
+ }
+
r = new Resources(assets, dm, config, compatInfo);
+ if (iconsAttached) setActivityIcons(r);
if (DEBUG) Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
+ r.getConfiguration() + " appScale=" + r.getCompatibilityInfo().applicationScale);
+
synchronized (this) {
WeakReference<Resources> wr = mActiveResources.get(key);
Resources existing = wr != null ? wr.get() : null;
@@ -258,6 +314,152 @@ public class ResourcesManager {
}
}
+ /**
+ * Creates the top level Resources for applications with the given compatibility info.
+ *
+ * @param resDir the resource directory.
+ * @param compatInfo the compability info. Must not be null.
+ *
+ * @hide
+ */
+ public Resources getTopLevelThemedResources(String resDir, int displayId, String packageName,
+ String themePackageName, CompatibilityInfo compatInfo, boolean isThemeable) {
+ Resources r;
+
+ ThemeConfig.Builder builder = new ThemeConfig.Builder();
+ builder.defaultOverlay(themePackageName);
+ builder.defaultIcon(themePackageName);
+ builder.defaultFont(themePackageName);
+ ThemeConfig themeConfig = builder.build();
+
+ ResourcesKey key = new ResourcesKey(resDir, displayId, null, compatInfo.applicationScale,
+ isThemeable, themeConfig);
+
+ synchronized (this) {
+ WeakReference<Resources> wr = mActiveResources.get(key);
+ r = wr != null ? wr.get() : null;
+ if (r != null && r.getAssets().isUpToDate()) {
+ if (false) {
+ Slog.w(TAG, "Returning cached resources " + r + " " + resDir
+ + ": appScale=" + r.getCompatibilityInfo().applicationScale);
+ }
+ return r;
+ }
+ }
+
+ AssetManager assets = new AssetManager();
+ assets.setAppName(packageName);
+ assets.setThemeSupport(isThemeable);
+ if (assets.addAssetPath(resDir) == 0) {
+ return null;
+ }
+
+ //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
+ DisplayMetrics dm = getDisplayMetricsLocked(displayId);
+ Configuration config;
+ boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+ final boolean hasOverrideConfig = key.hasOverrideConfiguration();
+ if (!isDefaultDisplay || hasOverrideConfig) {
+ config = new Configuration(getConfiguration());
+ if (!isDefaultDisplay) {
+ applyNonDefaultDisplayMetricsToConfigurationLocked(dm, config);
+ }
+ if (hasOverrideConfig) {
+ config.updateFrom(key.mOverrideConfiguration);
+ }
+ } else {
+ config = getConfiguration();
+ }
+
+ boolean iconsAttached = false;
+ if (isThemeable) {
+ /* Attach theme information to the resulting AssetManager when appropriate. */
+ attachThemeAssets(assets, themeConfig);
+ attachCommonAssets(assets, themeConfig);
+ iconsAttached = attachIconAssets(assets, themeConfig);
+ }
+ r = new Resources(assets, dm, config, compatInfo);
+ if (iconsAttached) setActivityIcons(r);
+
+ if (false) {
+ Slog.i(TAG, "Created THEMED app resources " + resDir + " " + r + ": "
+ + r.getConfiguration() + " appScale="
+ + r.getCompatibilityInfo().applicationScale);
+ }
+
+ synchronized (this) {
+ WeakReference<Resources> wr = mActiveResources.get(key);
+ Resources existing = wr != null ? wr.get() : null;
+ if (existing != null && existing.getAssets().isUpToDate()) {
+ // Someone else already created the resources while we were
+ // unlocked; go ahead and use theirs.
+ r.getAssets().close();
+ return existing;
+ }
+
+ // XXX need to remove entries when weak references go away
+ mActiveResources.put(key, new WeakReference<Resources>(r));
+ return r;
+ }
+ }
+
+ /**
+ * Creates a map between an activity & app's icon ids to its component info. This map
+ * is then stored in the resource object.
+ * When resource.getDrawable(id) is called it will check this mapping and replace
+ * the id with the themed resource id if one is available
+ * @param r
+ */
+ private void setActivityIcons(Resources r) {
+ SparseArray<PackageItemInfo> iconResources = new SparseArray<PackageItemInfo>();
+ String pkgName = r.getAssets().getAppName();
+ PackageInfo pkgInfo = null;
+ ApplicationInfo appInfo = null;
+
+ try {
+ pkgInfo = getPackageManager().getPackageInfo(pkgName, PackageManager.GET_ACTIVITIES,
+ UserHandle.getCallingUserId());
+ } catch (RemoteException e1) {
+ Slog.e(TAG, "Unable to get pkg " + pkgName, e1);
+ return;
+ }
+
+ final ThemeConfig themeConfig = r.getConfiguration().themeConfig;
+ if (pkgName != null && themeConfig != null &&
+ pkgName.equals(themeConfig.getIconPackPkgName())) {
+ return;
+ }
+
+ //Map application icon
+ if (pkgInfo != null && pkgInfo.applicationInfo != null) {
+ appInfo = pkgInfo.applicationInfo;
+ if (appInfo.themedIcon != 0 || iconResources.get(appInfo.icon) == null) {
+ iconResources.put(appInfo.icon, appInfo);
+ }
+ }
+
+ //Map activity icons.
+ if (pkgInfo != null && pkgInfo.activities != null) {
+ for (ActivityInfo ai : pkgInfo.activities) {
+ if (ai.icon != 0 && (ai.themedIcon != 0 || iconResources.get(ai.icon) == null)) {
+ iconResources.put(ai.icon, ai);
+ } else if (appInfo != null && appInfo.icon != 0 &&
+ (ai.themedIcon != 0 || iconResources.get(appInfo.icon) == null)) {
+ iconResources.put(appInfo.icon, ai);
+ }
+ }
+ }
+
+ r.setIconResources(iconResources);
+ final IPackageManager pm = getPackageManager();
+ try {
+ ComposedIconInfo iconInfo = pm.getComposedIconInfo();
+ r.setComposedIconInfo(iconInfo);
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Failed to retrieve ComposedIconInfo", e);
+ }
+ }
+
final boolean applyConfigurationToResourcesLocked(Configuration config,
CompatibilityInfo compat) {
if (mResConfiguration == null) {
@@ -303,6 +505,22 @@ public class ResourcesManager {
boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
DisplayMetrics dm = defaultDisplayMetrics;
final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
+ boolean themeChanged = (changes & ActivityInfo.CONFIG_THEME_RESOURCE) != 0;
+ if (themeChanged) {
+ AssetManager am = r.getAssets();
+ if (am.hasThemeSupport()) {
+ r.setIconResources(null);
+ r.setComposedIconInfo(null);
+ detachThemeAssets(am);
+ if (config.themeConfig != null) {
+ attachThemeAssets(am, config.themeConfig);
+ attachCommonAssets(am, config.themeConfig);
+ if (attachIconAssets(am, config.themeConfig)) {
+ setActivityIcons(r);
+ }
+ }
+ }
+ }
if (!isDefaultDisplay || hasOverrideConfiguration) {
if (tmpConfig == null) {
tmpConfig = new Configuration();
@@ -319,6 +537,9 @@ public class ResourcesManager {
} else {
r.updateConfiguration(config, dm, compat);
}
+ if (themeChanged) {
+ r.updateStringCache();
+ }
//Slog.i(TAG, "Updated app resources " + v.getKey()
// + " " + r + ": " + r.getConfiguration());
} else {
@@ -330,4 +551,265 @@ public class ResourcesManager {
return changes != 0;
}
+ public static IPackageManager getPackageManager() {
+ if (sPackageManager != null) {
+ return sPackageManager;
+ }
+ IBinder b = ServiceManager.getService("package");
+ sPackageManager = IPackageManager.Stub.asInterface(b);
+ return sPackageManager;
+ }
+
+
+ /**
+ * Attach the necessary theme asset paths and meta information to convert an
+ * AssetManager to being globally "theme-aware".
+ *
+ * @param assets
+ * @param theme
+ * @return true if the AssetManager is now theme-aware; false otherwise.
+ * This can fail, for example, if the theme package has been been
+ * removed and the theme manager has yet to revert formally back to
+ * the framework default.
+ */
+ private boolean attachThemeAssets(AssetManager assets, ThemeConfig theme) {
+ PackageInfo piTheme = null;
+ PackageInfo piTarget = null;
+ PackageInfo piAndroid = null;
+ PackageInfo piCm = null;
+
+ // Some apps run in process of another app (eg keyguard/systemUI) so we must get the
+ // package name from the res tables. The 0th base package name will be the android group.
+ // The 1st base package name will be the app group if one is attached. Check if it is there
+ // first or else the system will crash!
+ String basePackageName = null;
+ String resourcePackageName = null;
+ int count = assets.getBasePackageCount();
+ if (count > NUM_DEFAULT_ASSETS) {
+ basePackageName = assets.getBasePackageName(NUM_DEFAULT_ASSETS);
+ resourcePackageName = assets.getBaseResourcePackageName(NUM_DEFAULT_ASSETS);
+ } else if (count == NUM_DEFAULT_ASSETS) {
+ basePackageName = assets.getBasePackageName(0);
+ } else {
+ return false;
+ }
+
+ try {
+ piTheme = getPackageManager().getPackageInfo(
+ theme.getOverlayPkgNameForApp(basePackageName), 0,
+ UserHandle.getCallingUserId());
+ piTarget = getPackageManager().getPackageInfo(
+ basePackageName, 0, UserHandle.getCallingUserId());
+
+ // Handle special case where a system app (ex trebuchet) may have had its pkg name
+ // renamed during an upgrade. basePackageName would be the manifest value which will
+ // fail on getPackageInfo(). resource pkg is assumed to have the original name
+ if (piTarget == null && resourcePackageName != null) {
+ piTarget = getPackageManager().getPackageInfo(resourcePackageName,
+ 0, UserHandle.getCallingUserId());
+ }
+ piAndroid = getPackageManager().getPackageInfo("android", 0,
+ UserHandle.getCallingUserId());
+ piCm = getPackageManager().getPackageInfo("cyanogenmod.platform", 0,
+ UserHandle.getCallingUserId());
+ } catch (RemoteException e) {
+ }
+
+ if (piTheme == null || piTheme.applicationInfo == null ||
+ piTarget == null || piTarget.applicationInfo == null ||
+ piAndroid == null || piAndroid.applicationInfo == null ||
+ piCm == null || piCm.applicationInfo == null ||
+ piTheme.mOverlayTargets == null) {
+ return false;
+ }
+
+ // Attach themed resources for target
+ String themePackageName = piTheme.packageName;
+ String themePath = piTheme.applicationInfo.publicSourceDir;
+ if (!piTarget.isThemeApk && piTheme.mOverlayTargets.contains(basePackageName)) {
+ String targetPackagePath = piTarget.applicationInfo.sourceDir;
+ String prefixPath = ThemeUtils.getOverlayPathToTarget(basePackageName);
+
+ String resCachePath = ThemeUtils.getTargetCacheDir(piTarget.packageName,
+ piTheme.packageName);
+ String resApkPath = resCachePath + "/resources.apk";
+ String idmapPath = ThemeUtils.getIdmapPath(piTarget.packageName, piTheme.packageName);
+ int cookie = assets.addOverlayPath(idmapPath, themePath, resApkPath,
+ targetPackagePath, prefixPath);
+
+ if (cookie != 0) {
+ assets.setThemePackageName(themePackageName);
+ assets.addThemeCookie(cookie);
+ }
+ }
+
+ // Attach themed resources for cmsdk
+ if (!piTarget.isThemeApk && !piCm.packageName.equals(basePackageName) &&
+ piTheme.mOverlayTargets.contains(piCm.packageName)) {
+ String resCachePath= ThemeUtils.getTargetCacheDir(piCm.packageName,
+ piTheme.packageName);
+ String prefixPath = ThemeUtils.getOverlayPathToTarget(piCm.packageName);
+ String targetPackagePath = piCm.applicationInfo.publicSourceDir;
+ String resApkPath = resCachePath + "/resources.apk";
+ String idmapPath = ThemeUtils.getIdmapPath(piCm.packageName, piTheme.packageName);
+ int cookie = assets.addOverlayPath(idmapPath, themePath,
+ resApkPath, targetPackagePath, prefixPath);
+ if (cookie != 0) {
+ assets.setThemePackageName(themePackageName);
+ assets.addThemeCookie(cookie);
+ }
+ }
+
+ // Attach themed resources for android framework
+ if (!piTarget.isThemeApk && !"android".equals(basePackageName) &&
+ piTheme.mOverlayTargets.contains("android")) {
+ String resCachePath= ThemeUtils.getTargetCacheDir(piAndroid.packageName,
+ piTheme.packageName);
+ String prefixPath = ThemeUtils.getOverlayPathToTarget(piAndroid.packageName);
+ String targetPackagePath = piAndroid.applicationInfo.publicSourceDir;
+ String resApkPath = resCachePath + "/resources.apk";
+ String idmapPath = ThemeUtils.getIdmapPath("android", piTheme.packageName);
+ int cookie = assets.addOverlayPath(idmapPath, themePath,
+ resApkPath, targetPackagePath, prefixPath);
+ if (cookie != 0) {
+ assets.setThemePackageName(themePackageName);
+ assets.addThemeCookie(cookie);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Attach the necessary icon asset paths. Icon assets should be in a different
+ * namespace than the standard 0x7F.
+ *
+ * @param assets
+ * @param theme
+ * @return true if succes, false otherwise
+ */
+ private boolean attachIconAssets(AssetManager assets, ThemeConfig theme) {
+ PackageInfo piIcon = null;
+ try {
+ piIcon = getPackageManager().getPackageInfo(theme.getIconPackPkgName(), 0,
+ UserHandle.getCallingUserId());
+ } catch (RemoteException e) {
+ }
+
+ if (piIcon == null || piIcon.applicationInfo == null) {
+ return false;
+ }
+
+ String iconPkg = theme.getIconPackPkgName();
+ if (iconPkg != null && !iconPkg.isEmpty()) {
+ String themeIconPath = piIcon.applicationInfo.publicSourceDir;
+ String prefixPath = ThemeUtils.ICONS_PATH;
+ String iconDir = ThemeUtils.getIconPackDir(iconPkg);
+ String resTablePath = iconDir + "/resources.arsc";
+ String resApkPath = iconDir + "/resources.apk";
+
+ // Legacy Icon packs have everything in their APK
+ if (piIcon.isLegacyIconPackApk) {
+ prefixPath = "";
+ resApkPath = "";
+ resTablePath = "";
+ }
+
+ int cookie = assets.addIconPath(themeIconPath, resApkPath, prefixPath,
+ Resources.THEME_ICON_PKG_ID);
+ if (cookie != 0) {
+ assets.setIconPackCookie(cookie);
+ assets.setIconPackageName(iconPkg);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Attach the necessary common asset paths. Common assets should be in a different
+ * namespace than the standard 0x7F.
+ *
+ * @param assets
+ * @param theme
+ * @return true if succes, false otherwise
+ */
+ private boolean attachCommonAssets(AssetManager assets, ThemeConfig theme) {
+ // Some apps run in process of another app (eg keyguard/systemUI) so we must get the
+ // package name from the res tables. The 0th base package name will be the android group.
+ // The 1st base package name will be the app group if one is attached. Check if it is there
+ // first or else the system will crash!
+ String basePackageName;
+ int count = assets.getBasePackageCount();
+ if (count > NUM_DEFAULT_ASSETS) {
+ basePackageName = assets.getBasePackageName(NUM_DEFAULT_ASSETS);
+ } else if (count == NUM_DEFAULT_ASSETS) {
+ basePackageName = assets.getBasePackageName(0);
+ } else {
+ return false;
+ }
+
+ PackageInfo piTheme = null;
+ try {
+ piTheme = getPackageManager().getPackageInfo(
+ theme.getOverlayPkgNameForApp(basePackageName), 0,
+ UserHandle.getCallingUserId());
+ } catch (RemoteException e) {
+ }
+
+ if (piTheme == null || piTheme.applicationInfo == null) {
+ return false;
+ }
+
+ String themePackageName =
+ ThemeUtils.getCommonPackageName(piTheme.applicationInfo.packageName);
+ if (themePackageName != null && !themePackageName.isEmpty()) {
+ String themePath = piTheme.applicationInfo.publicSourceDir;
+ String prefixPath = ThemeUtils.COMMON_RES_PATH;
+ String resCachePath =
+ ThemeUtils.getTargetCacheDir(ThemeUtils.COMMON_RES_TARGET, piTheme.packageName);
+ String resApkPath = resCachePath + "/resources.apk";
+ int cookie = assets.addCommonOverlayPath(themePath, resApkPath,
+ prefixPath);
+ if (cookie != 0) {
+ assets.setCommonResCookie(cookie);
+ assets.setCommonResPackageName(themePackageName);
+ }
+ }
+
+ return true;
+ }
+
+ private void detachThemeAssets(AssetManager assets) {
+ String themePackageName = assets.getThemePackageName();
+ String iconPackageName = assets.getIconPackageName();
+ String commonResPackageName = assets.getCommonResPackageName();
+
+ //Remove Icon pack if it exists
+ if (!TextUtils.isEmpty(iconPackageName) && assets.getIconPackCookie() > 0) {
+ assets.removeOverlayPath(iconPackageName, assets.getIconPackCookie());
+ assets.setIconPackageName(null);
+ assets.setIconPackCookie(0);
+ }
+ //Remove common resources if it exists
+ if (!TextUtils.isEmpty(commonResPackageName) && assets.getCommonResCookie() > 0) {
+ assets.removeOverlayPath(commonResPackageName, assets.getCommonResCookie());
+ assets.setCommonResPackageName(null);
+ assets.setCommonResCookie(0);
+ }
+ final List<Integer> themeCookies = assets.getThemeCookies();
+ if (!TextUtils.isEmpty(themePackageName) && !themeCookies.isEmpty()) {
+ // remove overlays in reverse order
+ for (int i = themeCookies.size() - 1; i >= 0; i--) {
+ assets.removeOverlayPath(themePackageName, themeCookies.get(i));
+ }
+ }
+ assets.getThemeCookies().clear();
+ assets.setThemePackageName(null);
+ }
+
+ private ThemeConfig getThemeConfig() {
+ final Configuration config = getConfiguration();
+ return config != null ? config.themeConfig : null;
+ }
}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 5e8ad68..fad3f62 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -92,6 +92,7 @@ public class StatusBarManager {
public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0;
public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1;
+ public static final int CAMERA_LAUNCH_SOURCE_SCREEN_GESTURE = 2;
private Context mContext;
private IStatusBarService mService;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 3d264c6..34c967f 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -254,7 +254,9 @@ final class SystemServiceRegistry {
new StaticServiceFetcher<BatteryManager>() {
@Override
public BatteryManager createService() {
- return new BatteryManager();
+ IBinder b = ServiceManager.getService(Context.BATTERY_SERVICE);
+ IBatteryService service = IBatteryService.Stub.asInterface(b);
+ return new BatteryManager(service);
}});
registerService(Context.NFC_SERVICE, NfcManager.class,
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 22e79b6..045ee39 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -33,6 +33,7 @@ import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
@@ -230,9 +231,10 @@ public class WallpaperManager {
private IWallpaperManager mService;
private Bitmap mWallpaper;
private Bitmap mDefaultWallpaper;
+ private Bitmap mKeyguardWallpaper;
private static final int MSG_CLEAR_WALLPAPER = 1;
-
+
Globals(Looper looper) {
IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
mService = IWallpaperManager.Stub.asInterface(b);
@@ -250,6 +252,12 @@ public class WallpaperManager {
}
}
+ public void onKeyguardWallpaperChanged() {
+ synchronized (this) {
+ mKeyguardWallpaper = null;
+ }
+ }
+
public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
synchronized (this) {
if (mService != null) {
@@ -285,6 +293,23 @@ public class WallpaperManager {
}
}
+ /**
+ * @hide
+ */
+ public Bitmap peekKeyguardWallpaperBitmap(Context context) {
+ synchronized (this) {
+ if (mKeyguardWallpaper != null) {
+ return mKeyguardWallpaper;
+ }
+ try {
+ mKeyguardWallpaper = getCurrentKeyguardWallpaperLocked(context);
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "No memory load current keyguard wallpaper", e);
+ }
+ return mKeyguardWallpaper;
+ }
+ }
+
public void forgetLoadedWallpaper() {
synchronized (this) {
mWallpaper = null;
@@ -292,6 +317,12 @@ public class WallpaperManager {
}
}
+ public void forgetLoadedKeyguardWallpaper() {
+ synchronized (this) {
+ mKeyguardWallpaper = null;
+ }
+ }
+
private Bitmap getCurrentWallpaperLocked(Context context) {
if (mService == null) {
Log.w(TAG, "WallpaperService not running");
@@ -321,7 +352,37 @@ public class WallpaperManager {
}
return null;
}
-
+
+ private Bitmap getCurrentKeyguardWallpaperLocked(Context context) {
+ if (mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return null;
+ }
+ try {
+ Bundle params = new Bundle();
+ ParcelFileDescriptor fd = mService.getKeyguardWallpaper(this, params);
+ if (fd != null) {
+ try {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ Bitmap bm = BitmapFactory.decodeFileDescriptor(
+ fd.getFileDescriptor(), null, options);
+ return bm;
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "Can't decode file", e);
+ } finally {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ return null;
+ }
+
private Bitmap getDefaultWallpaperLocked(Context context) {
InputStream is = openDefaultWallpaper(context);
if (is != null) {
@@ -340,6 +401,18 @@ public class WallpaperManager {
}
return null;
}
+
+ /** @hide */
+ public void clearKeyguardWallpaper() {
+ synchronized (this) {
+ try {
+ mService.clearKeyguardWallpaper();
+ } catch (RemoteException e) {
+ // ignore
+ }
+ mKeyguardWallpaper = null;
+ }
+ }
}
private static final Object sSync = new Object[0];
@@ -599,6 +672,15 @@ public class WallpaperManager {
return null;
}
+ /** @hide */
+ public Drawable getFastKeyguardDrawable() {
+ Bitmap bm = sGlobals.peekKeyguardWallpaperBitmap(mContext);
+ if (bm != null) {
+ return new FastBitmapDrawable(bm);
+ }
+ return null;
+ }
+
/**
* Like {@link #getFastDrawable()}, but if there is no wallpaper set,
* a null pointer is returned.
@@ -624,6 +706,13 @@ public class WallpaperManager {
}
/**
+ * @hide
+ */
+ public Bitmap getKeyguardBitmap() {
+ return sGlobals.peekKeyguardWallpaperBitmap(mContext);
+ }
+
+ /**
* Remove all internal references to the last loaded wallpaper. Useful
* for apps that want to reduce memory usage when they only temporarily
* need to have the wallpaper. After calling, the next request for the
@@ -636,6 +725,13 @@ public class WallpaperManager {
}
/**
+ * @hide
+ */
+ public void forgetLoadedKeyguardWallpaper() {
+ sGlobals.forgetLoadedKeyguardWallpaper();
+ }
+
+ /**
* If the current wallpaper is a live wallpaper component, return the
* information about that wallpaper. Otherwise, if it is a static image,
* simply return null.
@@ -787,6 +883,36 @@ public class WallpaperManager {
}
/**
+ * @param bitmap
+ * @throws IOException
+ * @hide
+ */
+ public void setKeyguardBitmap(Bitmap bitmap) throws IOException {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return;
+ }
+ try {
+ ParcelFileDescriptor fd = sGlobals.mService.setKeyguardWallpaper(null,
+ mContext.getOpPackageName());
+ if (fd == null) {
+ return;
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ }
+
+ /**
* Change the current system wallpaper to a specific byte stream. The
* give InputStream is copied into persistent storage and will now be
* used as the wallpaper. Currently it must be either a JPEG or PNG
@@ -826,6 +952,34 @@ public class WallpaperManager {
}
}
+ /**
+ * @hide
+ */
+ public void setKeyguardStream(InputStream data) throws IOException {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return;
+ }
+ try {
+ ParcelFileDescriptor fd = sGlobals.mService.setKeyguardWallpaper(null,
+ mContext.getOpPackageName());
+ if (fd == null) {
+ return;
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ setWallpaper(data, fos);
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ }
+
private void setWallpaper(InputStream data, FileOutputStream fos)
throws IOException {
byte[] buffer = new byte[32768];
@@ -1088,7 +1242,29 @@ public class WallpaperManager {
mWallpaperXStep = xStep;
mWallpaperYStep = yStep;
}
-
+
+ /** @hide */
+ public int getLastWallpaperX() {
+ try {
+ return WindowManagerGlobal.getWindowSession().getLastWallpaperX();
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+
+ return -1;
+ }
+
+ /** @hide */
+ public int getLastWallpaperY() {
+ try {
+ return WindowManagerGlobal.getWindowSession().getLastWallpaperY();
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+
+ return -1;
+ }
+
/**
* Send an arbitrary command to the current active wallpaper.
*
@@ -1162,7 +1338,25 @@ public class WallpaperManager {
* wallpaper.
*/
public void clear() throws IOException {
- setStream(openDefaultWallpaper(mContext));
+ clear(true);
+ }
+
+ /** @hide */
+ public void clear(boolean setToDefault) throws IOException {
+ if (setToDefault) {
+ setStream(openDefaultWallpaper(mContext));
+ } else {
+ Bitmap blackBmp = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);
+ blackBmp.setPixel(0, 0, mContext.getResources().getColor(android.R.color.black));
+ setBitmap(blackBmp);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void clearKeyguardWallpaper() {
+ sGlobals.clearKeyguardWallpaper();
}
/**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e3414d9..5b9d9d5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4461,4 +4461,24 @@ public class DevicePolicyManager {
return PERMISSION_GRANT_STATE_DEFAULT;
}
}
+
+ /**
+ * CM: check if secure keyguard is required
+ * @hide
+ */
+ public boolean requireSecureKeyguard() {
+ return requireSecureKeyguard(UserHandle.myUserId());
+ }
+
+ /** @hide */
+ public boolean requireSecureKeyguard(int userHandle) {
+ if (mService != null) {
+ try {
+ return mService.requireSecureKeyguard(userHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get secure keyguard requirement");
+ }
+ }
+ return true;
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 376a3d8..a40507b 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -234,4 +234,6 @@ interface IDevicePolicyManager {
boolean setPermissionGrantState(in ComponentName admin, String packageName,
String permission, int grantState);
int getPermissionGrantState(in ComponentName admin, String packageName, String permission);
+
+ boolean requireSecureKeyguard(int userHandle);
}
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 7718a36..0335e28 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -21,6 +21,8 @@ import android.content.pm.PackageManager;
import android.content.res.XmlResourceParser;
import android.os.*;
import android.os.Process;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
@@ -207,6 +209,8 @@ public class FullBackup {
final int mFullBackupContent;
final PackageManager mPackageManager;
+ final StorageManager mStorageManager;
+ final StorageVolume[] mVolumes;
final String mPackageName;
/**
@@ -230,6 +234,15 @@ public class FullBackup {
} else {
return null;
}
+ } else if (domainToken.startsWith(FullBackup.SHARED_PREFIX)) {
+ int slash = domainToken.indexOf('/');
+ int i = Integer.parseInt(domainToken.substring(slash + 1));
+
+ if (i < mVolumes.length) {
+ return mVolumes[i].getPath();
+ } else {
+ Log.e(TAG, "Could not find volume for " + domainToken);
+ }
} else if (domainToken.equals(FullBackup.NO_BACKUP_TREE_TOKEN)) {
return NOBACKUP_DIR.getCanonicalPath();
}
@@ -263,6 +276,8 @@ public class FullBackup {
SHAREDPREF_DIR = context.getSharedPrefsFile("foo").getParentFile();
CACHE_DIR = context.getCacheDir();
NOBACKUP_DIR = context.getNoBackupFilesDir();
+ mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
+ mVolumes = mStorageManager.getVolumeList();
if (android.os.Process.myUid() != Process.SYSTEM_UID) {
EXTERNAL_DIR = context.getExternalFilesDir(null);
} else {
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index 2e27345..74302f2 100644..100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -371,6 +371,89 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
}
/**
+ * Set priority of the profile
+ *
+ * <p> The device should already be paired.
+ * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
+ * {@link #PRIORITY_OFF},
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Paired bluetooth device
+ * @param priority
+ * @return true if priority is set, false on error
+ * @hide
+ */
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setPriority(" + device + ", " + priority + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ if (priority != BluetoothProfile.PRIORITY_OFF &&
+ priority != BluetoothProfile.PRIORITY_ON){
+ return false;
+ }
+ try {
+ return mService.setPriority(device, priority);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Get the priority of the profile.
+ *
+ * <p> The priority can be any of:
+ * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
+ * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param device Bluetooth device
+ * @return priority of the device
+ * @hide
+ */
+ public int getPriority(BluetoothDevice device) {
+ if (VDBG) log("getPriority(" + device + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mService.getPriority(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.PRIORITY_OFF;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.PRIORITY_OFF;
+ }
+
+ /**
+ * Check if A2DP profile is streaming music.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param device BluetoothDevice device
+ */
+ public boolean isA2dpPlaying(BluetoothDevice device) {
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mService.isA2dpPlaying(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
* Helper for converting a state to a string.
*
* For debug use only - strings are not internationalized.
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 1f3ff51..71183d9 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1,6 +1,8 @@
/*
* Copyright (C) 2009-2015 The Android Open Source Project
* Copyright (C) 2015 Samsung LSI
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +25,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.app.ActivityThread;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
@@ -92,7 +95,7 @@ import java.util.UUID;
*/
public final class BluetoothAdapter {
private static final String TAG = "BluetoothAdapter";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false;
/**
@@ -538,6 +541,7 @@ public final class BluetoothAdapter {
* @throws IllegalArgumentException if address is invalid
*/
public BluetoothDevice getRemoteDevice(String address) {
+ android.util.SeempLog.record(62);
return new BluetoothDevice(address);
}
@@ -553,6 +557,7 @@ public final class BluetoothAdapter {
* @throws IllegalArgumentException if address is invalid
*/
public BluetoothDevice getRemoteDevice(byte[] address) {
+ android.util.SeempLog.record(62);
if (address == null || address.length != 6) {
throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
}
@@ -762,7 +767,7 @@ public final class BluetoothAdapter {
try {
if (DBG) Log.d(TAG, "Calling enableBLE");
mManagerService.updateBleAppCount(mToken, true);
- return mManagerService.enable();
+ return mManagerService.enable(ActivityThread.currentPackageName());
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -784,6 +789,7 @@ public final class BluetoothAdapter {
@RequiresPermission(Manifest.permission.BLUETOOTH)
@AdapterState
public int getState() {
+ android.util.SeempLog.record(63);
try {
synchronized(mManagerCallback) {
if (mService != null)
@@ -880,6 +886,7 @@ public final class BluetoothAdapter {
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean enable() {
+ android.util.SeempLog.record(56);
int state = STATE_OFF;
if (isEnabled() == true){
if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
@@ -898,7 +905,7 @@ public final class BluetoothAdapter {
return true;
}
try {
- return mManagerService.enable();
+ return mManagerService.enable(ActivityThread.currentPackageName());
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -929,6 +936,7 @@ public final class BluetoothAdapter {
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean disable() {
+ android.util.SeempLog.record(57);
try {
return mManagerService.disable(true);
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -946,6 +954,7 @@ public final class BluetoothAdapter {
* @hide
*/
public boolean disable(boolean persist) {
+ android.util.SeempLog.record(57);
try {
return mManagerService.disable(persist);
@@ -1190,6 +1199,7 @@ public final class BluetoothAdapter {
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean startDiscovery() {
+ android.util.SeempLog.record(58);
if (getState() != STATE_ON) return false;
try {
synchronized(mManagerCallback) {
@@ -1408,6 +1418,7 @@ public final class BluetoothAdapter {
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
public Set<BluetoothDevice> getBondedDevices() {
+ android.util.SeempLog.record(61);
if (getState() != STATE_ON) {
return toDeviceSet(new BluetoothDevice[0]);
}
@@ -1460,6 +1471,7 @@ public final class BluetoothAdapter {
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
public int getProfileConnectionState(int profile) {
+ android.util.SeempLog.record(64);
if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
try {
synchronized(mManagerCallback) {
@@ -1582,6 +1594,7 @@ public final class BluetoothAdapter {
@RequiresPermission(Manifest.permission.BLUETOOTH)
public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
throws IOException {
+ android.util.SeempLog.record(59);
return createNewRfcommSocketAndRecord(name, uuid, false, false);
}
@@ -1754,6 +1767,117 @@ public final class BluetoothAdapter {
return listenUsingL2capOn(port, false, false);
}
+
+ /**
+ * Construct an insecure L2CAP server socket.
+ * Call #accept to retrieve connections to this socket.
+ * <p>To auto assign a port without creating a SDP record use
+ * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
+ * @param port the PSM to listen on
+ * @return An L2CAP BluetoothServerSocket
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient permissions.
+ * @hide
+ */
+ public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException {
+ BluetoothServerSocket socket = new BluetoothServerSocket(
+ BluetoothSocket.TYPE_L2CAP, false, false, port, false, false);
+ int errno = socket.mSocket.bindListen();
+ if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
+ socket.setChannel(socket.mSocket.getPort());
+ }
+ if (errno != 0) {
+ //TODO(BT): Throw the same exception error code
+ // that the previous code was using.
+ //socket.mSocket.throwErrnoNative(errno);
+ throw new IOException("Error: " + errno);
+ }
+ return socket;
+
+ }
+
+ /**
+ * Create a client side Message Access Profile Service Record.
+ * Create the record once, and reuse it for all connections.
+ * If changes to a record is needed remove the old record using {@link removeSdpRecord}
+ * and then create a new one.
+ * WARNING: This API requires removeSdpRecord() to be called, to avoid leaking resources!
+ * A second call to this function - either from two different apps or from the
+ * same app, without first calling removeSdpRecord() - will make the device
+ * break the Bluetooth spec, which could lead to severe IOP issues.
+ * @param serviceName The textual name of the service
+ * @param rfcommChannel The RFCOMM channel that clients can connect to
+ * (obtain from BluetoothServerSocket)
+ * @param l2capPsm The L2CAP PSM channel that clients can connect to
+ * (obtain from BluetoothServerSocket)
+ * Supply -1 to omit the L2CAP PSM from the record.
+ * @param version The Profile version number (As specified in the Bluetooth
+ * MAP specification)
+ * @param features The feature bit mask (As specified in the Bluetooth
+ * MAP specification)
+ * @return a handle to the record created. The record can be removed again
+ * using {@link removeSdpRecord}(). The record is not linked to the
+ * creation/destruction of BluetoothSockets, hence SDP record cleanup
+ * is a separate process.
+ * returns -1 if an error occure and the record was not created.
+ * @hide
+ */
+ public int createMapMnsSdpRecord(String serviceName, int rfcommChannel,
+ int l2capPsm, int version, int features) {
+ try {
+ return mService.createMapMnsSdpRecord(serviceName, rfcommChannel,
+ l2capPsm, version, features);
+ } catch (RemoteException e) {
+ Log.e(TAG, "createMapMnsSdpRecord: ", e);
+ }
+ return -1;
+ }
+
+ /**
+ * Create a client side Phonebook Access Profile Service Record.
+ * Create the record once, and reuse it for all connections.
+ * If changes to a record is needed remove the old record using {@link removeSdpRecord}
+ * and then create a new one.
+ * WARNING: This API requires removeSdpRecord() to be called, to avoid leaking resources!
+ * A second call to this function - either from two different apps or from the
+ * same app, without first calling removeSdpRecord() - will make the device
+ * break the Bluetooth spec, which could lead to severe IOP issues.
+ * @param serviceName The textual name of the service
+ * @param version The Profile version number (As specified in the Bluetooth
+ * PBAP specification)
+ * @return a handle to the record created. The record can be removed again
+ * using {@link removeSdpRecord}(). The record is not linked to the
+ * creation/destruction of BluetoothSockets, hence SDP record cleanup
+ * is a separate process.
+ * returns -1 if an error occure and the record was not created.
+ * @hide
+ */
+ public int createPbapPceSdpRecord(String serviceName, int version) {
+ try {
+ return mService.createPbapPceSdpRecord(serviceName, version);
+ } catch (RemoteException e) {
+ Log.e(TAG, "createPbapPceSdpRecord: ", e);
+ }
+ return -1;
+ }
+
+ /**
+ * Remove a SDP record created using createSdpRecord().
+ * This function shall be called before a new call to createSdpRecord for the same record
+ * type can be made, unless the record type created supports multiple instances.
+ * @param recordHandle handle of the record to remove - provided by createSdpRecord()
+ * @return true if success
+ * @hide
+ */
+ public boolean removeSdpRecord(int recordHandle){
+ try {
+ return mService.removeSdpRecord(recordHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "removeSdpRecord: ", e);
+ }
+ return false;
+ }
+
/**
* Read the local Out of Band Pairing Data
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
@@ -1825,6 +1949,9 @@ public final class BluetoothAdapter {
} else if (profile == BluetoothProfile.PAN) {
BluetoothPan pan = new BluetoothPan(context, listener);
return true;
+ } else if (profile == BluetoothProfile.DUN) {
+ BluetoothDun dun = new BluetoothDun(context, listener);
+ return true;
} else if (profile == BluetoothProfile.HEALTH) {
BluetoothHealth health = new BluetoothHealth(context, listener);
return true;
@@ -1837,6 +1964,9 @@ public final class BluetoothAdapter {
} else if (profile == BluetoothProfile.SAP) {
BluetoothSap sap = new BluetoothSap(context, listener);
return true;
+ } else if (profile == BluetoothProfile.HID_DEVICE) {
+ BluetoothHidDevice hidd = new BluetoothHidDevice(context, listener);
+ return true;
} else {
return false;
}
@@ -1881,6 +2011,10 @@ public final class BluetoothAdapter {
BluetoothPan pan = (BluetoothPan)proxy;
pan.close();
break;
+ case BluetoothProfile.DUN:
+ BluetoothDun dun = (BluetoothDun)proxy;
+ dun.close();
+ break;
case BluetoothProfile.HEALTH:
BluetoothHealth health = (BluetoothHealth)proxy;
health.close();
@@ -1905,6 +2039,10 @@ public final class BluetoothAdapter {
BluetoothSap sap = (BluetoothSap)proxy;
sap.close();
break;
+ case BluetoothProfile.HID_DEVICE:
+ BluetoothHidDevice hidd = (BluetoothHidDevice) proxy;
+ hidd.close();
+ break;
}
}
@@ -1929,13 +2067,14 @@ public final class BluetoothAdapter {
}
public void onBluetoothServiceDown() {
- if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
+ Log.d(TAG, "onBluetoothServiceDown: " + mService);
synchronized (mManagerCallback) {
mService = null;
if (mLeScanClients != null) mLeScanClients.clear();
if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup();
if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup();
synchronized (mProxyServiceStateCallbacks) {
+ Log.d(TAG, "onBluetoothServiceDown: Sending callbacks to " + mProxyServiceStateCallbacks.size() + " clients");
for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
try {
if (cb != null) {
@@ -1947,6 +2086,7 @@ public final class BluetoothAdapter {
}
}
}
+ Log.d(TAG, "onBluetoothServiceDown: Finished sending callbacks to registered clients");
}
public void onBrEdrDown() {
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
index b53a8fc..4851087 100644
--- a/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -210,7 +211,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
}
public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
- if (DBG) Log.d(TAG, "sendPassThroughCmd");
+ if (DBG) Log.d(TAG, "sendPassThroughCmd dev = " + device + " key " + keyCode + " State = " + keyState);
if (mService != null && isEnabled()) {
try {
mService.sendPassThroughCmd(device, keyCode, keyState);
@@ -223,6 +224,90 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
if (mService == null) Log.w(TAG, "Proxy not attached to service");
}
+ public void getMetaData(int[] attributeIds) {
+ if (DBG) Log.d(TAG, "getMetaData num requested Ids = " + attributeIds.length);
+ if (mService != null && isEnabled()) {
+ try {
+ mService.getMetaData(attributeIds);
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in getMetaData", e);
+ return;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ }
+
+ public void getPlayStatus(int[] playStatusIds) {
+ if (DBG) Log.d(TAG, "getPlayStatus num requested Ids = "+ playStatusIds.length);
+ if (mService != null && isEnabled()) {
+ try {
+ mService.getPlayStatus(playStatusIds);
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in getPlayStatus()", e);
+ return;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ }
+
+ public void getPlayerApplicationSetting() {
+ if (DBG) Log.d(TAG, "getPlayerApplicationSetting");
+ if (mService != null && isEnabled()) {
+ try {
+ mService.getPlayerApplicationSetting();
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in getPlayerApplicationSetting()", e);
+ return;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ }
+
+ public void setPlayerApplicationSetting(int attributeId, int attributeVal) {
+ if (DBG) Log.d(TAG, "setPlayerApplicationSetting attribId = " + attributeId + " attribVal = " + attributeVal);
+ if (mService != null && isEnabled()) {
+ try {
+ mService.setPlayerApplicationSetting(attributeId, attributeVal);
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in setPlayerApplicationSetting()", e);
+ return;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ }
+
+ public BluetoothAvrcpInfo getSupportedPlayerAppSetting(BluetoothDevice device) {
+ if (DBG) Log.d(TAG, "getSupportedPlayerAppSetting dev = " + device);
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getSupportedPlayerAppSetting(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in getSupportedPlayerAppSetting()", e);
+ return null;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return null;
+ }
+
+ public int getSupportedFeatures(BluetoothDevice device) {
+ if (DBG) Log.d(TAG, "getSupportedFeatures dev = " + device);
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getSupportedFeatures(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in getSupportedFeatures()", e);
+ return 0;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return 0;
+ }
+
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
diff --git a/core/java/android/bluetooth/BluetoothAvrcpInfo.aidl b/core/java/android/bluetooth/BluetoothAvrcpInfo.aidl
new file mode 100644
index 0000000..9b85c80
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAvrcpInfo.aidl
@@ -0,0 +1,34 @@
+/*
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothAvrcpInfo;
diff --git a/core/java/android/bluetooth/BluetoothAvrcpInfo.java b/core/java/android/bluetooth/BluetoothAvrcpInfo.java
new file mode 100644
index 0000000..a815d10
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAvrcpInfo.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package android.bluetooth;
+
+import java.util.ArrayList;
+import android.util.Log;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.BaseColumns;
+import android.net.Uri;
+
+/**
+ * Represents the AVRCP Metadata of remote Bluetooth Device.
+ *
+ * {@see BluetoothAvrcpController}
+ *
+ * {@hide}
+ */
+public final class BluetoothAvrcpInfo implements Parcelable, BaseColumns{
+
+ private byte[] supportedPlayerAttributes;// attributes supported
+ private byte[] numSupportedPlayerAttribValues; // number of values of each attribute
+ private String TAG = "BluetoothAvrcpInfo";
+ /*
+ * This would a list of values of all AttributeIds
+ */
+ private byte[] supportedPlayerAtribValues; // actual values lies here.
+
+ /* Default Constructor */
+ public BluetoothAvrcpInfo() {
+ supportedPlayerAttributes = null;
+ numSupportedPlayerAttribValues = null;
+ supportedPlayerAtribValues = null;
+ }
+ public BluetoothAvrcpInfo(byte[] attribIds, byte[] numValueSupported, byte[] valuesSupported) {
+ int numAttributes = attribIds.length;
+ int zz = 0;
+ supportedPlayerAttributes = new byte[numAttributes];
+ numSupportedPlayerAttribValues = new byte[numAttributes];
+ supportedPlayerAtribValues = new byte[valuesSupported.length];
+ for (zz = 0; zz < numAttributes; zz++) {
+ supportedPlayerAttributes[zz] = attribIds[zz];
+ numSupportedPlayerAttribValues[zz] = numValueSupported[zz];
+ }
+ for (zz = 0; zz < supportedPlayerAtribValues.length; zz++)
+ supportedPlayerAtribValues[zz] = valuesSupported[zz];
+ }
+ /*
+ * Reading Structure back from Paracel
+ */
+ public BluetoothAvrcpInfo(Parcel source){
+ ArrayList<Byte> attribs = new ArrayList<Byte>();
+ ArrayList<Byte> numAttribVal = new ArrayList<Byte>();
+ ArrayList<Byte> attribVals = new ArrayList<Byte>();
+ Byte numAttributes = source.readByte();
+ /*
+ * Read from Source
+ */
+ for(int xx = 0; xx < numAttributes ; xx++) {
+ attribs.add(source.readByte());
+ numAttribVal.add(source.readByte());
+ for (int zz = 0; zz < numAttribVal.get(xx); zz++) {
+ attribVals.add(source.readByte());
+ }
+ }
+
+ /*
+ * Write Back to Private Data Structures
+ */
+ supportedPlayerAttributes = new byte[attribs.size()];
+ for (int zz = 0; zz< attribs.size(); zz++) {
+ supportedPlayerAttributes[zz] = attribs.get(zz);
+ }
+
+ numSupportedPlayerAttribValues = new byte[numAttribVal.size()];
+ for (int zz = 0; zz< numAttribVal.size(); zz++) {
+ numSupportedPlayerAttribValues[zz] = numAttribVal.get(zz);
+ }
+
+ supportedPlayerAtribValues = new byte[attribVals.size()];
+ for (int zz = 0; zz< attribVals.size(); zz++) {
+ supportedPlayerAtribValues[zz] = attribVals.get(zz);
+ }
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ /* While flatenning the structure we would use the follwing way
+ * NumAttributes,ID, numValues, Values
+ */
+ public void writeToParcel(Parcel out, int flags) {
+ byte numSuppAttributes = (byte)supportedPlayerAttributes.length;
+ out.writeByte(numSuppAttributes);
+ for (int xx = 0; xx < numSuppAttributes; xx++) {
+ out.writeByte(supportedPlayerAttributes[xx]);
+ out.writeByte(numSupportedPlayerAttribValues[xx]);
+ for (int zz = 0; zz < numSupportedPlayerAttribValues[xx]; zz++) {
+ out.writeByte(supportedPlayerAtribValues[zz]);
+ }
+ }
+ }
+
+ public byte[] getSupportedPlayerAttributes() {
+ return supportedPlayerAttributes;
+ }
+
+ public byte getNumSupportedPlayerAttributeVal(byte playerAttributeId) {
+ for (int zz = 0; zz < supportedPlayerAttributes.length; zz++) {
+ if (playerAttributeId == supportedPlayerAttributes[zz]) {
+ return numSupportedPlayerAttribValues[zz];
+ }
+ }
+ return 0;
+ }
+
+ public byte[] getSupportedPlayerAttributeVlaues (byte playerAttributeId) {
+ int index = 0;
+ int zz = 0;
+ boolean attributeFound = false;
+ for (zz = 0; zz < supportedPlayerAttributes.length; zz++) {
+ if (playerAttributeId == supportedPlayerAttributes[zz]) {
+ attributeFound = true;
+ break;
+ }
+ else
+ index = index + numSupportedPlayerAttribValues[zz];
+ }
+ if (attributeFound) {
+ byte[] supportedValues = new byte[numSupportedPlayerAttribValues[zz]];
+ for (int xx = 0; xx < numSupportedPlayerAttribValues[zz]; xx++)
+ supportedValues[xx] = supportedPlayerAtribValues[xx + index];
+ return supportedValues;
+ }
+ else
+ return new byte[0];
+ }
+ public void putPlayerSettingAttributes(byte[] attribIds, byte[] numValueSupported, byte[] valuesSupported) {
+ int numAttributes = attribIds.length;
+ int zz = 0;
+ supportedPlayerAttributes = new byte[numAttributes];
+ numSupportedPlayerAttribValues = new byte[numAttributes];
+ supportedPlayerAtribValues = new byte[valuesSupported.length];
+ for (zz = 0; zz < numAttributes; zz++) {
+ supportedPlayerAttributes[zz] = attribIds[zz];
+ numSupportedPlayerAttribValues[zz] = numValueSupported[zz];
+ }
+ for (zz = 0; zz < supportedPlayerAtribValues.length; zz++)
+ supportedPlayerAtribValues[zz] = valuesSupported[zz];
+ }
+ public static final Parcelable.Creator<BluetoothAvrcpInfo> CREATOR =
+ new Parcelable.Creator<BluetoothAvrcpInfo>() {
+ public BluetoothAvrcpInfo createFromParcel(Parcel in) {
+ return new BluetoothAvrcpInfo(in);
+ }
+ public BluetoothAvrcpInfo[] newArray(int size) {
+ return new BluetoothAvrcpInfo[size];
+ }
+ };
+
+ public static final String PERMISSION_ACCESS = "android.permission.ACCESS_BLUETOOTH_AVRCP_CT_DATA";
+ public static final Uri CONTENT_URI = Uri.parse("content://com.android.bluetooth.avrcp/btavrcp_ct");
+
+ /*
+ * BaseColumns already has _ID and COUNT values
+ * Below mentioned strings are used to implement different columns
+ * of AVRCP MetaData table.
+ * TRACK_NUM : Ineteger value containing the order number of
+ * the audio-file on its original recording.
+ * Numeric ASCII string converted to Integer
+ * TITLE : Text field representing the title, song name
+ * ARTIST_NAME : Text field representing artist(s), performer(s)
+ * ALBUM_NAME : Text field representing the title of the recording
+ * (source) from which the audio in the file is taken.
+ * TOTAL_TRACKS : Integet value containing the total number of tracks
+ * or elements on the original recording.
+ * GENRE : Text field representing the category of the composition
+ * characterized by a particular style.
+ * PLAYING_TIME : Integer containing the length of the audio file in
+ * milliseconds for eg 02:30 = 150000
+ * PLAY_STATUS : Text feild showing current state of track. Possible
+ * values would be Playing, Stopped, Paused, Forward_Seek
+ * REV_SEEK
+ * REPEAT_STATUS : String describing Repeat mode status on remote Media Player
+ * Posible values "NOT SUPPORTED", "OFF" "Single Track Repeat"
+ * "All Track Repeat" "Group Repeat"
+ * SHUFFLE_STATUS : String describing Shuffle mode status on remote Media Player
+ * Posible values "NOT SUPPORTED", "OFF" "All Track Shuffle"
+ * "Group Shuffle"
+ * SCAN_STAUS : String describing SCAN mode status on remote Media Player
+ * Possible values "NOT SUPPORTED", "OFF","ALL Tracks Scan"
+ * "Group Scan"
+ *
+ * EQUALIZER_STATUS: String describing EQUALIZER mode status on remote Media Player
+ * Possible values "NOT SUPPORTED", "OFF","ON"
+ */
+ public static final String TRACK_NUM = "track_num";
+ public static final String TITLE = "title";
+ public static final String ARTIST_NAME = "artist_name";
+ public static final String ALBUM_NAME = "album_name";
+ public static final String TOTAL_TRACKS = "total_tracks";
+ public static final String GENRE = "genre";
+ public static final String PLAYING_TIME = "playing_time";
+ public static final String TOTAL_TRACK_TIME = "total_track_time";
+ public static final String PLAY_STATUS = "play_status";
+ public static final String REPEAT_STATUS = "repeat_status";
+ public static final String SHUFFLE_STATUS = "shuffle_status";
+ public static final String SCAN_STATUS = "scan_status";
+ public static final String EQUALIZER_STATUS = "equalizer_status";
+
+ /*
+ * Default values for each of the items
+ */
+ public static final int TRACK_NUM_INVALID = 0xFF;
+ public static final String TITLE_INVALID = "NOT_SUPPORTED";
+ public static final String ARTIST_NAME_INVALID = "NOT_SUPPORTED";
+ public static final String ALBUM_NAME_INVALID = "NOT_SUPPORTED";
+ public static final int TOTAL_TRACKS_INVALID = 0xFF;
+ public static final String GENRE_INVALID = "NOT_SUPPORTED";
+ public static final int PLAYING_TIME_INVALID = 0xFF;
+ public static final int TOTAL_TRACK_TIME_INVALID = 0xFF;
+ public static final String PLAY_STATUS_INVALID = "NOT_SUPPORTED";
+ public static final String REPEAT_STATUS_INVALID = "NOT_SUPPORTED";
+ public static final String SHUFFLE_STATUS_INVALID = "NOT_SUPPORTED";
+ public static final String SCAN_STATUS_INVALID = "NOT_SUPPORTED";
+ public static final String EQUALIZER_STATUS_INVALID = "NOT_SUPPORTED";
+
+ /*
+ *Element Id Values for GetMetaData
+ */
+ public static final int MEDIA_ATTRIBUTE_ALL = 0x00;
+ public static final int MEDIA_ATTRIBUTE_TITLE = 0x01;
+ public static final int MEDIA_ATTRIBUTE_ARTIST_NAME = 0x02;
+ public static final int MEDIA_ATTRIBUTE_ALBUM_NAME = 0x03;
+ public static final int MEDIA_ATTRIBUTE_TRACK_NUMBER = 0x04;
+ public static final int MEDIA_ATTRIBUTE_TOTAL_TRACK_NUMBER = 0x05;
+ public static final int MEDIA_ATTRIBUTE_GENRE = 0x06;
+ public static final int MEDIA_ATTRIBUTE_PLAYING_TIME = 0x07;
+
+ /*
+ *PlayStatusId Values for GetPlayStatus
+ */
+ public static final int MEDIA_PLAYSTATUS_ALL = 0x08;
+ public static final int MEDIA_PLAYSTATUS_SONG_TOTAL_LEN = 0x09;
+ public static final int MEDIA_PLAYSTATUS_SONG_CUR_POS = 0x0a;
+ public static final int MEDIA_PLAYSTATUS_SONG_PLAY_STATUS = 0x0b;
+
+ /*
+ * Values for SetPlayerApplicationSettings
+ */
+ public static final byte ATTRIB_EQUALIZER_STATUS = 0x01;
+ public static final byte ATTRIB_REPEAT_STATUS = 0x02;
+ public static final byte ATTRIB_SHUFFLE_STATUS = 0x03;
+ public static final byte ATTRIB_SCAN_STATUS = 0x04;
+
+ public static final byte EQUALIZER_STATUS_OFF = 0x01;
+ public static final byte EQUALIZER_STATUS_ON = 0x02;
+
+ public static final byte REPEAT_STATUS_OFF = 0x01;
+ public static final byte REPEAT_STATUS_SINGLE_TRACK_REPEAT = 0x02;
+ public static final byte REPEAT_STATUS_ALL_TRACK_REPEAT = 0x03;
+ public static final byte REPEAT_STATUS_GROUP_REPEAT = 0x04;
+
+ public static final byte SHUFFLE_STATUS_OFF = 0x01;
+ public static final byte SHUFFLE_STATUS_ALL_TRACK_SHUFFLE = 0x02;
+ public static final byte SHUFFLE_STATUS_GROUP_SHUFFLE = 0x03;
+
+ public static final byte SCAN_STATUS_OFF = 0x01;
+ public static final byte SCAN_STATUS_ALL_TRACK_SCAN = 0x02;
+ public static final byte SCAN_STATUS_GROUP_SCAN = 0x03;
+
+ public static final int BTRC_FEAT_METADATA = 0x01;
+ public static final int BTRC_FEAT_ABSOLUTE_VOLUME = 0x02;
+ public static final int BTRC_FEAT_BROWSE = 0x04;
+
+}
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 54bf4af..4a38287 100644..100755
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -283,6 +283,8 @@ public final class BluetoothClass implements Parcelable {
public static final int PROFILE_PANU = 4;
/** @hide */
public static final int PROFILE_NAP = 5;
+ /** @hide */
+ public static final int PROFILE_A2DP_SINK = 6;
/**
* Check class bits for possible bluetooth profile support.
@@ -310,6 +312,21 @@ public final class BluetoothClass implements Parcelable {
default:
return false;
}
+ } else if (profile == PROFILE_A2DP_SINK) {
+ if (hasService(Service.CAPTURE)) {
+ return true;
+ }
+ // By the A2DP spec, srcs must indicate the CAPTURE service.
+ // However if some device that do not, we try to
+ // match on some other class bits.
+ switch (getDeviceClass()) {
+ case Device.AUDIO_VIDEO_HIFI_AUDIO:
+ case Device.AUDIO_VIDEO_SET_TOP_BOX:
+ case Device.AUDIO_VIDEO_VCR :
+ return true;
+ default:
+ return false;
+ }
} else if (profile == PROFILE_HEADSET) {
// The render service class is required by the spec for HFP, so is a
// pretty good signal
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index d27dfa0..b4006de 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -25,6 +25,7 @@ import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.ParcelUuid;
+import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
@@ -823,6 +824,9 @@ public final class BluetoothDevice implements Parcelable {
return false;
}
try {
+ Log.i(TAG, "createBond() for device " + getAddress() +
+ " called by pid: " + Process.myPid() +
+ " tid: " + Process.myTid());
return sService.createBond(this, TRANSPORT_AUTO);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
@@ -854,6 +858,9 @@ public final class BluetoothDevice implements Parcelable {
throw new IllegalArgumentException(transport + " is not a valid Bluetooth transport");
}
try {
+ Log.i(TAG, "createBond() for device " + getAddress() +
+ " called by pid: " + Process.myPid() +
+ " tid: " + Process.myTid());
return sService.createBond(this, transport);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
@@ -922,6 +929,9 @@ public final class BluetoothDevice implements Parcelable {
return false;
}
try {
+ Log.i(TAG, "cancelBondProcess() for device " + getAddress() +
+ " called by pid: " + Process.myPid() +
+ " tid: " + Process.myTid());
return sService.cancelBondProcess(this);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
@@ -943,6 +953,9 @@ public final class BluetoothDevice implements Parcelable {
return false;
}
try {
+ Log.i(TAG, "removeBond() for device " + getAddress() +
+ " called by pid: " + Process.myPid() +
+ " tid: " + Process.myTid());
return sService.removeBond(this);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
@@ -1390,6 +1403,27 @@ public final class BluetoothDevice implements Parcelable {
}
/**
+ * Create an L2cap {@link BluetoothSocket} ready to start an insecure
+ * outgoing connection to this remote device on given channel.
+ * <p>The remote device will be not authenticated and communication on this
+ * socket will not be encrypted.
+ * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
+ * connection.
+ * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+ *
+ * @param channel L2cap PSM/channel to connect to
+ * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions
+ * @hide
+ */
+ public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel,
+ null);
+ }
+
+ /**
* Create an RFCOMM {@link BluetoothSocket} ready to start a secure
* outgoing connection to this remote device using SDP lookup of uuid.
* <p>This is designed to be used with {@link
diff --git a/core/java/android/bluetooth/BluetoothDevicePicker.java b/core/java/android/bluetooth/BluetoothDevicePicker.java
index c794be2..51d14cc 100644
--- a/core/java/android/bluetooth/BluetoothDevicePicker.java
+++ b/core/java/android/bluetooth/BluetoothDevicePicker.java
@@ -44,6 +44,14 @@ public interface BluetoothDevicePicker {
"android.bluetooth.devicepicker.action.DEVICE_SELECTED";
/**
+ * Broadcast when no BT device is selected from BT device picker screen.
+ * This happens when user presses back button.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DEVICE_NOT_SELECTED =
+ "org.codeaurora.bluetooth.devicepicker.action.DEVICE_NOT_SELECTED";
+
+ /**
* Broadcast when someone want to select one BT device from devices list.
* This intent contains below extra data:
* - {@link #EXTRA_NEED_AUTH} (boolean): if need authentication
diff --git a/core/java/android/bluetooth/BluetoothDun.java b/core/java/android/bluetooth/BluetoothDun.java
new file mode 100644
index 0000000..0912061
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothDun.java
@@ -0,0 +1,296 @@
+/*
+*Copyright (c) 2013, The Linux Foundation. All rights reserved.
+*
+*Redistribution and use in source and binary forms, with or without
+*modification, are permitted provided that the following conditions are
+*met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+*THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+*WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+*ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+*BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+*CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+*SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+*WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+*OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+*IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+package android.bluetooth;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides the APIs to control the Bluetooth Dun
+ * Profile.
+ *
+ *<p>BluetoothDun is a proxy object for controlling the Bluetooth DUN
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothDun proxy object.
+ *
+ *<p>Each method is protected with its appropriate permission.
+ *@hide
+ */
+public final class BluetoothDun implements BluetoothProfile {
+ private static final String TAG = "BluetoothDun";
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ /**
+ * Intent used to broadcast the change in connection state of the Dun
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTED}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "codeaurora.bluetooth.dun.profile.action.CONNECTION_STATE_CHANGED";
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private BluetoothAdapter mAdapter;
+ private IBluetoothDun mDunService;
+
+ /**
+ * Create a BluetoothDun proxy object for interacting with the local
+ * Bluetooth Service which handles the Dun profile
+ *
+ */
+ /*package*/ BluetoothDun(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ try {
+ mAdapter.getBluetoothManager().registerStateChangeCallback(mStateChangeCallback);
+ } catch (RemoteException re) {
+ Log.w(TAG,"Unable to register BluetoothStateChangeCallback",re);
+ }
+ Log.d(TAG, "BluetoothDun() call bindService");
+ doBind();
+ }
+
+ boolean doBind() {
+ Intent intent = new Intent(IBluetoothDun.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth Dun Service with " + intent);
+ return false;
+ }
+ return true;
+ }
+
+
+ /*package*/ void close() {
+ if (VDBG) log("close()");
+ mServiceListener = null;
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mStateChangeCallback);
+ } catch (RemoteException re) {
+ Log.w(TAG,"Unable to unregister BluetoothStateChangeCallback",re);
+ }
+ }
+
+ synchronized (mConnection) {
+ if ( mDunService != null) {
+ try {
+ mDunService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+
+ protected void finalize() {
+ close();
+ }
+
+ private IBluetoothStateChangeCallback mStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+
+ @Override
+ public void onBluetoothStateChange(boolean on) {
+ //Handle enable request to bind again.
+ Log.d(TAG, "onBluetoothStateChange on: " + on);
+ if (on) {
+ try {
+ if (mDunService == null) {
+ Log.d(TAG, "onBluetoothStateChange call bindService");
+ doBind();
+ }
+ } catch (IllegalStateException e) {
+ Log.e(TAG,"onBluetoothStateChange: could not bind to DUN service: ", e);
+ } catch (SecurityException e) {
+ Log.e(TAG,"onBluetoothStateChange: could not bind to DUN service: ", e);
+ }
+ } else {
+ if (VDBG) Log.d(TAG,"Unbinding service...");
+ synchronized (mConnection) {
+ if ( mDunService != null) {
+ try {
+ mDunService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+ }
+ };
+
+ /**
+ * Initiate disconnection from DUN server.
+ *
+ * <p> Once the disconnection is initiated by any device either local host
+ * or remote device, the state will transition from {@link #STATE_CONNECTED}
+ * to {@link #STATE_DISCONNECTED}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error,
+ * true otherwise
+ * @hide
+ */
+ public boolean disconnect(BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ if (mDunService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mDunService.disconnect(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mDunService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ if (mDunService != null && isEnabled()) {
+ try {
+ return mDunService.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mDunService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ if (mDunService != null && isEnabled()) {
+ try {
+ return mDunService.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mDunService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getConnectionState(BluetoothDevice device) {
+ if (VDBG) log("getState(" + device + ")");
+ if (mDunService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mDunService.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (mDunService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "BluetoothDUN Proxy object connected");
+ mDunService = IBluetoothDun.Stub.asInterface(service);
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.DUN,
+ BluetoothDun.this);
+ }
+ }
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "BluetoothDUN Proxy object disconnected");
+ mDunService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.DUN);
+ }
+ }
+ };
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 25d9aa9..da81032 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -20,11 +20,11 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context;
-import android.os.Handler;
+import android.content.Intent;
+import android.content.ServiceConnection;
import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -47,7 +47,7 @@ import java.util.List;
public final class BluetoothHeadset implements BluetoothProfile {
private static final String TAG = "BluetoothHeadset";
private static final boolean DBG = true;
- private static final boolean VDBG = false;
+ private static final boolean VDBG = true;
/**
* Intent used to broadcast the change in connection state of the Headset
@@ -129,6 +129,13 @@ public final class BluetoothHeadset implements BluetoothProfile {
"android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
/**
+ * @hide Broadcast intent when HF indicator value changed is updated by HS.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_HF_INDICATOR_VALUE_CHANGED =
+ "codeaurora.bluetooth.headset.action.ACTION_HF_INDICATOR_VALUE_CHANGED";
+
+ /**
* A String extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
* intents that contains the name of the vendor-specific command.
*/
@@ -199,6 +206,20 @@ public final class BluetoothHeadset implements BluetoothProfile {
public static final String VENDOR_RESULT_CODE_COMMAND_ANDROID = "+ANDROID";
/**
+ * @hide Used for sharing the HF indicator assigned number.
+ */
+ public static final String HF_INDICATOR_ASSIGNED_NUMBER =
+ "codeaurora.bluetooth.headset.intent.category.anum";
+
+
+ /**
+ * @hide Used for sharing the HF indicator assigned number's value.
+ */
+ public static final String HF_INDICATOR_ASSIGNED_NUMBER_VALUE =
+ "codeaurora.bluetooth.headset.intent.category.anumvalue";
+
+
+ /**
* Headset state when SCO audio is not connected.
* This state can be one of
* {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
@@ -222,8 +243,6 @@ public final class BluetoothHeadset implements BluetoothProfile {
*/
public static final int STATE_AUDIO_CONNECTED = 12;
- private static final int MESSAGE_HEADSET_SERVICE_CONNECTED = 100;
- private static final int MESSAGE_HEADSET_SERVICE_DISCONNECTED = 101;
private Context mContext;
private ServiceListener mServiceListener;
@@ -236,7 +255,14 @@ public final class BluetoothHeadset implements BluetoothProfile {
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
if (!up) {
if (VDBG) Log.d(TAG,"Unbinding service...");
- doUnbind();
+ synchronized (mConnection) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
} else {
synchronized (mConnection) {
try {
@@ -273,26 +299,15 @@ public final class BluetoothHeadset implements BluetoothProfile {
}
boolean doBind() {
- try {
- return mAdapter.getBluetoothManager().bindBluetoothProfileService(
- BluetoothProfile.HEADSET, mConnection);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to bind HeadsetService", e);
- }
- return false;
- }
-
- void doUnbind() {
- synchronized (mConnection) {
- if (mService != null) {
- try {
- mAdapter.getBluetoothManager().unbindBluetoothProfileService(
- BluetoothProfile.HEADSET, mConnection);
- } catch (RemoteException e) {
- Log.e(TAG,"Unable to unbind HeadsetService", e);
- }
- }
+ Intent intent = new Intent(IBluetoothHeadset.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ UserHandle.CURRENT_OR_SELF)) {
+ Log.e(TAG, "Could not bind to Bluetooth Headset Service with " + intent);
+ return false;
}
+ return true;
}
/**
@@ -312,8 +327,18 @@ public final class BluetoothHeadset implements BluetoothProfile {
Log.e(TAG,"",e);
}
}
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
mServiceListener = null;
- doUnbind();
}
/**
@@ -685,6 +710,48 @@ public final class BluetoothHeadset implements BluetoothProfile {
}
/**
+ * Sets whether audio routing is allowed. When set to {@code false}, the AG will not route any
+ * audio to the HF unless explicitly told to.
+ * This method should be used in cases where the SCO channel is shared between multiple profiles
+ * and must be delegated by a source knowledgeable
+ * Note: This is an internal function and shouldn't be exposed
+ *
+ * @param allowed {@code true} if the profile can reroute audio, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public void setAudioRouteAllowed(boolean allowed) {
+ if (VDBG) log("setAudioRouteAllowed");
+ if (mService != null && isEnabled()) {
+ try {
+ mService.setAudioRouteAllowed(allowed);
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+
+ /**
+ * Returns whether audio routing is allowed. see {@link #setAudioRouteAllowed(boolean)}.
+ * Note: This is an internal function and shouldn't be exposed
+ *
+ * @hide
+ */
+ public boolean getAudioRouteAllowed() {
+ if (VDBG) log("getAudioRouteAllowed");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getAudioRouteAllowed();
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
* Check if Bluetooth SCO audio is connected.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
@@ -927,21 +994,21 @@ public final class BluetoothHeadset implements BluetoothProfile {
return false;
}
- private final IBluetoothProfileServiceConnection mConnection
- = new IBluetoothProfileServiceConnection.Stub() {
- @Override
+ private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
mService = IBluetoothHeadset.Stub.asInterface(service);
- mHandler.sendMessage(mHandler.obtainMessage(
- MESSAGE_HEADSET_SERVICE_CONNECTED));
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this);
+ }
}
- @Override
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
mService = null;
- mHandler.sendMessage(mHandler.obtainMessage(
- MESSAGE_HEADSET_SERVICE_DISCONNECTED));
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET);
+ }
}
};
@@ -965,25 +1032,4 @@ public final class BluetoothHeadset implements BluetoothProfile {
private static void log(String msg) {
Log.d(TAG, msg);
}
-
- private final Handler mHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_HEADSET_SERVICE_CONNECTED: {
- if (mServiceListener != null) {
- mServiceListener.onServiceConnected(BluetoothProfile.HEADSET,
- BluetoothHeadset.this);
- }
- break;
- }
- case MESSAGE_HEADSET_SERVICE_DISCONNECTED: {
- if (mServiceListener != null) {
- mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET);
- }
- break;
- }
- }
- }
- };
}
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index ff4ebee..484a856 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -100,7 +100,9 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* {@link #EXTRA_BATTERY_LEVEL},
* {@link #EXTRA_OPERATOR_NAME},
* {@link #EXTRA_VOICE_RECOGNITION},
- * {@link #EXTRA_IN_BAND_RING}</p>
+ * {@link #EXTRA_IN_BAND_RING}
+ * {@link #EXTRA_MANF_ID}
+ * {@link #EXTRA_MANF_MODEL}</p>
*/
public static final String ACTION_AG_EVENT =
"android.bluetooth.headsetclient.profile.action.AG_EVENT";
@@ -206,6 +208,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
"android.bluetooth.headsetclient.extra.SUBSCRIBER_INFO";
/**
+ * Extra for AG_EVENT intent indicates manufacturer identification.
+ * <p>Value: <code>String</code> containing manufacturer identification.</p>
+ */
+ public static final String EXTRA_MANF_ID =
+ "android.bluetooth.headsetclient.extra.MANF_ID";
+
+ /**
+ * Extra for AG_EVENT intent indicates manufacturer model.
+ * <p>Value: <code>String</code> containing manufacturer model.</p>
+ */
+ public static final String EXTRA_MANF_MODEL =
+ "android.bluetooth.headsetclient.extra.MANF_MODEL";
+
+
+ /**
* Extra for AG_CALL_CHANGED intent indicates the
* {@link BluetoothHeadsetClientCall} object that has changed.
*/
@@ -1059,6 +1076,41 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
}
/**
+ * Sets whether audio routing is allowed.
+ *
+ * Note: This is an internal function and shouldn't be exposed
+ */
+ public void setAudioRouteAllowed(boolean allowed) {
+ if (VDBG) log("setAudioRouteAllowed");
+ if (mService != null && isEnabled()) {
+ try {
+ mService.setAudioRouteAllowed(allowed);
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+
+ /**
+ * Returns whether audio routing is allowed.
+ *
+ * Note: This is an internal function and shouldn't be exposed
+ */
+ public boolean getAudioRouteAllowed() {
+ if (VDBG) log("getAudioRouteAllowed");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getAudioRouteAllowed();
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
* Initiates a connection of audio channel.
*
* It setup SCO channel with remote connected Handsfree AG device.
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
index 7b5a045..002f63f 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
@@ -19,6 +19,8 @@ package android.bluetooth;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.UUID;
+
/**
* This class represents a single call, its state and properties.
* It implements {@link Parcelable} for inter-process message passing.
@@ -67,14 +69,21 @@ public final class BluetoothHeadsetClientCall implements Parcelable {
private String mNumber;
private boolean mMultiParty;
private final boolean mOutgoing;
+ private final UUID mUUID;
/**
* Creates BluetoothHeadsetClientCall instance.
*/
public BluetoothHeadsetClientCall(BluetoothDevice device, int id, int state, String number,
boolean multiParty, boolean outgoing) {
+ this(device, id, UUID.randomUUID(), state, number, multiParty, outgoing);
+ }
+
+ public BluetoothHeadsetClientCall(BluetoothDevice device, int id, UUID uuid, int state,
+ String number, boolean multiParty, boolean outgoing) {
mDevice = device;
mId = id;
+ mUUID = uuid;
mState = state;
mNumber = number != null ? number : "";
mMultiParty = multiParty;
@@ -134,6 +143,16 @@ public final class BluetoothHeadsetClientCall implements Parcelable {
}
/**
+ * Gets call's UUID.
+ *
+ * @return call uuid
+ * @hide
+ */
+ public UUID getUUID() {
+ return mUUID;
+ }
+
+ /**
* Gets call's current state.
*
* @return state of this particular phone call.
@@ -172,10 +191,16 @@ public final class BluetoothHeadsetClientCall implements Parcelable {
}
public String toString() {
+ return toString(false);
+ }
+
+ public String toString(boolean loggable) {
StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mDevice: ");
- builder.append(mDevice);
+ builder.append(loggable ? mDevice.hashCode() : mDevice);
builder.append(", mId: ");
builder.append(mId);
+ builder.append(", mUUID: ");
+ builder.append(mUUID);
builder.append(", mState: ");
switch (mState) {
case CALL_STATE_ACTIVE: builder.append("ACTIVE"); break;
@@ -189,7 +214,7 @@ public final class BluetoothHeadsetClientCall implements Parcelable {
default: builder.append(mState); break;
}
builder.append(", mNumber: ");
- builder.append(mNumber);
+ builder.append(loggable ? mNumber.hashCode() : mNumber);
builder.append(", mMultiParty: ");
builder.append(mMultiParty);
builder.append(", mOutgoing: ");
@@ -206,8 +231,8 @@ public final class BluetoothHeadsetClientCall implements Parcelable {
@Override
public BluetoothHeadsetClientCall createFromParcel(Parcel in) {
return new BluetoothHeadsetClientCall((BluetoothDevice)in.readParcelable(null),
- in.readInt(), in.readInt(), in.readString(),
- in.readInt() == 1, in.readInt() == 1);
+ in.readInt(), UUID.fromString(in.readString()), in.readInt(),
+ in.readString(), in.readInt() == 1, in.readInt() == 1);
}
@Override
@@ -220,6 +245,7 @@ public final class BluetoothHeadsetClientCall implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(mDevice, 0);
out.writeInt(mId);
+ out.writeString(mUUID.toString());
out.writeInt(mState);
out.writeString(mNumber);
out.writeInt(mMultiParty ? 1 : 0);
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
new file mode 100644
index 0000000..468df4d
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public final class BluetoothHidDevice implements BluetoothProfile {
+
+ private static final String TAG = BluetoothHidDevice.class.getSimpleName();
+
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "codeaurora.bluetooth.hid.profile.action.CONNECTION_STATE_CHANGED";
+
+ /**
+ * Constants representing device subclass.
+ *
+ * @see #registerApp(String, String, String, byte, byte[],
+ * BluetoothHidDeviceCallback)
+ */
+ public static final byte SUBCLASS1_NONE = (byte) 0x00;
+ public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40;
+ public static final byte SUBCLASS1_MOUSE = (byte) 0x80;
+ public static final byte SUBCLASS1_COMBO = (byte) 0xC0;
+
+ public static final byte SUBCLASS2_UNCATEGORIZED = (byte) 0x00;
+ public static final byte SUBCLASS2_JOYSTICK = (byte) 0x01;
+ public static final byte SUBCLASS2_GAMEPAD = (byte) 0x02;
+ public static final byte SUBCLASS2_REMOTE_CONTROL = (byte) 0x03;
+ public static final byte SUBCLASS2_SENSING_DEVICE = (byte) 0x04;
+ public static final byte SUBCLASS2_DIGITIZER_TABLED = (byte) 0x05;
+ public static final byte SUBCLASS2_CARD_READER = (byte) 0x06;
+
+ /**
+ * Constants representing report types.
+ *
+ * @see BluetoothHidDeviceCallback#onGetReport(byte, byte, int)
+ * @see BluetoothHidDeviceCallback#onSetReport(byte, byte, byte[])
+ * @see BluetoothHidDeviceCallback#onIntrData(byte, byte[])
+ */
+ public static final byte REPORT_TYPE_INPUT = (byte) 1;
+ public static final byte REPORT_TYPE_OUTPUT = (byte) 2;
+ public static final byte REPORT_TYPE_FEATURE = (byte) 3;
+
+ /**
+ * Constants representing error response for Set Report.
+ *
+ * @see BluetoothHidDeviceCallback#onSetReport(byte, byte, byte[])
+ */
+ public static final byte ERROR_RSP_SUCCESS = (byte) 0;
+ public static final byte ERROR_RSP_NOT_READY = (byte) 1;
+ public static final byte ERROR_RSP_INVALID_RPT_ID = (byte) 2;
+ public static final byte ERROR_RSP_UNSUPPORTED_REQ = (byte) 3;
+ public static final byte ERROR_RSP_INVALID_PARAM = (byte) 4;
+ public static final byte ERROR_RSP_UNKNOWN = (byte) 14;
+
+ /**
+ * Constants representing protocol mode used set by host. Default is always
+ * {@link #PROTOCOL_REPORT_MODE} unless notified otherwise.
+ *
+ * @see BluetoothHidDeviceCallback#onSetProtocol(byte)
+ */
+ public static final byte PROTOCOL_BOOT_MODE = (byte) 0;
+ public static final byte PROTOCOL_REPORT_MODE = (byte) 1;
+
+ private Context mContext;
+
+ private ServiceListener mServiceListener;
+
+ private IBluetoothHidDevice mService;
+
+ private BluetoothAdapter mAdapter;
+
+ private static class BluetoothHidDeviceCallbackWrapper extends IBluetoothHidDeviceCallback.Stub {
+
+ private BluetoothHidDeviceCallback mCallback;
+
+ public BluetoothHidDeviceCallbackWrapper(BluetoothHidDeviceCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onAppStatusChanged(BluetoothDevice pluggedDevice,
+ BluetoothHidDeviceAppConfiguration config, boolean registered) {
+ mCallback.onAppStatusChanged(pluggedDevice, config, registered);
+ }
+
+ @Override
+ public void onConnectionStateChanged(BluetoothDevice device, int state) {
+ mCallback.onConnectionStateChanged(device, state);
+ }
+
+ @Override
+ public void onGetReport(byte type, byte id, int bufferSize) {
+ mCallback.onGetReport(type, id, bufferSize);
+ }
+
+ @Override
+ public void onSetReport(byte type, byte id, byte[] data) {
+ mCallback.onSetReport(type, id, data);
+ }
+
+ @Override
+ public void onSetProtocol(byte protocol) {
+ mCallback.onSetProtocol(protocol);
+ }
+
+ @Override
+ public void onIntrData(byte reportId, byte[] data) {
+ mCallback.onIntrData(reportId, data);
+ }
+
+ @Override
+ public void onVirtualCableUnplug() {
+ mCallback.onVirtualCableUnplug();
+ }
+ }
+
+ final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+
+ public void onBluetoothStateChange(boolean up) {
+ Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ synchronized (mConnection) {
+ if (!up) {
+ Log.d(TAG,"Unbinding service...");
+ if (mService != null) {
+ mService = null;
+ try {
+ mContext.unbindService(mConnection);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG,"onBluetoothStateChange: could not unbind service:", e);
+ }
+ }
+ } else {
+ try {
+ if (mService == null) {
+ Log.d(TAG,"Binding HID Device service...");
+ doBind();
+ }
+ } catch (IllegalStateException e) {
+ Log.e(TAG,"onBluetoothStateChange: could not bind to HID Dev service: ", e);
+ } catch (SecurityException e) {
+ Log.e(TAG,"onBluetoothStateChange: could not bind to HID Dev service: ", e);
+ }
+ }
+ }
+ }
+ };
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "onServiceConnected()");
+
+ mService = IBluetoothHidDevice.Stub.asInterface(service);
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.HID_DEVICE,
+ BluetoothHidDevice.this);
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "onServiceDisconnected()");
+
+ mService = null;
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.HID_DEVICE);
+ }
+ }
+ };
+
+ BluetoothHidDevice(Context context, ServiceListener listener) {
+ Log.v(TAG, "BluetoothHidDevice");
+
+ mContext = context;
+ mServiceListener = listener;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ doBind();
+ }
+
+ boolean doBind() {
+ Intent intent = new Intent(IBluetoothHidDevice.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth HID Device Service with " + intent);
+ return false;
+ }
+ Log.d(TAG, "Bound to HID Device Service");
+ return true;
+ }
+
+ void close() {
+ Log.v(TAG, "close()");
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ mService = null;
+ try {
+ mContext.unbindService(mConnection);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG,"close: could not unbind HID Dev service: ", e);
+ }
+ }
+ }
+
+ mServiceListener = null;
+ }
+
+ @Override
+ public List<BluetoothDevice> getConnectedDevices() {
+ Log.v(TAG, "getConnectedDevices()");
+ return null;
+ }
+
+ @Override
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ Log.v(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states));
+ return null;
+ }
+
+ @Override
+ public int getConnectionState(BluetoothDevice device) {
+ Log.v(TAG, "getConnectionState(): device=" + device.getAddress());
+
+ return STATE_DISCONNECTED;
+ }
+
+ /**
+ * Registers application to be used for HID device. Connections to HID
+ * Device are only possible when application is registered. Only one
+ * application can be registered at time. When no longer used, application
+ * should be unregistered using
+ * {@link #unregisterApp(BluetoothHidDeviceAppConfiguration)}.
+ *
+ * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of
+ * HID Device SDP record.
+ * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of
+ * Incoming QoS Settings.
+ * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of
+ * Outgoing QoS Settings.
+ * @param callback {@link BluetoothHidDeviceCallback} object to which
+ * callback messages will be sent.
+ * @return
+ */
+ public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
+ BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
+ BluetoothHidDeviceCallback callback) {
+ Log.v(TAG, "registerApp(): sdp=" + sdp + " inQos=" + inQos + " outQos=" + outQos
+ + " callback=" + callback);
+
+ boolean result = false;
+
+ if (sdp == null || callback == null) {
+ return false;
+ }
+
+ if (mService != null) {
+ try {
+ BluetoothHidDeviceAppConfiguration config =
+ new BluetoothHidDeviceAppConfiguration();
+ BluetoothHidDeviceCallbackWrapper cbw =
+ new BluetoothHidDeviceCallbackWrapper(callback);
+ result = mService.registerApp(config, sdp, inQos, outQos, cbw);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Unregisters application. Active connection will be disconnected and no
+ * new connections will be allowed until registered again using
+ * {@link #registerApp(String, String, String, byte, byte[], BluetoothHidDeviceCallback)}
+ *
+ * @param config {@link BluetoothHidDeviceAppConfiguration} object as
+ * obtained from
+ * {@link BluetoothHidDeviceCallback#onAppStatusChanged(BluetoothDevice,
+ * BluetoothHidDeviceAppConfiguration, boolean)}
+ *
+ * @return
+ */
+ public boolean unregisterApp(BluetoothHidDeviceAppConfiguration config) {
+ Log.v(TAG, "unregisterApp()");
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.unregisterApp(config);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Sends report to remote host using interrupt channel.
+ *
+ * @param id Report Id, as defined in descriptor. Can be 0 in case Report Id
+ * are not defined in descriptor.
+ * @param data Report data, not including Report Id.
+ * @return
+ */
+ public boolean sendReport(int id, byte[] data) {
+ Log.v(TAG, "sendReport(): id=" + id);
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.sendReport(id, data);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Sends report to remote host as reply for GET_REPORT request from
+ * {@link BluetoothHidDeviceCallback#onGetReport(byte, byte, int)}.
+ *
+ * @param type Report Type, as in request.
+ * @param id Report Id, as in request.
+ * @param data Report data, not including Report Id.
+ * @return
+ */
+ public boolean replyReport(byte type, byte id, byte[] data) {
+ Log.v(TAG, "replyReport(): type=" + type + " id=" + id);
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.replyReport(type, id, data);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Sends error handshake message as reply for invalid SET_REPORT request
+ * from {@link BluetoothHidDeviceCallback#onSetReport(byte, byte, byte[])}.
+ *
+ * @param error Error to be sent for SET_REPORT via HANDSHAKE.
+ * @return
+ */
+ public boolean reportError(byte error) {
+ Log.v(TAG, "reportError(): error = " + error);
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.reportError(error);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Sends Virtual Cable Unplug to currently connected host.
+ *
+ * @return
+ */
+ public boolean unplug() {
+ Log.v(TAG, "unplug()");
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.unplug();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Initiates connection to host which currently has Virtual Cable
+ * established with device.
+ *
+ * @return
+ */
+ public boolean connect() {
+ Log.v(TAG, "connect()");
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.connect();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+
+ /**
+ * Disconnects from currently connected host.
+ *
+ * @return
+ */
+ public boolean disconnect() {
+ Log.v(TAG, "disconnect()");
+
+ boolean result = false;
+
+ if (mService != null) {
+ try {
+ result = mService.disconnect();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return result;
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl
new file mode 100644
index 0000000..1af309c
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl
@@ -0,0 +1,21 @@
+/*
+** Copyright (C) 2013 The Linux Foundation. All rights reserved
+** Not a Contribution.
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.bluetooth;
+
+parcelable BluetoothHidDeviceAppConfiguration;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java
new file mode 100644
index 0000000..9f3cd3c
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Random;
+
+/** @hide */
+public final class BluetoothHidDeviceAppConfiguration implements Parcelable {
+ private final long mHash;
+
+ BluetoothHidDeviceAppConfiguration() {
+ Random rnd = new Random();
+ mHash = rnd.nextLong();
+ }
+
+ BluetoothHidDeviceAppConfiguration(long hash) {
+ mHash = hash;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothHidDeviceAppConfiguration) {
+ BluetoothHidDeviceAppConfiguration config = (BluetoothHidDeviceAppConfiguration) o;
+ return mHash == config.mHash;
+ }
+ return false;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<BluetoothHidDeviceAppConfiguration> CREATOR =
+ new Parcelable.Creator<BluetoothHidDeviceAppConfiguration>() {
+
+ @Override
+ public BluetoothHidDeviceAppConfiguration createFromParcel(Parcel in) {
+ long hash = in.readLong();
+ return new BluetoothHidDeviceAppConfiguration(hash);
+ }
+
+ @Override
+ public BluetoothHidDeviceAppConfiguration[] newArray(int size) {
+ return new BluetoothHidDeviceAppConfiguration[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(mHash);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl
new file mode 100644
index 0000000..ae93235
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl
@@ -0,0 +1,21 @@
+/*
+** Copyright (C) 2013 The Linux Foundation. All rights reserved
+** Not a Contribution.
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.bluetooth;
+
+parcelable BluetoothHidDeviceAppQosSettings;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
new file mode 100644
index 0000000..a4044d9
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Random;
+
+/** @hide */
+public final class BluetoothHidDeviceAppQosSettings implements Parcelable {
+
+ final public int serviceType;
+ final public int tokenRate;
+ final public int tokenBucketSize;
+ final public int peakBandwidth;
+ final public int latency;
+ final public int delayVariation;
+
+ final static public int SERVICE_NO_TRAFFIC = 0x00;
+ final static public int SERVICE_BEST_EFFORT = 0x01;
+ final static public int SERVICE_GUARANTEED = 0x02;
+
+ final static public int MAX = (int) 0xffffffff;
+
+ public BluetoothHidDeviceAppQosSettings(int serviceType, int tokenRate, int tokenBucketSize,
+ int peakBandwidth,
+ int latency, int delayVariation) {
+ this.serviceType = serviceType;
+ this.tokenRate = tokenRate;
+ this.tokenBucketSize = tokenBucketSize;
+ this.peakBandwidth = peakBandwidth;
+ this.latency = latency;
+ this.delayVariation = delayVariation;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothHidDeviceAppQosSettings) {
+ BluetoothHidDeviceAppQosSettings qos = (BluetoothHidDeviceAppQosSettings) o;
+ return false;
+ }
+ return false;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<BluetoothHidDeviceAppQosSettings> CREATOR =
+ new Parcelable.Creator<BluetoothHidDeviceAppQosSettings>() {
+
+ @Override
+ public BluetoothHidDeviceAppQosSettings createFromParcel(Parcel in) {
+
+ return new BluetoothHidDeviceAppQosSettings(in.readInt(), in.readInt(), in.readInt(),
+ in.readInt(),
+ in.readInt(), in.readInt());
+ }
+
+ @Override
+ public BluetoothHidDeviceAppQosSettings[] newArray(int size) {
+ return new BluetoothHidDeviceAppQosSettings[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(serviceType);
+ out.writeInt(tokenRate);
+ out.writeInt(tokenBucketSize);
+ out.writeInt(peakBandwidth);
+ out.writeInt(latency);
+ out.writeInt(delayVariation);
+ }
+
+ public int[] toArray() {
+ return new int[] {
+ serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
+ };
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl
new file mode 100644
index 0000000..38ac1ec
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl
@@ -0,0 +1,21 @@
+/*
+** Copyright (C) 2013 The Linux Foundation. All rights reserved
+** Not a Contribution.
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.bluetooth;
+
+parcelable BluetoothHidDeviceAppSdpSettings;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
new file mode 100644
index 0000000..db88f0d
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Random;
+
+/** @hide */
+public final class BluetoothHidDeviceAppSdpSettings implements Parcelable {
+
+ final public String name;
+ final public String description;
+ final public String provider;
+ final public byte subclass;
+ final public byte[] descriptors;
+
+ public BluetoothHidDeviceAppSdpSettings(String name, String description, String provider,
+ byte subclass, byte[] descriptors) {
+ this.name = name;
+ this.description = description;
+ this.provider = provider;
+ this.subclass = subclass;
+ this.descriptors = descriptors.clone();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothHidDeviceAppSdpSettings) {
+ BluetoothHidDeviceAppSdpSettings sdp = (BluetoothHidDeviceAppSdpSettings) o;
+ return false;
+ }
+ return false;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<BluetoothHidDeviceAppSdpSettings> CREATOR =
+ new Parcelable.Creator<BluetoothHidDeviceAppSdpSettings>() {
+
+ @Override
+ public BluetoothHidDeviceAppSdpSettings createFromParcel(Parcel in) {
+
+ return new BluetoothHidDeviceAppSdpSettings(in.readString(), in.readString(),
+ in.readString(), in.readByte(), in.createByteArray());
+ }
+
+ @Override
+ public BluetoothHidDeviceAppSdpSettings[] newArray(int size) {
+ return new BluetoothHidDeviceAppSdpSettings[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(name);
+ out.writeString(description);
+ out.writeString(provider);
+ out.writeByte(subclass);
+ out.writeByteArray(descriptors);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
new file mode 100644
index 0000000..cc60833
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.util.Log;
+
+/** @hide */
+public abstract class BluetoothHidDeviceCallback {
+
+ private static final String TAG = BluetoothHidDeviceCallback.class.getSimpleName();
+
+ /**
+ * Callback called when application registration state changes. Usually it's
+ * called due to either
+ * {@link BluetoothHidDevice#registerApp(String, String, String, byte, byte[],
+ * BluetoothHidDeviceCallback)}
+ * or
+ * {@link BluetoothHidDevice#unregisterApp(BluetoothHidDeviceAppConfiguration)}
+ * , but can be also unsolicited in case e.g. Bluetooth was turned off in
+ * which case application is unregistered automatically.
+ *
+ * @param pluggedDevice {@link BluetoothDevice} object which represents host
+ * that currently has Virtual Cable established with device. Only
+ * valid when application is registered, can be <code>null</code>
+ * .
+ * @param config {@link BluetoothHidDeviceAppConfiguration} object which
+ * represents token required to unregister application using
+ * {@link BluetoothHidDevice#unregisterApp(BluetoothHidDeviceAppConfiguration)}
+ * .
+ * @param registered <code>true</code> if application is registered,
+ * <code>false</code> otherwise.
+ */
+ public void onAppStatusChanged(BluetoothDevice pluggedDevice,
+ BluetoothHidDeviceAppConfiguration config, boolean registered) {
+ Log.d(TAG, "onAppStatusChanged: pluggedDevice=" + (pluggedDevice == null ?
+ null : pluggedDevice.toString()) + " registered=" + registered);
+ }
+
+ /**
+ * Callback called when connection state with remote host was changed.
+ * Application can assume than Virtual Cable is established when called with
+ * {@link BluetoothProfile#STATE_CONNECTED} <code>state</code>.
+ *
+ * @param device {@link BluetoothDevice} object representing host device
+ * which connection state was changed.
+ * @param state Connection state as defined in {@link BluetoothProfile}.
+ */
+ public void onConnectionStateChanged(BluetoothDevice device, int state) {
+ Log.d(TAG, "onConnectionStateChanged: device=" + device.toString() + " state=" + state);
+ }
+
+ /**
+ * Callback called when GET_REPORT is received from remote host. Should be
+ * replied by application using
+ * {@link BluetoothHidDevice#replyReport(byte, byte, byte[])}.
+ *
+ * @param type Requested Report Type.
+ * @param id Requested Report Id, can be 0 if no Report Id are defined in
+ * descriptor.
+ * @param bufferSize Requested buffer size, application shall respond with
+ * at least given number of bytes.
+ */
+ public void onGetReport(byte type, byte id, int bufferSize) {
+ Log.d(TAG, "onGetReport: type=" + type + " id=" + id + " bufferSize=" + bufferSize);
+ }
+
+ /**
+ * Callback called when SET_REPORT is received from remote host. In case
+ * received data are invalid, application shall respond with
+ * {@link BluetoothHidDevice#reportError()}.
+ *
+ * @param type Report Type.
+ * @param id Report Id.
+ * @param data Report data.
+ */
+ public void onSetReport(byte type, byte id, byte[] data) {
+ Log.d(TAG, "onSetReport: type=" + type + " id=" + id);
+ }
+
+ /**
+ * Callback called when SET_PROTOCOL is received from remote host.
+ * Application shall use this information to send only reports valid for
+ * given protocol mode. By default,
+ * {@link BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed.
+ *
+ * @param protocol Protocol Mode.
+ */
+ public void onSetProtocol(byte protocol) {
+ Log.d(TAG, "onSetProtocol: protocol=" + protocol);
+ }
+
+ /**
+ * Callback called when report data is received over interrupt channel.
+ * Report Type is assumed to be
+ * {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}.
+ *
+ * @param reportId Report Id.
+ * @param data Report data.
+ */
+ public void onIntrData(byte reportId, byte[] data) {
+ Log.d(TAG, "onIntrData: reportId=" + reportId);
+ }
+
+ /**
+ * Callback called when Virtual Cable is removed. This can be either due to
+ * {@link BluetoothHidDevice#unplug()} or request from remote side. After
+ * this callback is received connection will be disconnected automatically.
+ */
+ public void onVirtualCableUnplug() {
+ Log.d(TAG, "onVirtualCableUnplug");
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index 252e3d2..db23ef5 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -96,6 +96,12 @@ public final class BluetoothInputDevice implements BluetoothProfile {
public static final String ACTION_VIRTUAL_UNPLUG_STATUS =
"android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS";
+ /**
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_IDLE_TIME_CHANGED =
+ "codeaurora.bluetooth.input.profile.action.IDLE_TIME_CHANGED";
/**
* Return codes for the connect and disconnect Bluez / Dbus calls.
@@ -199,6 +205,11 @@ public final class BluetoothInputDevice implements BluetoothProfile {
*/
public static final String EXTRA_VIRTUAL_UNPLUG_STATUS = "android.bluetooth.BluetoothInputDevice.extra.VIRTUAL_UNPLUG_STATUS";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_IDLE_TIME = "codeaurora.bluetooth.BluetoothInputDevice.extra.IDLE_TIME";
+
private Context mContext;
private ServiceListener mServiceListener;
private BluetoothAdapter mAdapter;
@@ -658,6 +669,56 @@ public final class BluetoothInputDevice implements BluetoothProfile {
if (mService == null) Log.w(TAG, "Proxy not attached to service");
return false;
}
+
+ /**
+ * Send Get_Idle_Time command to the connected HID input device.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error,
+ * true otherwise
+ * @hide
+ */
+ public boolean getIdleTime(BluetoothDevice device) {
+ if (DBG) log("getIdletime(" + device + ")");
+ if (mService != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return mService.getIdleTime(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Send Set_Idle_Time command to the connected HID input device.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @param idleTime Idle time to be set on HID Device
+ * @return false on immediate error,
+ * true otherwise
+ * @hide
+ */
+ public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
+ if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime);
+ if (mService != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return mService.setIdleTime(device, idleTime);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
private static void log(String msg) {
Log.d(TAG, msg);
}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index cbce22c..9ef931e 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -131,6 +131,18 @@ public interface BluetoothProfile {
public static final int HEADSET_CLIENT = 16;
/**
+ * HID device
+ * @hide
+ */
+ public static final int HID_DEVICE = 17;
+
+ /**
+ * DUN
+ * @hide
+ */
+ public static final int DUN = 21;
+
+ /**
* Default priority for devices that we try to auto-connect to and
* and allow incoming connections for the profile
* @hide
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index fb81fd1..2eb4953 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -247,6 +247,7 @@ public final class BluetoothSocket implements Closeable {
as.mSocketOS = as.mSocket.getOutputStream();
as.mAddress = RemoteAddr;
as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(RemoteAddr);
+ as.mPort = mPort;
return as;
}
/**
@@ -468,6 +469,61 @@ public final class BluetoothSocket implements Closeable {
return acceptedSocket;
}
+ /**
+ * setSocketOpt for the Buetooth Socket.
+ *
+ * @param optionName socket option name
+ * @param optionVal socket option value
+ * @param optionLen socket option length
+ * @return -1 on immediate error,
+ * 0 otherwise
+ * @hide
+ */
+ public int setSocketOpt(int optionName, byte [] optionVal, int optionLen) throws IOException {
+ int ret = 0;
+ if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
+ IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+ if (bluetoothProxy == null) {
+ Log.e(TAG, "setSocketOpt fail, reason: bluetooth is off");
+ return -1;
+ }
+ try {
+ if(VDBG) Log.d(TAG, "setSocketOpt(), mType: " + mType + " mPort: " + mPort);
+ ret = bluetoothProxy.setSocketOpt(mType, mPort, optionName, optionVal, optionLen);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return -1;
+ }
+ return ret;
+ }
+
+ /**
+ * getSocketOpt for the Buetooth Socket.
+ *
+ * @param optionName socket option name
+ * @param optionVal socket option value
+ * @return -1 on immediate error,
+ * length of returned socket option otherwise
+ * @hide
+ */
+ public int getSocketOpt(int optionName, byte [] optionVal) throws IOException {
+ int ret = 0;
+ if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
+ IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+ if (bluetoothProxy == null) {
+ Log.e(TAG, "getSocketOpt fail, reason: bluetooth is off");
+ return -1;
+ }
+ try {
+ if(VDBG) Log.d(TAG, "getSocketOpt(), mType: " + mType + " mPort: " + mPort);
+ ret = bluetoothProxy.getSocketOpt(mType, mPort, optionName, optionVal);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return -1;
+ }
+ return ret;
+ }
+
/*package*/ int available() throws IOException {
if (VDBG) Log.d(TAG, "available: " + mSocketIS);
return mSocketIS.available();
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 66f3418..2f1e8b4 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -70,6 +70,11 @@ interface IBluetooth
boolean fetchRemoteUuids(in BluetoothDevice device);
boolean sdpSearch(in BluetoothDevice device, in ParcelUuid uuid);
+ int createMapMnsSdpRecord(in String serviceName, in int rfcommChannel,
+ in int l2capPsm, in int version, in int features);
+ int createPbapPceSdpRecord(in String serviceName, in int version);
+ boolean removeSdpRecord(in int recordHandle);
+
boolean setPin(in BluetoothDevice device, boolean accept, int len, in byte[] pinCode);
boolean setPasskey(in BluetoothDevice device, boolean accept, int len, in byte[]
passkey);
@@ -106,4 +111,7 @@ interface IBluetooth
void dump(in ParcelFileDescriptor fd);
void onLeServiceUp();
void onBrEdrDown();
+
+ int setSocketOpt(int type, int port, int optionName, in byte [] optionVal, int optionLen);
+ int getSocketOpt(int type, int port, int optionName, out byte [] optionVal);
}
diff --git a/core/java/android/bluetooth/IBluetoothA2dpSink.aidl b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
index b7c6476..774a1ec 100644..100755
--- a/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
@@ -30,5 +30,8 @@ interface IBluetoothA2dpSink {
List<BluetoothDevice> getConnectedDevices();
List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
int getConnectionState(in BluetoothDevice device);
+ boolean setPriority(in BluetoothDevice device, int priority);
+ int getPriority(in BluetoothDevice device);
+ boolean isA2dpPlaying(in BluetoothDevice device);
BluetoothAudioConfig getAudioConfig(in BluetoothDevice device);
}
diff --git a/core/java/android/bluetooth/IBluetoothAvrcpController.aidl b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
index f917a50..fb61c98 100644
--- a/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
+++ b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,6 +18,7 @@
package android.bluetooth;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothAvrcpInfo;
/**
* APIs for Bluetooth AVRCP controller service
@@ -28,4 +30,10 @@ interface IBluetoothAvrcpController {
List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
int getConnectionState(in BluetoothDevice device);
void sendPassThroughCmd(in BluetoothDevice device, int keyCode, int keyState);
+ void getMetaData(in int[] attributeIds);
+ void getPlayStatus(in int[] playStatusIds);
+ void getPlayerApplicationSetting();
+ void setPlayerApplicationSetting(in int attributeId, in int attribVal);
+ BluetoothAvrcpInfo getSupportedPlayerAppSetting(in BluetoothDevice device);
+ int getSupportedFeatures(in BluetoothDevice device);
}
diff --git a/core/java/android/bluetooth/IBluetoothDun.aidl b/core/java/android/bluetooth/IBluetoothDun.aidl
new file mode 100644
index 0000000..a4f2017
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothDun.aidl
@@ -0,0 +1,45 @@
+/*
+*Copyright (c) 2013, The Linux Foundation. All rights reserved.
+*
+*Redistribution and use in source and binary forms, with or without
+*modification, are permitted provided that the following conditions are
+*met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+*THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+*WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+*ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+*BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+*CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+*SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+*WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+*OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+*IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * API for Bluetooth Dun service
+ *
+ * {@hide}
+ */
+interface IBluetoothDun {
+ // Public API
+ boolean disconnect(in BluetoothDevice device);
+ int getConnectionState(in BluetoothDevice device);
+ List<BluetoothDevice> getConnectedDevices();
+ List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+}
diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl
index 0e23fad..0bb4088 100755
--- a/core/java/android/bluetooth/IBluetoothHeadset.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl
@@ -50,6 +50,8 @@ interface IBluetoothHeadset {
boolean isAudioOn();
boolean connectAudio();
boolean disconnectAudio();
+ void setAudioRouteAllowed(boolean allowed);
+ boolean getAudioRouteAllowed();
boolean startScoUsingVirtualVoiceCall(in BluetoothDevice device);
boolean stopScoUsingVirtualVoiceCall(in BluetoothDevice device);
void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type);
diff --git a/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
index e518b7d..79ae4e4 100644
--- a/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
@@ -62,6 +62,8 @@ interface IBluetoothHeadsetClient {
int getAudioState(in BluetoothDevice device);
boolean connectAudio();
boolean disconnectAudio();
+ void setAudioRouteAllowed(boolean allowed);
+ boolean getAudioRouteAllowed();
Bundle getCurrentAgFeatures(in BluetoothDevice device);
}
diff --git a/core/java/android/bluetooth/IBluetoothHidDevice.aidl b/core/java/android/bluetooth/IBluetoothHidDevice.aidl
new file mode 100644
index 0000000..60358c5
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothHidDevice.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHidDeviceAppConfiguration;
+import android.bluetooth.IBluetoothHidDeviceCallback;
+import android.bluetooth.BluetoothHidDeviceAppSdpSettings;
+import android.bluetooth.BluetoothHidDeviceAppQosSettings;
+
+/** @hide */
+interface IBluetoothHidDevice {
+ boolean registerApp(in BluetoothHidDeviceAppConfiguration config,
+ in BluetoothHidDeviceAppSdpSettings sdp, in BluetoothHidDeviceAppQosSettings inQos,
+ in BluetoothHidDeviceAppQosSettings outQos, in IBluetoothHidDeviceCallback callback);
+ boolean unregisterApp(in BluetoothHidDeviceAppConfiguration config);
+ boolean sendReport(in int id, in byte[] data);
+ boolean replyReport(in byte type, in byte id, in byte[] data);
+ boolean reportError(byte error);
+ boolean unplug();
+ boolean connect();
+ boolean disconnect();
+}
diff --git a/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl b/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl
new file mode 100644
index 0000000..7c71a17
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * Copyright (C) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHidDeviceAppConfiguration;
+
+/** @hide */
+interface IBluetoothHidDeviceCallback {
+ void onAppStatusChanged(in BluetoothDevice device, in BluetoothHidDeviceAppConfiguration config, boolean registered);
+ void onConnectionStateChanged(in BluetoothDevice device, in int state);
+ void onGetReport(in byte type, in byte id, in int bufferSize);
+ void onSetReport(in byte type, in byte id, in byte[] data);
+ void onSetProtocol(in byte protocol);
+ void onIntrData(in byte reportId, in byte[] data);
+ void onVirtualCableUnplug();
+}
diff --git a/core/java/android/bluetooth/IBluetoothInputDevice.aidl b/core/java/android/bluetooth/IBluetoothInputDevice.aidl
index 1ebb9ca..5bd3f78 100644
--- a/core/java/android/bluetooth/IBluetoothInputDevice.aidl
+++ b/core/java/android/bluetooth/IBluetoothInputDevice.aidl
@@ -56,4 +56,12 @@ interface IBluetoothInputDevice {
* @hide
*/
boolean sendData(in BluetoothDevice device, String report);
+ /**
+ * @hide
+ */
+ boolean getIdleTime(in BluetoothDevice device);
+ /**
+ * @hide
+ */
+ boolean setIdleTime(in BluetoothDevice device, byte idleTime);
}
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
index 0b81ee8..bd8c6c9 100644
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -19,7 +19,6 @@ package android.bluetooth;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManagerCallback;
-import android.bluetooth.IBluetoothProfileServiceConnection;
import android.bluetooth.IBluetoothStateChangeCallback;
/**
@@ -34,14 +33,11 @@ interface IBluetoothManager
void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
boolean isEnabled();
- boolean enable();
+ boolean enable(String callingPackage);
boolean enableNoAutoConnect();
boolean disable(boolean persist);
IBluetoothGatt getBluetoothGatt();
- boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
- void unbindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
-
String getAddress();
String getName();
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 2260d7e..bf0c48d 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -16,6 +16,7 @@
package android.content;
+import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.IActivityManager;
@@ -747,6 +748,17 @@ public abstract class BroadcastReceiver {
return mPendingResult.mSendingUser;
}
+ /** @hide */
+ public String getSendingPackage(Intent intent) {
+ final IActivityManager mgr = ActivityManagerNative.getDefault();
+ try {
+ boolean fg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
+ return mgr.getCallingPackageForBroadcast(fg);
+ } catch (RemoteException ex) {
+ return null;
+ }
+ }
+
/**
* Control inclusion of debugging help for mismatched
* calls to {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 6ede29b..863ca65 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -431,6 +431,7 @@ public abstract class ContentResolver {
public final @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
@Nullable String selection, @Nullable String[] selectionArgs,
@Nullable String sortOrder) {
+ android.util.SeempLog.record_uri(13, uri);
return query(uri, projection, selection, selectionArgs, sortOrder, null);
}
@@ -471,6 +472,7 @@ public abstract class ContentResolver {
public final @Nullable Cursor query(final @NonNull Uri uri, @Nullable String[] projection,
@Nullable String selection, @Nullable String[] selectionArgs,
@Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) {
+ android.util.SeempLog.record_uri(13, uri);
Preconditions.checkNotNull(uri, "uri");
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
@@ -984,6 +986,7 @@ public abstract class ContentResolver {
stableProvider = acquireProvider(uri);
}
releaseUnstableProvider(unstableProvider);
+ unstableProvider = null;
ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
fd.getParcelFileDescriptor(), stableProvider);
@@ -1128,6 +1131,7 @@ public abstract class ContentResolver {
stableProvider = acquireProvider(uri);
}
releaseUnstableProvider(unstableProvider);
+ unstableProvider = null;
ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
fd.getParcelFileDescriptor(), stableProvider);
@@ -1221,6 +1225,7 @@ public abstract class ContentResolver {
* @return the URL of the newly created row.
*/
public final @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues values) {
+ android.util.SeempLog.record_uri(37, url);
Preconditions.checkNotNull(url, "url");
IContentProvider provider = acquireProvider(url);
if (provider == null) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 758b6ff..7ddda11 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -497,6 +497,9 @@ public abstract class Context {
@ViewDebug.ExportedProperty(deepExport = true)
public abstract Resources.Theme getTheme();
+ /** @hide */
+ public abstract void recreateTheme();
+
/**
* Retrieve styled attribute information in this Context's theme. See
* {@link android.content.res.Resources.Theme#obtainStyledAttributes(int[])}
@@ -3858,6 +3861,26 @@ public abstract class Context {
int flags) throws PackageManager.NameNotFoundException;
/**
+ * Similar to {@link #createPackageContext(String, int)}, but with a
+ * different {@link UserHandle}. For example, {@link #getContentResolver()}
+ * will open any {@link Uri} as the given user. A theme package can be
+ * specified which will be used when adding resources to this context
+ *
+ * @hide
+ */
+ public abstract Context createPackageContextAsUser(
+ String packageName, String themePackageName, int flags, UserHandle user)
+ throws PackageManager.NameNotFoundException;
+
+ /**
+ * Creates a context given an {@link android.content.pm.ApplicationInfo}.
+ *
+ * @hide
+ */
+ public abstract Context createApplicationContext(ApplicationInfo application,
+ String themePackageName, int flags) throws PackageManager.NameNotFoundException;
+
+ /**
* Get the userId associated with this context
* @return user id
*
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 8359edf..795b9ae 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -123,6 +123,12 @@ public class ContextWrapper extends Context {
return mBase.getTheme();
}
+ /** @hide */
+ @Override
+ public void recreateTheme() {
+ mBase.recreateTheme();
+ }
+
@Override
public ClassLoader getClassLoader() {
return mBase.getClassLoader();
@@ -757,7 +763,20 @@ public class ContextWrapper extends Context {
@Override
public Context createApplicationContext(ApplicationInfo application,
int flags) throws PackageManager.NameNotFoundException {
- return mBase.createApplicationContext(application, flags);
+ return createApplicationContext(application, null, flags);
+ }
+
+ /** @hide */
+ public Context createApplicationContext(ApplicationInfo application,
+ String themePackageName, int flags) throws PackageManager.NameNotFoundException {
+ return mBase.createApplicationContext(application, themePackageName, flags);
+ }
+
+ /** @hide */
+ @Override
+ public Context createPackageContextAsUser(String packageName, String themePackageName,
+ int flags, UserHandle user) throws PackageManager.NameNotFoundException {
+ return mBase.createPackageContextAsUser(packageName, themePackageName, flags, user);
}
/** @hide */
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 87d52e4..c06f98a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1604,6 +1605,23 @@ public class Intent implements Parcelable, Cloneable {
= "android.intent.action.GET_PERMISSIONS_COUNT";
/**
+ * Broadcast action that requests list of all apps that have runtime permissions. It will
+ * respond to the request by sending a broadcast with action defined by
+ * {@link #EXTRA_GET_PERMISSIONS_PACKAGES_RESPONSE_INTENT}. The response will contain
+ * {@link #EXTRA_GET_PERMISSIONS_APP_LIST_RESULT}, as well as
+ * {@link #EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT}, with contents described below or
+ * a null upon failure.
+ *
+ * <p>{@link #EXTRA_GET_PERMISSIONS_APP_LIST_RESULT} will contain a list of package names of
+ * apps that have runtime permissions. {@link #EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT}
+ * will contain the list of app labels corresponding ot the apps in the first list.
+ *
+ * @hide
+ */
+ public static final String ACTION_GET_PERMISSIONS_PACKAGES
+ = "android.intent.action.GET_PERMISSIONS_PACKAGES";
+
+ /**
* Extra included in response to {@link #ACTION_GET_PERMISSIONS_COUNT}.
* @hide
*/
@@ -1618,6 +1636,28 @@ public class Intent implements Parcelable, Cloneable {
= "android.intent.extra.GET_PERMISSIONS_GROUP_LIST_RESULT";
/**
+ * String list of apps that have one or more runtime permissions.
+ * @hide
+ */
+ public static final String EXTRA_GET_PERMISSIONS_APP_LIST_RESULT
+ = "android.intent.extra.GET_PERMISSIONS_APP_LIST_RESULT";
+
+ /**
+ * String list of app labels for apps that have one or more runtime permissions.
+ * @hide
+ */
+ public static final String EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT
+ = "android.intent.extra.GET_PERMISSIONS_APP_LABEL_LIST_RESULT";
+
+ /**
+ * Boolean list describing if the app is a system app for apps that have one or more runtime
+ * permissions.
+ * @hide
+ */
+ public static final String EXTRA_GET_PERMISSIONS_IS_SYSTEM_APP_LIST_RESULT
+ = "android.intent.extra.GET_PERMISSIONS_IS_SYSTEM_APP_LIST_RESULT";
+
+ /**
* Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_COUNT} broadcasts.
* @hide
*/
@@ -1625,6 +1665,13 @@ public class Intent implements Parcelable, Cloneable {
= "android.intent.extra.GET_PERMISSIONS_RESONSE_INTENT";
/**
+ * Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_PACKAGES} broadcasts.
+ * @hide
+ */
+ public static final String EXTRA_GET_PERMISSIONS_PACKAGES_RESPONSE_INTENT
+ = "android.intent.extra.GET_PERMISSIONS_PACKAGES_RESONSE_INTENT";
+
+ /**
* Activity action: Launch UI to manage which apps have a given permission.
* <p>
* Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission access
@@ -1800,6 +1847,15 @@ public class Intent implements Parcelable, Cloneable {
*/
public static final String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
/**
+ * Broadcast Action: Update preferences for the power menu dialog. This is to provide a
+ * way for the preferences that need to be enabled/disabled to update because they were
+ * toggled elsewhere in the settings (ie profiles, immersive desktop, etc) so we don't have
+ * to do constant lookups while we wait for the menu to be created. Getting the values once
+ * when necessary is enough.
+ *@hide
+ */
+ public static final String UPDATE_POWER_MENU = "android.intent.action.UPDATE_POWER_MENU";
+ /**
* Broadcast Action: Trigger the download and eventual installation
* of a package.
* <p>Input: {@link #getData} is the URI of the package file to download.
@@ -2075,6 +2131,15 @@ public class Intent implements Parcelable, Cloneable {
*/
@Deprecated @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED";
+
+ /**
+ * Broadcast Action: The current keyguard wallpaper configuration
+ * has changed and should be re-read.
+ * {@hide}
+ */
+ public static final String ACTION_KEYGUARD_WALLPAPER_CHANGED =
+ "android.intent.action.KEYGUARD_WALLPAPER_CHANGED";
+
/**
* Broadcast Action: The current device {@link android.content.res.Configuration}
* (orientation, locale, etc) has changed. When such a change happens, the
@@ -2659,6 +2724,45 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.GET_RESTRICTION_ENTRIES";
/**
+ * <p>Broadcast Action: The state of the HOTWORD audio input has changed.:</p>
+ * <ul>
+ * <li><em>state</em> - A String value indicating the state of the input.
+ * {@link #EXTRA_HOTWORD_INPUT_STATE}. The value will be one of:
+ * {@link android.media.AudioRecord#RECORDSTATE_RECORDING} or
+ * {@link android.media.AudioRecord#RECORDSTATE_STOPPED}.
+ * </li>
+ * <li><em>package</em> - A String value indicating the package name of the application
+ * that currently holds the HOTWORD input.
+ * {@link #EXTRA_CURRENT_PACKAGE_NAME}
+ * </li>
+ * </ul>
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system. It can only be received by packages that hold
+ * {@link android.Manifest.permission#CAPTURE_AUDIO_HOTWORD}.
+ *
+ * @hide
+ */
+ //@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_HOTWORD_INPUT_CHANGED
+ = "com.cyanogenmod.intent.action.HOTWORD_INPUT_CHANGED";
+
+ /**
+ * @hide
+ * Activity to challenge the user for a PIN that was configured when setting up
+ * restrictions. Restrictions include blocking of apps and preventing certain user operations,
+ * controlled by {@link android.os.UserManager#setUserRestrictions(Bundle).
+ * Launch the activity using
+ * {@link android.app.Activity#startActivityForResult(Intent, int)} and check if the
+ * result is {@link android.app.Activity#RESULT_OK} for a successful response to the
+ * challenge.<p/>
+ * Before launching this activity, make sure that there is a PIN in effect, by calling
+ * {@link android.os.UserManager#hasRestrictionsChallenge()}.
+ */
+ public static final String ACTION_RESTRICTIONS_CHALLENGE =
+ "android.intent.action.RESTRICTIONS_CHALLENGE";
+
+ /**
* Sent the first time a user is starting, to allow system apps to
* perform one time initialization. (This will not be seen by third
* party applications because a newly initialized user does not have any
@@ -2830,6 +2934,13 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.SHOW_BRIGHTNESS_DIALOG";
/**
+ * Activity Action: Shows the notification brightness setting dialog.
+ * @hide
+ */
+ public static final String ACTION_SHOW_NOTIFICATION_BRIGHTNESS_DIALOG =
+ "android.intent.action.SHOW_NOTIFICATION_BRIGHTNESS_DIALOG";
+
+ /**
* Broadcast Action: A global button was pressed. Includes a single
* extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that
* caused the broadcast.
@@ -2918,6 +3029,19 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
/**
+ * Broadcast Action: A theme's resources were cached. Includes two extra fields,
+ * {@link #EXTRA_THEME_PACKAGE_NAME}, containing the package name of the theme that was
+ * processed, and {@link #EXTRA_THEME_RESULT}, containing the result code.
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.</p>
+ *
+ * @hide
+ */
+ public static final String ACTION_THEME_RESOURCES_CACHED =
+ "android.intent.action.THEME_RESOURCES_CACHED";
+
+ /**
* Activity Action: Allow the user to pick a directory subtree. When
* invoked, the system will display the various {@link DocumentsProvider}
* instances installed on the device, letting the user navigate through
@@ -2984,6 +3108,43 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_PROCESS_TEXT_READONLY =
"android.intent.extra.PROCESS_TEXT_READONLY";
+ /** {@hide} */
+ public static final String ACTION_DOZE_PULSE_STARTING =
+ "android.intent.action.DOZE_PULSE_STARTING";
+
+ /**
+ * Broadcast action: reports when a new thermal event has been reached. When the device
+ * is reaching its maximum temperatue, the thermal level reported
+ * {@hide}
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_THERMAL_EVENT = "android.intent.action.THERMAL_EVENT";
+
+ /** {@hide} */
+ public static final String EXTRA_THERMAL_STATE = "android.intent.extra.THERMAL_STATE";
+
+ /**
+ * Thermal state when the device is normal. This state is sent in the
+ * {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}.
+ * {@hide}
+ */
+ public static final int EXTRA_THERMAL_STATE_NORMAL = 0;
+
+ /**
+ * Thermal state where the device is approaching its maximum threshold. This state is sent in
+ * the {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}.
+ * {@hide}
+ */
+ public static final int EXTRA_THERMAL_STATE_WARNING = 1;
+
+ /**
+ * Thermal state where the device has reached its maximum threshold. This state is sent in the
+ * {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}.
+ * {@hide}
+ */
+ public static final int EXTRA_THERMAL_STATE_EXCEEDED = 2;
+
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
@@ -3086,6 +3247,13 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_HOME = "android.intent.category.HOME";
/**
+ * This is the home activity that is displayed when the device is finished setting up and ready
+ * for use.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_HOME_MAIN = "android.intent.category.HOME_MAIN";
+ /**
* This is the setup wizard activity, that is the first activity that is displayed
* when the user sets up the device for the first time.
* @hide
@@ -3795,6 +3963,42 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_SIM_ACTIVATION_RESPONSE =
"android.intent.extra.SIM_ACTIVATION_RESPONSE";
+ /**
+ * Extra for {@link #ACTION_THEME_RESOURCES_CACHED} that provides the return value
+ * from processThemeResources. A value of 0 indicates a successful caching of resources.
+ * Error results are:
+ * {@link android.content.pm.PackageManager#INSTALL_FAILED_THEME_AAPT_ERROR}
+ * {@link android.content.pm.PackageManager#INSTALL_FAILED_THEME_IDMAP_ERROR}
+ * {@link android.content.pm.PackageManager#INSTALL_FAILED_THEME_UNKNOWN_ERROR}
+ *
+ * @hide
+ */
+ public static final String EXTRA_THEME_RESULT = "android.intent.extra.RESULT";
+
+ /**
+ * Extra for {@link #ACTION_THEME_RESOURCES_CACHED} that provides the package name of the
+ * theme that was processed.
+ *
+ * @hide
+ */
+ public static final String EXTRA_THEME_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
+
+ /**
+ * Extra for {@link #ACTION_HOTWORD_INPUT_CHANGED} that provides the state of
+ * the input when the broadcast action was sent.
+ * @hide
+ */
+ public static final String EXTRA_HOTWORD_INPUT_STATE =
+ "com.cyanogenmod.intent.extra.HOTWORD_INPUT_STATE";
+
+ /**
+ * Extra for {@link #ACTION_RECENTS_LONG_PRESS} that provides the package name of the
+ * app in foreground when recents was long pressed. Can be reused for other purposes.
+ * @hide
+ */
+ public static final String EXTRA_CURRENT_PACKAGE_NAME =
+ "com.cyanogenmod.intent.extra.CURRENT_PACKAGE_NAME";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
diff --git a/core/java/android/content/ThemeVersion.java b/core/java/android/content/ThemeVersion.java
new file mode 100644
index 0000000..05fbc41
--- /dev/null
+++ b/core/java/android/content/ThemeVersion.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content;
+
+/**
+ * Warning: Careful moving/refactoring this class as our SDK references it.
+ * ThemeVersion 1 = CM11
+ * ThemeVersion 2 = CM12/CM12.1 First Release
+ * ThemeVersion 3 = CM12.1 W/ Wallpaper Packs
+ * @hide
+ */
+public class ThemeVersion {
+ /**
+ * Increment this anytime changes are made to:
+ * 1) Changes to ThemesContract
+ * 2) Changes to ThemeService API
+ * 3) Changes to ThemeManager API
+ */
+ public static int THEME_VERSION = 3;
+
+ /**
+ * Change this if a change to the contract or service would break compatibility.
+ * Example: A client app like chooser might be outdated from the framework.
+ * It could then query the FW for this value and determine whether its safe to proceed.
+ */
+ public static int MIN_SUPPORTED_THEME_VERSION = 2;
+
+ /**
+ * Do not change the order of this. See SDK.
+ * Increment the minSupportedVersion when the fw can no longer support a theme's apk structure
+ * Increment currentVersion when a change to the theme's apk structure is changed
+ * For example, CM11 to CM12 introduces new resources to overlay, so the overlays
+ * version should change. Because the changes are not compatible with CM11, the minVersion
+ * must change as well.
+ *
+ * If a new feature is added to a component (ex rotations in icon packs), the current version
+ * for the ICON component would be incremented. If a new component is created, then add it
+ * to the enum list.
+ *
+ * Wallpaper Version 2: Multi wallpaper ability
+ *
+ */
+ public static enum ComponentVersion {
+ OVERLAY(0, 2, 2),
+ BOOT_ANIM(1, 1, 1),
+ WALLPAPER(2, 1, 2),
+ LOCKSCREEN(3, 1, 1),
+ FONT(4, 1, 2),
+ ICON(5, 1, 1),
+ SOUNDS(6, 1, 1);
+
+ public int id;
+ public int minSupportedVersion;
+ public int currentVersion;
+
+ private ComponentVersion(int id, int minSupportedVersion, int currentVersion) {
+ this.id = id;
+ this.minSupportedVersion = minSupportedVersion;
+ this.currentVersion = currentVersion;
+ }
+ }
+}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index e798eb8..0105e09 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2007 The Android Open Source Project
- *
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
+
* 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
@@ -545,6 +546,16 @@ public class ActivityInfo extends ComponentInfo
*/
public static final int CONFIG_LAYOUT_DIRECTION = 0x2000;
/**
+ * Bit in {@link #configChanges} that indicates a theme change occurred
+ * @hide
+ */
+ public static final int CONFIG_THEME_RESOURCE = 0x100000;
+ /**
+ * Bit in {@link #configChanges} that indicates a font change occurred
+ * @hide
+ */
+ public static final int CONFIG_THEME_FONT = 0x200000;
+ /**
* Bit in {@link #configChanges} that indicates that the activity
* can itself handle changes to the font scaling factor. Set from the
* {@link android.R.attr#configChanges} attribute. This is
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6feb860..1933fc9 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -654,6 +655,19 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public int installLocation = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+ /**
+ * When true, indicates that any one component within this application is
+ * protected.
+ * @hide
+ */
+ public boolean protect = false;
+
+ /**
+ * Is given application theme agnostic, i.e. behaves properly when default theme is changed.
+ * @hide
+ */
+ public boolean isThemeable = false;
+
public void dump(Printer pw, String prefix) {
super.dumpFront(pw, prefix);
if (className != null) {
@@ -785,6 +799,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
uiOptions = orig.uiOptions;
backupAgentName = orig.backupAgentName;
fullBackupContent = orig.fullBackupContent;
+ protect = orig.protect;
+ isThemeable = orig.isThemeable;
}
@@ -838,6 +854,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeInt(descriptionRes);
dest.writeInt(uiOptions);
dest.writeInt(fullBackupContent);
+ dest.writeInt(protect ? 1 : 0);
+ dest.writeInt(isThemeable ? 1 : 0);
}
public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -890,6 +908,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
descriptionRes = source.readInt();
uiOptions = source.readInt();
fullBackupContent = source.readInt();
+ protect = source.readInt() != 0;
+ isThemeable = source.readInt() != 0;
}
/**
diff --git a/core/java/android/content/pm/BaseThemeInfo.java b/core/java/android/content/pm/BaseThemeInfo.java
new file mode 100644
index 0000000..8ece42d
--- /dev/null
+++ b/core/java/android/content/pm/BaseThemeInfo.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010, T-Mobile USA, Inc.
+ *
+ * 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.content.pm;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.util.Log;
+import android.util.AttributeSet;
+import android.content.res.Resources;
+
+/**
+ * @hide
+ */
+public class BaseThemeInfo implements Parcelable {
+ /**
+ * The theme id, which does not change when the theme is modified.
+ * Specifies an Android UI Style using style name.
+ *
+ * @see themeId attribute
+ *
+ */
+ public String themeId;
+
+ /**
+ * The name of the theme (as displayed by UI).
+ *
+ * @see name attribute
+ *
+ */
+ public String name;
+
+ /**
+ * The author name of the theme package.
+ *
+ * @see author attribute
+ *
+ */
+ public String author;
+
+ /*
+ * Describe the kinds of special objects contained in this Parcelable's
+ * marshalled representation.
+ *
+ * @return a bitmask indicating the set of special object types marshalled
+ * by the Parcelable.
+ *
+ * @see android.os.Parcelable#describeContents()
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /*
+ * Flatten this object in to a Parcel.
+ *
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
+ *
+ * @see android.os.Parcelable#writeToParcel(android.os.Parcel, int)
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(themeId);
+ dest.writeString(name);
+ dest.writeString(author);
+ }
+
+ /** @hide */
+ public static final Parcelable.Creator<BaseThemeInfo> CREATOR
+ = new Parcelable.Creator<BaseThemeInfo>() {
+ public BaseThemeInfo createFromParcel(Parcel source) {
+ return new BaseThemeInfo(source);
+ }
+
+ public BaseThemeInfo[] newArray(int size) {
+ return new BaseThemeInfo[size];
+ }
+ };
+
+ /** @hide */
+ public final String getResolvedString(Resources res, AttributeSet attrs, int index) {
+ int resId = attrs.getAttributeResourceValue(index, 0);
+ if (resId !=0 ) {
+ return res.getString(resId);
+ }
+ return attrs.getAttributeValue(index);
+ }
+
+ protected BaseThemeInfo() {
+ }
+
+ protected BaseThemeInfo(Parcel source) {
+ themeId = source.readString();
+ name = source.readString();
+ author = source.readString();
+ }
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index fec2c44..a3329db 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -17,6 +17,7 @@
package android.content.pm;
+import android.app.ComposedIconInfo;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -509,4 +510,17 @@ interface IPackageManager {
boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId);
String getPermissionControllerPackageName();
+
+ /** Protected Apps */
+ void setComponentProtectedSetting(in ComponentName componentName,
+ in boolean newState, int userId);
+
+ /** Themes */
+ void updateIconMapping(String pkgName);
+ ComposedIconInfo getComposedIconInfo();
+ int processThemeResources(String themePkgName);
+
+ /** Protected Apps */
+ boolean isComponentProtected(in String callingPackage, in int callingUid,
+ in ComponentName componentName, int userId);
}
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 9e6c6b5..0de867e 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +17,11 @@
package android.content.pm;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
import android.os.Parcel;
import android.os.Parcelable;
@@ -254,6 +260,34 @@ public class PackageInfo implements Parcelable {
/** @hide */
public boolean coreApp;
+ // Is Theme Apk
+ /**
+ * {@hide}
+ */
+ public boolean isThemeApk = false;
+
+ /**
+ * {@hide}
+ */
+ public boolean hasIconPack = false;
+
+ /**
+ * {@hide}
+ */
+ public ArrayList<String> mOverlayTargets;
+
+ // Is Legacy Icon Apk
+ /**
+ * {@hide}
+ */
+ public boolean isLegacyIconPackApk = false;
+
+ // ThemeInfo
+ /**
+ * {@hide}
+ */
+ public ThemeInfo themeInfo;
+
/** @hide */
public boolean requiredForAllUsers;
@@ -323,6 +357,13 @@ public class PackageInfo implements Parcelable {
dest.writeString(restrictedAccountType);
dest.writeString(requiredAccountType);
dest.writeString(overlayTarget);
+
+ /* Theme-specific. */
+ dest.writeInt((isThemeApk) ? 1 : 0);
+ dest.writeStringList(mOverlayTargets);
+ dest.writeParcelable(themeInfo, parcelableFlags);
+ dest.writeInt(hasIconPack ? 1 : 0);
+ dest.writeInt((isLegacyIconPackApk) ? 1 : 0);
}
public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -372,5 +413,12 @@ public class PackageInfo implements Parcelable {
restrictedAccountType = source.readString();
requiredAccountType = source.readString();
overlayTarget = source.readString();
+
+ /* Theme-specific. */
+ isThemeApk = (source.readInt() != 0);
+ mOverlayTargets = source.createStringArrayList();
+ themeInfo = source.readParcelable(null);
+ hasIconPack = source.readInt() == 1;
+ isLegacyIconPackApk = source.readInt() == 1;
}
}
diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java
index 1efe082..d4f33fb 100644
--- a/core/java/android/content/pm/PackageInfoLite.java
+++ b/core/java/android/content/pm/PackageInfoLite.java
@@ -62,6 +62,7 @@ public class PackageInfoLite implements Parcelable {
*/
public int recommendedInstallLocation;
public int installLocation;
+ public boolean isTheme;
public VerifierInfo[] verifiers;
@@ -87,6 +88,7 @@ public class PackageInfoLite implements Parcelable {
dest.writeInt(recommendedInstallLocation);
dest.writeInt(installLocation);
dest.writeInt(multiArch ? 1 : 0);
+ dest.writeInt(isTheme ? 1 : 0);
if (verifiers == null || verifiers.length == 0) {
dest.writeInt(0);
@@ -116,6 +118,7 @@ public class PackageInfoLite implements Parcelable {
recommendedInstallLocation = source.readInt();
installLocation = source.readInt();
multiArch = (source.readInt() != 0);
+ isTheme = source.readInt() == 1 ? true : false;
final int verifiersLength = source.readInt();
if (verifiersLength == 0) {
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 22a899c..366deb4 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -66,7 +66,14 @@ public class PackageItemInfo {
* component's icon. From the "icon" attribute or, if not set, 0.
*/
public int icon;
-
+
+ /**
+ * A drawable resource identifier in the icon pack's resources
+ * If there isn't an icon pack or not set, then 0.
+ * @hide
+ */
+ public int themedIcon;
+
/**
* A drawable resource identifier (in the package's resources) of this
* component's banner. From the "banner" attribute or, if not set, 0.
@@ -110,6 +117,7 @@ public class PackageItemInfo {
logo = orig.logo;
metaData = orig.metaData;
showUserIcon = orig.showUserIcon;
+ themedIcon = orig.themedIcon;
}
/**
@@ -309,8 +317,9 @@ public class PackageItemInfo {
dest.writeBundle(metaData);
dest.writeInt(banner);
dest.writeInt(showUserIcon);
+ dest.writeInt(themedIcon);
}
-
+
protected PackageItemInfo(Parcel source) {
name = source.readString();
packageName = source.readString();
@@ -322,6 +331,7 @@ public class PackageItemInfo {
metaData = source.readBundle();
banner = source.readInt();
showUserIcon = source.readInt();
+ themedIcon = source.readInt();
}
/**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c8e9402..8f0500e 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -830,6 +830,51 @@ public abstract class PackageManager {
public static final int INSTALL_FAILED_ABORTED = -115;
/**
+ * Used by themes
+ * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+ * if the system failed to install the theme because aapt could not compile the app
+ * @hide
+ */
+ public static final int INSTALL_FAILED_THEME_AAPT_ERROR = -400;
+
+ /**
+ * Used by themes
+ * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+ * if the system failed to install the theme because idmap failed
+ * apps.
+ * @hide
+ */
+ public static final int INSTALL_FAILED_THEME_IDMAP_ERROR = -401;
+
+ /**
+ * Used by themes
+ * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+ * if the system failed to install the theme for an unknown reason
+ * apps.
+ * @hide
+ */
+ public static final int INSTALL_FAILED_THEME_UNKNOWN_ERROR = -402;
+
+ /**
+ * Used for prebundles
+ * Installation failed for a prebundled app because the user previously uninstalled it
+ * and we don't want to bring it back
+ * @hide
+ */
+ public static final int INSTALL_FAILED_UNINSTALLED_PREBUNDLE = -403;
+
+ /**
+ * Used for prebundles
+ * Installation failed for a prebundled app because it wasn't needed in the default
+ * mobile country exported by the hardware
+ * @hide
+ */
+ public static final int INSTALL_FAILED_REGION_LOCKED_PREBUNDLE = -404; //bloat not found
+
+ /**
* Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the
* package's data directory.
*
@@ -1912,6 +1957,20 @@ public abstract class PackageManager {
= "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
/**
+ * Flag for {@link #setComponentProtectedSetting(android.content.ComponentName, boolean)}:
+ * This component or application has set to protected status
+ * @hide
+ */
+ public static final boolean COMPONENT_PROTECTED_STATUS = false;
+
+ /**
+ * Flag for {@link #setComponentProtectedSetting(android.content.ComponentName, boolean)}:
+ * This component or application has been explicitly set to visible status
+ * @hide
+ */
+ public static final boolean COMPONENT_VISIBLE_STATUS = true;
+
+ /**
* String extra for {@link PackageInstallObserver} in the 'extras' Bundle in case of
* {@link #INSTALL_FAILED_DUPLICATE_PERMISSION}. This extra names the package which provides
* the existing definition for the permission.
@@ -3511,6 +3570,18 @@ public abstract class PackageManager {
public abstract Resources getResourcesForApplicationAsUser(String appPackageName, int userId)
throws NameNotFoundException;
+ /** @hide */
+ public abstract Resources getThemedResourcesForApplication(ApplicationInfo app,
+ String themePkgName) throws NameNotFoundException;
+
+ /** @hide */
+ public abstract Resources getThemedResourcesForApplication(String appPackageName,
+ String themePkgName) throws NameNotFoundException;
+
+ /** @hide */
+ public abstract Resources getThemedResourcesForApplicationAsUser(String appPackageName,
+ String themePkgName, int userId) throws NameNotFoundException;
+
/**
* Retrieve overall information about an application package defined
* in a package archive file
@@ -4484,6 +4555,19 @@ public abstract class PackageManager {
public abstract @NonNull PackageInstaller getPackageInstaller();
/**
+ * Update Component protection state
+ * @hide
+ */
+ public abstract void setComponentProtectedSetting(ComponentName componentName, boolean newState);
+
+ /**
+ * Return whether or not a specific component is protected
+ * @hide
+ */
+ public abstract boolean isComponentProtected(String callingPackage, int callingUid,
+ ComponentName componentName);
+
+ /**
* Adds a {@link CrossProfileIntentFilter}. After calling this method all intents sent from the
* user with id sourceUserId can also be be resolved by activities in the user with id
* targetUserId if they match the specified intent filter.
@@ -4709,4 +4793,22 @@ public abstract class PackageManager {
}
}
}
+
+ /**
+ * Updates the theme icon res id for the new theme
+ * @hide
+ */
+ public abstract void updateIconMaps(String pkgName);
+
+ /**
+ * Used to compile theme resources for a given theme
+ * @param themePkgName
+ * @return A value of 0 indicates success. Possible errors returned are:
+ * {@link android.content.pm.PackageManager#INSTALL_FAILED_THEME_AAPT_ERROR},
+ * {@link android.content.pm.PackageManager#INSTALL_FAILED_THEME_IDMAP_ERROR}, or
+ * {@link android.content.pm.PackageManager#INSTALL_FAILED_THEME_UNKNOWN_ERROR}
+ *
+ * @hide
+ */
+ public abstract int processThemeResources(String themePkgName);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 99bd390..6a07b31 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -61,6 +62,7 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
@@ -77,12 +79,17 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.jar.StrictJarFile;
import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
/**
* Parser for package files (APKs) on disk. This supports apps packaged either
@@ -112,6 +119,17 @@ public class PackageParser {
/** File name in an APK for the Android manifest. */
private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
+ /** Path to overlay directory in a theme APK */
+ private static final String OVERLAY_PATH = "assets/overlays/";
+ /** Path to icon directory in a theme APK */
+ private static final String ICON_PATH = "assets/icons/";
+
+ private static final String PACKAGE_REDIRECTIONS_XML = "res/xml/redirections.xml";
+
+ private static final String TAG_PACKAGE_REDIRECTIONS = "package-redirections";
+ private static final String TAG_RESOURCE_REDIRECTIONS = "resource-redirections";
+ private static final String TAG_ITEM = "item";
+ private static final String ATTRIBUTE_ITEM_NAME = "name";
/** Path prefix for apps on expanded storage */
private static final String MNT_EXPAND = "/mnt/expand/";
@@ -251,6 +269,7 @@ public class PackageParser {
public final int versionCode;
public final int installLocation;
public final VerifierInfo[] verifiers;
+ public boolean isTheme;
/** Names of any split APKs, ordered by parsed splitName */
public final String[] splitNames;
@@ -276,6 +295,7 @@ public class PackageParser {
public final boolean multiArch;
public final boolean extractNativeLibs;
+
public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
String[] splitCodePaths, int[] splitRevisionCodes) {
this.packageName = baseApk.packageName;
@@ -291,6 +311,7 @@ public class PackageParser {
this.coreApp = baseApk.coreApp;
this.multiArch = baseApk.multiArch;
this.extractNativeLibs = baseApk.extractNativeLibs;
+ this.isTheme = baseApk.isTheme;
}
public List<String> getAllCodePaths() {
@@ -318,11 +339,12 @@ public class PackageParser {
public final boolean coreApp;
public final boolean multiArch;
public final boolean extractNativeLibs;
+ public final boolean isTheme;
public ApkLite(String codePath, String packageName, String splitName, int versionCode,
int revisionCode, int installLocation, List<VerifierInfo> verifiers,
Signature[] signatures, boolean coreApp, boolean multiArch,
- boolean extractNativeLibs) {
+ boolean extractNativeLibs, boolean isTheme) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
@@ -334,6 +356,7 @@ public class PackageParser {
this.coreApp = coreApp;
this.multiArch = multiArch;
this.extractNativeLibs = extractNativeLibs;
+ this.isTheme = isTheme;
}
}
@@ -424,6 +447,14 @@ public class PackageParser {
pi.versionName = p.mVersionName;
pi.sharedUserId = p.mSharedUserId;
pi.sharedUserLabel = p.mSharedUserLabel;
+ pi.isThemeApk = p.mIsThemeApk;
+ pi.hasIconPack = p.hasIconPack;
+ pi.isLegacyIconPackApk = p.mIsLegacyIconPackApk;
+
+ if (pi.isThemeApk) {
+ pi.mOverlayTargets = p.mOverlayTargets;
+ pi.themeInfo = p.mThemeInfo;
+ }
pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
pi.installLocation = p.installLocation;
pi.coreApp = p.coreApp;
@@ -614,6 +645,7 @@ public class PackageParser {
public final static int PARSE_IS_PRIVILEGED = 1<<7;
public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
+ public final static int PARSE_IS_PREBUNDLED_DIR = 1<<10;
private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
@@ -898,6 +930,18 @@ public class PackageParser {
pkg.baseCodePath = apkPath;
pkg.mSignatures = null;
+ // If the pkg is a theme, we need to know what themes it overlays
+ // and determine if it has an icon pack
+ if (pkg.mIsThemeApk) {
+ //Determine existance of Overlays
+ ArrayList<String> overlayTargets = scanPackageOverlays(apkFile);
+ for(String overlay : overlayTargets) {
+ pkg.mOverlayTargets.add(overlay);
+ }
+
+ pkg.hasIconPack = packageHasIconPack(apkFile);
+ }
+
return pkg;
} catch (PackageParserException e) {
@@ -1020,6 +1064,68 @@ public class PackageParser {
return pkg;
}
+
+ private ArrayList<String> scanPackageOverlays(File originalFile) {
+ Set<String> overlayTargets = new HashSet<String>();
+ ZipFile privateZip = null;
+ try {
+ privateZip = new ZipFile(originalFile.getPath());
+ final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries();
+ while (privateZipEntries.hasMoreElements()) {
+ final ZipEntry zipEntry = privateZipEntries.nextElement();
+ final String zipEntryName = zipEntry.getName();
+
+ if (zipEntryName.startsWith(OVERLAY_PATH) && zipEntryName.length() > 16) {
+ String[] subdirs = zipEntryName.split("/");
+ overlayTargets.add(subdirs[2]);
+ }
+ }
+ } catch(Exception e) {
+ e.printStackTrace();
+ overlayTargets.clear();
+ } finally {
+ if (privateZip != null) {
+ try {
+ privateZip.close();
+ } catch (Exception e) {
+ //Ignore
+ }
+ }
+ }
+
+ ArrayList<String> overlays = new ArrayList<String>();
+ overlays.addAll(overlayTargets);
+ return overlays;
+ }
+
+ private boolean packageHasIconPack(File originalFile) {
+ ZipFile privateZip = null;
+ try {
+ privateZip = new ZipFile(originalFile.getPath());
+ final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries();
+ while (privateZipEntries.hasMoreElements()) {
+ final ZipEntry zipEntry = privateZipEntries.nextElement();
+ final String zipEntryName = zipEntry.getName();
+
+ if (zipEntryName.startsWith(ICON_PATH) &&
+ zipEntryName.length() > ICON_PATH.length()) {
+ return true;
+ }
+ }
+ } catch(Exception e) {
+ Log.e(TAG, "Could not read zip entries while checking if apk has icon pack", e);
+ } finally {
+ if (privateZip != null) {
+ try {
+ privateZip.close();
+ } catch (Exception e) {
+ //Ignore
+ }
+ }
+ }
+ return false;
+ }
+
/**
* Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the
* APK. If it successfully scanned the package and found the
@@ -1027,6 +1133,7 @@ public class PackageParser {
*/
public void collectManifestDigest(Package pkg) throws PackageParserException {
pkg.manifestDigest = null;
+ pkg.manifestHashCode = 0;
// TODO: extend to gather digest for split APKs
try {
@@ -1035,6 +1142,7 @@ public class PackageParser {
final ZipEntry je = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
if (je != null) {
pkg.manifestDigest = ManifestDigest.fromInputStream(jarFile.getInputStream(je));
+ pkg.manifestHashCode = ThemeUtils.getPackageHashCode(pkg, jarFile);
}
} finally {
jarFile.close();
@@ -1300,6 +1408,9 @@ public class PackageParser {
// Only search the tree when the tag is directly below <manifest>
int type;
final int searchDepth = parser.getDepth() + 1;
+ // Search for category and actions inside <intent-filter>
+ final int iconPackSearchDepth = parser.getDepth() + 4;
+ boolean isTheme = false;
final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1326,11 +1437,53 @@ public class PackageParser {
}
}
}
+
+ if (parser.getDepth() == searchDepth && "meta-data".equals(parser.getName())) {
+ for (int i=0; i < parser.getAttributeCount(); i++) {
+ if ("name".equals(parser.getAttributeName(i)) &&
+ ThemeInfo.META_TAG_NAME.equals(parser.getAttributeValue(i))) {
+ isTheme = true;
+ installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+ break;
+ }
+ }
+ }
+
+ if (parser.getDepth() == searchDepth && "theme".equals(parser.getName())) {
+ isTheme = true;
+ installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+ }
+
+ if (parser.getDepth() == iconPackSearchDepth && isLegacyIconPack(parser)) {
+ isTheme = true;
+ installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+ }
}
return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
revisionCode, installLocation, verifiers, signatures, coreApp, multiArch,
- extractNativeLibs);
+ extractNativeLibs, isTheme);
+ }
+
+ private static boolean isLegacyIconPack(XmlPullParser parser) {
+ boolean isAction = "action".equals(parser.getName());
+ boolean isCategory = "category".equals(parser.getName());
+ String[] items = isAction ? ThemeUtils.sSupportedActions
+ : (isCategory ? ThemeUtils.sSupportedCategories : null);
+
+ if (items != null) {
+ for (int i = 0; i < parser.getAttributeCount(); i++) {
+ if ("name".equals(parser.getAttributeName(i))) {
+ final String value = parser.getAttributeValue(i);
+ for (String item : items) {
+ if (item.equals(value)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
}
/**
@@ -1382,6 +1535,8 @@ public class PackageParser {
}
final Package pkg = new Package(pkgName);
+ Bundle metaDataBundle = new Bundle();
+
boolean foundApp = false;
TypedArray sa = res.obtainAttributes(attrs,
@@ -1794,6 +1949,11 @@ public class PackageParser {
XmlUtils.skipCurrentTag(parser);
continue;
+ } else if (parser.getName().equals("meta-data")) {
+ if ((metaDataBundle=parseMetaData(res, parser, attrs, metaDataBundle,
+ outError)) == null) {
+ return null;
+ }
} else if (RIGID_PARSER) {
outError[0] = "Bad element under <manifest>: "
+ parser.getName();
@@ -1882,6 +2042,17 @@ public class PackageParser {
>= android.os.Build.VERSION_CODES.DONUT)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
}
+ if (pkg.mIsThemeApk || pkg.mIsLegacyIconPackApk) {
+ pkg.applicationInfo.isThemeable = false;
+ }
+
+ //Is this pkg a theme?
+ if (metaDataBundle.containsKey(ThemeInfo.META_TAG_NAME)) {
+ pkg.mIsThemeApk = true;
+ pkg.mTrustedOverlay = true;
+ pkg.mOverlayPriority = 1;
+ pkg.mThemeInfo = new ThemeInfo(metaDataBundle);
+ }
return pkg;
}
@@ -2257,6 +2428,10 @@ public class PackageParser {
perm.info.flags = sa.getInt(
com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0);
+ perm.info.allowViaWhitelist = sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestPermission_allowViaWhitelist,
+ false);
+
sa.recycle();
if (perm.info.protectionLevel == -1) {
@@ -2409,6 +2584,10 @@ public class PackageParser {
final ApplicationInfo ai = owner.applicationInfo;
final String pkgName = owner.applicationInfo.packageName;
+ String[] nonThemeablePackages =
+ res.getStringArray(com.android.internal.R.array.non_themeable_packages);
+ ai.isThemeable = isPackageThemeable(pkgName, nonThemeablePackages);
+
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestApplication);
@@ -3238,6 +3417,26 @@ public class PackageParser {
if (!parseIntent(res, parser, attrs, true, true, intent, outError)) {
return null;
}
+
+ // Check if package is a legacy icon pack
+ if (!owner.mIsLegacyIconPackApk) {
+ for(String action : ThemeUtils.sSupportedActions) {
+ if (intent.hasAction(action)) {
+ owner.mIsLegacyIconPackApk = true;
+ break;
+ }
+
+ }
+ }
+ if (!owner.mIsLegacyIconPackApk) {
+ for(String category : ThemeUtils.sSupportedCategories) {
+ if (intent.hasCategory(category)) {
+ owner.mIsLegacyIconPackApk = true;
+ break;
+ }
+ }
+ }
+
if (intent.countActions() == 0) {
Slog.w(TAG, "No actions in intent filter at "
+ mArchiveSourcePath + " "
@@ -4247,6 +4446,22 @@ public class PackageParser {
return true;
}
+ /**1
+ * Returns whether the specified package is themeable
+ * @param packageName Name of package to check
+ * @param nonThemeablePackages Array of packages that are declared as non-themeable
+ * @return True if the package is themeable, false otherwise
+ */
+ private static boolean isPackageThemeable(String packageName, String[] nonThemeablePackages) {
+ for (String pkg : nonThemeablePackages) {
+ if (packageName.startsWith(pkg)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
/**
* Representation of a full package parsed from APK files on disk. A package
* consists of a single base APK, and zero or more split APKs.
@@ -4345,6 +4560,17 @@ public class PackageParser {
// For use by package manager to keep track of when a package was last used.
public long mLastPackageUsageTimeInMills;
+ // Is Theme Apk
+ public boolean mIsThemeApk = false;
+ public final ArrayList<String> mOverlayTargets = new ArrayList<String>(0);
+ public Map<String, Map<String, String>> mPackageRedirections
+ = new HashMap<String, Map<String, String>>();
+
+ // Theme info
+ public ThemeInfo mThemeInfo = null;
+
+ // Legacy icon pack
+ public boolean mIsLegacyIconPackApk = false;
// // User set enabled state.
// public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -4387,6 +4613,9 @@ public class PackageParser {
public int mOverlayPriority;
public boolean mTrustedOverlay;
+ public boolean hasIconPack;
+ public int manifestHashCode;
+
/**
* Data used to feed the KeySetManagerService
*/
@@ -4739,6 +4968,12 @@ public class PackageParser {
&& p.usesLibraryFiles != null) {
return true;
}
+ if (state.protectedComponents != null) {
+ boolean protect = state.protectedComponents.size() > 0;
+ if (p.applicationInfo.protect != protect) {
+ return true;
+ }
+ }
return false;
}
@@ -4772,6 +5007,9 @@ public class PackageParser {
ai.enabled = false;
}
ai.enabledSetting = state.enabled;
+ if (state.protectedComponents != null) {
+ ai.protect = state.protectedComponents.size() > 0;
+ }
}
public static ApplicationInfo generateApplicationInfo(Package p, int flags,
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 9b28401..7b6d188 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -36,6 +36,8 @@ public class PackageUserState {
public ArraySet<String> disabledComponents;
public ArraySet<String> enabledComponents;
+ public ArraySet<String> protectedComponents;
+ public ArraySet<String> visibleComponents;
public int domainVerificationStatus;
public int appLinkGeneration;
@@ -62,5 +64,9 @@ public class PackageUserState {
blockUninstall = o.blockUninstall;
domainVerificationStatus = o.domainVerificationStatus;
appLinkGeneration = o.appLinkGeneration;
+ protectedComponents = o.protectedComponents != null
+ ? new ArraySet<String>(o.protectedComponents) : null;
+ visibleComponents = o.visibleComponents != null
+ ? new ArraySet<String>(o.visibleComponents) : null;
}
}
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 9da2ba9..0fed65f 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -178,6 +178,14 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
*/
public CharSequence nonLocalizedDescription;
+ /**
+ * Whether this permission will be granted to apps signed with white-listed keys in
+ * /system/etc/permissions/someapp.xml
+ *
+ * @hide
+ */
+ public boolean allowViaWhitelist;
+
/** @hide */
public static int fixProtectionLevel(int level) {
if (level == PROTECTION_SIGNATURE_OR_SYSTEM) {
@@ -237,6 +245,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
group = orig.group;
descriptionRes = orig.descriptionRes;
nonLocalizedDescription = orig.nonLocalizedDescription;
+ allowViaWhitelist = orig.allowViaWhitelist;
}
/**
@@ -279,6 +288,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
dest.writeInt(flags);
dest.writeString(group);
dest.writeInt(descriptionRes);
+ dest.writeInt(allowViaWhitelist ? 1 : 0);
TextUtils.writeToParcel(nonLocalizedDescription, dest, parcelableFlags);
}
@@ -298,6 +308,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
flags = source.readInt();
group = source.readString();
descriptionRes = source.readInt();
+ allowViaWhitelist = source.readInt() == 1;
nonLocalizedDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
}
}
diff --git a/core/java/android/content/pm/ThemeInfo.aidl b/core/java/android/content/pm/ThemeInfo.aidl
new file mode 100644
index 0000000..acbc85e
--- /dev/null
+++ b/core/java/android/content/pm/ThemeInfo.aidl
@@ -0,0 +1,3 @@
+package android.content.pm;
+
+parcelable ThemeInfo;
diff --git a/core/java/android/content/pm/ThemeInfo.java b/core/java/android/content/pm/ThemeInfo.java
new file mode 100644
index 0000000..ab798db
--- /dev/null
+++ b/core/java/android/content/pm/ThemeInfo.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010, T-Mobile USA, Inc.
+ *
+ * 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.content.pm;
+
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParser;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.content.res.Resources;
+
+/**
+ * Overall information about "theme" package. This corresponds
+ * to the information collected from AndroidManifest.xml
+ *
+ * Below is an example of the manifest:
+ *
+ * <meta-data android:name="org.cyanogenmod.theme.name" android:value="Foobar's Theme"/>
+ * <meta-data android:name="org.cyanogenmod.theme.author" android:value="Mr.Foo" />
+ *
+ * @hide
+ */
+public final class ThemeInfo extends BaseThemeInfo {
+
+ public static final String META_TAG_NAME = "org.cyanogenmod.theme.name";
+ public static final String META_TAG_AUTHOR = "org.cyanogenmod.theme.author";
+
+ public ThemeInfo(Bundle bundle) {
+ super();
+ name = bundle.getString(META_TAG_NAME);
+ themeId = name;
+ author = bundle.getString(META_TAG_AUTHOR);
+ }
+
+ public static final Parcelable.Creator<ThemeInfo> CREATOR
+ = new Parcelable.Creator<ThemeInfo>() {
+ public ThemeInfo createFromParcel(Parcel source) {
+ return new ThemeInfo(source);
+ }
+
+ public ThemeInfo[] newArray(int size) {
+ return new ThemeInfo[size];
+ }
+ };
+
+ private ThemeInfo(Parcel source) {
+ super(source);
+ }
+}
diff --git a/core/java/android/content/pm/ThemeUtils.java b/core/java/android/content/pm/ThemeUtils.java
new file mode 100644
index 0000000..07e73b5
--- /dev/null
+++ b/core/java/android/content/pm/ThemeUtils.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm;
+
+import android.content.res.ThemeConfig;
+import android.text.TextUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.jar.StrictJarFile;
+import java.util.zip.ZipEntry;
+
+/**
+ * @hide
+ */
+public class ThemeUtils {
+ private static final String TAG = ThemeUtils.class.getSimpleName();
+
+ /* Path inside a theme APK to the overlay folder */
+ public static final String OVERLAY_PATH = "assets/overlays/";
+ public static final String ICONS_PATH = "assets/icons/";
+ public static final String COMMON_RES_PATH = "assets/overlays/common/";
+ public static final String RESOURCE_CACHE_DIR = "/data/resource-cache/";
+ public static final String COMMON_RES_TARGET = "common";
+
+ // Package name for any app which does not have a specific theme applied
+ private static final String DEFAULT_PKG = "default";
+
+ private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
+
+ /**
+ * IDMAP hash version code used to alter the resulting hash and force recreating
+ * of the idmap. This value should be changed whenever there is a need to force
+ * an update to all idmaps.
+ */
+ private static final byte IDMAP_HASH_VERSION = 3;
+
+ // Actions in manifests which identify legacy icon packs
+ public static final String[] sSupportedActions = new String[] {
+ "org.adw.launcher.THEMES",
+ "com.gau.go.launcherex.theme",
+ "com.novalauncher.THEME"
+ };
+
+ // Categories in manifests which identify legacy icon packs
+ public static final String[] sSupportedCategories = new String[] {
+ "com.fede.launcher.THEME_ICONPACK",
+ "com.anddoes.launcher.THEME",
+ "com.teslacoilsw.launcher.THEME"
+ };
+
+
+ /**
+ * Get the root path of the resource cache for the given theme
+ * @param themePkgName
+ * @return Root resource cache path for the given theme
+ */
+ public static String getOverlayResourceCacheDir(String themePkgName) {
+ return RESOURCE_CACHE_DIR + themePkgName;
+ }
+
+ /**
+ * Get the path of the resource cache for the given target and theme
+ * @param targetPkgName Target app package name
+ * @param themePkgName Theme package name
+ * @return Path to the resource cache for this target and theme
+ */
+ public static String getTargetCacheDir(String targetPkgName, String themePkgName) {
+ return getOverlayResourceCacheDir(themePkgName) + File.separator + targetPkgName;
+ }
+
+ /**
+ * Get the path to the icons for the given theme
+ * @param pkgName
+ * @return
+ */
+ public static String getIconPackDir(String pkgName) {
+ return getOverlayResourceCacheDir(pkgName) + File.separator + "icons";
+ }
+
+ public static String getIconPackApkPath(String pkgName) {
+ return getIconPackDir(pkgName) + "/resources.apk";
+ }
+
+ public static String getIdmapPath(String targetPkgName, String overlayPkgName) {
+ return getTargetCacheDir(targetPkgName, overlayPkgName) + File.separator + "idmap";
+ }
+
+ public static String getOverlayPathToTarget(String targetPkgName) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(OVERLAY_PATH);
+ sb.append(targetPkgName);
+ sb.append('/');
+ return sb.toString();
+ }
+
+ public static String getCommonPackageName(String themePackageName) {
+ if (TextUtils.isEmpty(themePackageName)) return null;
+
+ return COMMON_RES_TARGET;
+ }
+
+ /**
+ * Convenience method to determine if a theme component is a per app theme and not a standard
+ * component.
+ * @param component
+ * @return
+ */
+ public static boolean isPerAppThemeComponent(String component) {
+ return !(DEFAULT_PKG.equals(component)
+ || ThemeConfig.SYSTEMUI_STATUS_BAR_PKG.equals(component)
+ || ThemeConfig.SYSTEMUI_NAVBAR_PKG.equals(component));
+ }
+
+ /**
+ * Get a 32 bit hashcode for the given package.
+ * @param pkg
+ * @return
+ */
+ public static int getPackageHashCode(PackageParser.Package pkg, StrictJarFile jarFile) {
+ int hash = pkg.manifestDigest != null ? pkg.manifestDigest.hashCode() : 0;
+ final ZipEntry je = jarFile.findEntry(MANIFEST_NAME);
+ if (je != null) {
+ try {
+ try {
+ ManifestDigest digest = ManifestDigest.fromInputStream(
+ jarFile.getInputStream(je));
+ if (digest != null) {
+ hash += digest.hashCode();
+ }
+ } finally {
+ jarFile.close();
+ }
+ } catch (IOException | RuntimeException e) {
+ // Failed to generate digest from manifest.mf
+ }
+ }
+ hash = 31 * hash + IDMAP_HASH_VERSION;
+ return hash;
+ }
+}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 8d96f5c..abb1871 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -21,9 +21,11 @@ import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
+import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.HashMap;
/**
@@ -77,6 +79,16 @@ public final class AssetManager implements AutoCloseable {
private boolean mOpen = true;
private HashMap<Long, RuntimeException> mRefStacks;
+ private String mAppName;
+
+ private boolean mThemeSupport;
+ private String mThemePackageName;
+ private String mIconPackageName;
+ private String mCommonResPackageName;
+ private ArrayList<Integer> mThemeCookies = new ArrayList<Integer>(2);
+ private int mIconPackCookie;
+ private int mCommonResCookie;
+
/**
* Create a new AssetManager containing only the basic system assets.
* Applications will not generally use this method, instead retrieving the
@@ -252,6 +264,12 @@ public final class AssetManager implements AutoCloseable {
}
}
+ /*package*/ final void recreateStringBlocks() {
+ synchronized (this) {
+ makeStringBlocks(sSystem.mStringBlocks);
+ }
+ }
+
/*package*/ final void makeStringBlocks(StringBlock[] seed) {
final int seedNum = (seed != null) ? seed.length : 0;
final int num = getStringBlockCount();
@@ -612,7 +630,9 @@ public final class AssetManager implements AutoCloseable {
public final int addAssetPath(String path) {
synchronized (this) {
int res = addAssetPathNative(path);
- makeStringBlocks(mStringBlocks);
+ if (mStringBlocks != null) {
+ makeStringBlocks(mStringBlocks);
+ }
return res;
}
}
@@ -627,11 +647,14 @@ public final class AssetManager implements AutoCloseable {
*
* {@hide}
*/
-
- public final int addOverlayPath(String idmapPath) {
+ public final int addOverlayPath(String idmapPath, String themeApkPath,
+ String resApkPath, String targetPkgPath, String prefixPath) {
synchronized (this) {
- int res = addOverlayPathNative(idmapPath);
- makeStringBlocks(mStringBlocks);
+ int res = addOverlayPathNative(idmapPath, themeApkPath, resApkPath, targetPkgPath,
+ prefixPath);
+ if (mStringBlocks != null) {
+ makeStringBlocks(mStringBlocks);
+ }
return res;
}
}
@@ -641,7 +664,59 @@ public final class AssetManager implements AutoCloseable {
*
* {@hide}
*/
- public native final int addOverlayPathNative(String idmapPath);
+ private native final int addOverlayPathNative(String idmapPath, String themeApkPath,
+ String resApkPath, String targetPkgPath, String prefixPath);
+
+ /**
+ * Add a set of common assets.
+ *
+ * {@hide}
+ */
+ public final int addCommonOverlayPath(String themeApkPath,
+ String resApkPath, String prefixPath) {
+ synchronized (this) {
+ return addCommonOverlayPathNative(themeApkPath, resApkPath, prefixPath);
+ }
+ }
+
+ private native final int addCommonOverlayPathNative(String themeApkPath,
+ String resApkPath, String prefixPath);
+
+ /**
+ * Add a set of assets as an icon pack. A pkgIdOverride value will change the package's id from
+ * what is in the resource table to a new value. Manage this carefully, if icon pack has more
+ * than one package then that next package's id will use pkgIdOverride+1.
+ *
+ * Icon packs are different from overlays as they have a different pkg id and
+ * do not use idmap so no targetPkg is required
+ *
+ * {@hide}
+ */
+ public final int addIconPath(String idmapPath, String resApkPath,
+ String prefixPath, int pkgIdOverride) {
+ synchronized (this) {
+ return addIconPathNative(idmapPath, resApkPath, prefixPath, pkgIdOverride);
+ }
+ }
+
+ private native final int addIconPathNative(String idmapPath,
+ String resApkPath, String prefixPath, int pkgIdOverride);
+
+ /**
+ * Delete a set of overlay assets from the asset manager. Not for use by
+ * applications. Returns true if succeeded or false on failure.
+ *
+ * Also works for icon packs
+ *
+ * {@hide}
+ */
+ public final boolean removeOverlayPath(String packageName, int cookie) {
+ synchronized (this) {
+ return removeOverlayPathNative(packageName, cookie);
+ }
+ }
+
+ private native final boolean removeOverlayPathNative(String packageName, int cookie);
/**
* Add multiple sets of assets to the asset manager at once. See
@@ -664,6 +739,126 @@ public final class AssetManager implements AutoCloseable {
}
/**
+ * Sets a flag indicating that this AssetManager should have themes
+ * attached, according to the initial request to create it by the
+ * ApplicationContext.
+ *
+ * {@hide}
+ */
+ public final void setThemeSupport(boolean themeSupport) {
+ mThemeSupport = themeSupport;
+ }
+
+ /**
+ * Should this AssetManager have themes attached, according to the initial
+ * request to create it by the ApplicationContext?
+ *
+ * {@hide}
+ */
+ public final boolean hasThemeSupport() {
+ return mThemeSupport;
+ }
+
+ /**
+ * Get package name of current icon pack (may return null).
+ * {@hide}
+ */
+ public String getIconPackageName() {
+ return mIconPackageName;
+ }
+
+ /**
+ * Sets icon package name
+ * {@hide}
+ */
+ public void setIconPackageName(String packageName) {
+ mIconPackageName = packageName;
+ }
+
+ /**
+ * Get package name of current common resources (may return null).
+ * {@hide}
+ */
+ public String getCommonResPackageName() {
+ return mCommonResPackageName;
+ }
+
+ /**
+ * Sets common resources package name
+ * {@hide}
+ */
+ public void setCommonResPackageName(String packageName) {
+ mCommonResPackageName = packageName;
+ }
+
+ /**
+ * Get package name of current theme (may return null).
+ * {@hide}
+ */
+ public String getThemePackageName() {
+ return mThemePackageName;
+ }
+
+ /**
+ * Sets package name and highest level style id for current theme (null, 0 is allowed).
+ * {@hide}
+ */
+ public void setThemePackageName(String packageName) {
+ mThemePackageName = packageName;
+ }
+
+ /**
+ * Get asset cookie for current theme (may return 0).
+ * {@hide}
+ */
+ public ArrayList<Integer> getThemeCookies() {
+ return mThemeCookies;
+ }
+
+ /** {@hide} */
+ public void setIconPackCookie(int cookie) {
+ mIconPackCookie = cookie;
+ }
+
+ /** {@hide} */
+ public int getIconPackCookie() {
+ return mIconPackCookie;
+ }
+
+ /** {@hide} */
+ public void setCommonResCookie(int cookie) {
+ mCommonResCookie = cookie;
+ }
+
+ /** {@hide} */
+ public int getCommonResCookie() {
+ return mCommonResCookie;
+ }
+
+ /**
+ * Sets asset cookie for current theme (0 if not a themed asset manager).
+ * {@hide}
+ */
+ public void addThemeCookie(int cookie) {
+ mThemeCookies.add(cookie);
+ }
+
+ /** {@hide} */
+ public String getAppName() {
+ return mAppName;
+ }
+
+ /** {@hide} */
+ public void setAppName(String pkgName) {
+ mAppName = pkgName;
+ }
+
+ /** {@hide} */
+ public boolean hasThemedAssets() {
+ return mThemeCookies.size() > 0;
+ }
+
+ /**
* Determine whether the state in this asset manager is up-to-date with
* the files on the filesystem. If false is returned, you need to
* instantiate a new AssetManager class to see the new data.
@@ -800,6 +995,26 @@ public final class AssetManager implements AutoCloseable {
/*package*/ native final int[] getStyleAttributes(int themeRes);
private native final void init(boolean isSystem);
+ /**
+ * {@hide}
+ */
+ public native final int getBasePackageCount();
+
+ /**
+ * {@hide}
+ */
+ public native final String getBasePackageName(int index);
+
+ /**
+ * {@hide}
+ */
+ public native final String getBaseResourcePackageName(int index);
+
+ /**
+ * {@hide}
+ */
+ public native final int getBasePackageId(int index);
+
private native final void destroy();
private final void incRefsLocked(long id) {
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index da35ee9..2b8951e 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -241,8 +241,7 @@ public class CompatibilityInfo implements Parcelable {
mCompatibilityFlags = compatFlags;
}
- private CompatibilityInfo(int compFlags,
- int dens, float scale, float invertedScale) {
+ private CompatibilityInfo(int compFlags, int dens, float scale, float invertedScale) {
mCompatibilityFlags = compFlags;
applicationDensity = dens;
applicationScale = scale;
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index fd60476..0bc1ec2 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -82,6 +83,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public Locale locale;
/**
+ * @hide
+ */
+ public ThemeConfig themeConfig;
+
+ /**
* Locale should persist on setting. This is hidden because it is really
* questionable whether this is the right way to expose the functionality.
* @hide
@@ -441,7 +447,47 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public static final int ORIENTATION_LANDSCAPE = 2;
/** @deprecated Not currently supported or used. */
@Deprecated public static final int ORIENTATION_SQUARE = 3;
-
+
+ /**
+ * @hide
+ * @deprecated
+ */
+ public static final String THEME_PACKAGE_NAME_PERSISTENCE_PROPERTY
+ = "persist.sys.themePackageName";
+
+ /**
+ * @hide
+ * @deprecated
+ */
+ public static final String THEME_ICONPACK_PACKAGE_NAME_PERSISTENCE_PROPERTY
+ = "themeIconPackPkgName";
+
+ /**
+ * @hide
+ * @deprecated
+ */
+ public static final String THEME_FONT_PACKAGE_NAME_PERSISTENCE_PROPERTY
+ = "themeFontPackPkgName";
+
+ /**
+ * @hide
+ * Serialized json structure mapping app pkgnames to their set theme.
+ *
+ * {
+ * "default":{
+ *" stylePkgName":"com.jasonevil.theme.miuiv5dark",
+ * "iconPkgName":"com.cyngn.hexo",
+ * "fontPkgName":"com.cyngn.hexo"
+ * }
+ * }
+
+ * If an app does not have a specific theme set then it will use the 'default' theme+
+ * example: 'default' -> overlayPkgName: 'org.blue.theme'
+ * 'com.android.phone' -> 'com.red.theme'
+ * 'com.google.vending' -> 'com.white.theme'
+ */
+ public static final String THEME_PKG_CONFIGURATION_PERSISTENCE_PROPERTY = "themeConfig";
+
/**
* Overall orientation of the screen. May be one of
* {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}.
@@ -673,8 +719,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration
compatScreenHeightDp = o.compatScreenHeightDp;
compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp;
seq = o.seq;
+ if (o.themeConfig != null) {
+ themeConfig = (ThemeConfig) o.themeConfig.clone();
+ }
}
-
+
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("{");
@@ -809,6 +858,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
sb.append(" s.");
sb.append(seq);
}
+ sb.append(" themeResource=");
+ sb.append(themeConfig);
sb.append('}');
return sb.toString();
}
@@ -835,6 +886,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
densityDpi = DENSITY_DPI_UNDEFINED;
seq = 0;
+ themeConfig = null;
}
/** {@hide} */
@@ -977,7 +1029,18 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (delta.seq != 0) {
seq = delta.seq;
}
-
+
+ if (delta.themeConfig != null
+ && (themeConfig == null || !themeConfig.equals(delta.themeConfig))) {
+ changed |= ActivityInfo.CONFIG_THEME_RESOURCE;
+ final String fontPkgName = delta.themeConfig.getFontPkgName();
+ if (themeConfig == null ||
+ (fontPkgName != null && !fontPkgName.equals(themeConfig.getFontPkgName()))) {
+ changed |= ActivityInfo.CONFIG_THEME_FONT;
+ }
+ themeConfig = (ThemeConfig)delta.themeConfig.clone();
+ }
+
return changed;
}
@@ -1087,7 +1150,15 @@ public final class Configuration implements Parcelable, Comparable<Configuration
&& densityDpi != delta.densityDpi) {
changed |= ActivityInfo.CONFIG_DENSITY;
}
-
+ if (delta.themeConfig != null &&
+ (themeConfig == null || !themeConfig.equals(delta.themeConfig))) {
+ changed |= ActivityInfo.CONFIG_THEME_RESOURCE;
+ final String fontPkgName = delta.themeConfig.getFontPkgName();
+ if (themeConfig == null ||
+ (fontPkgName != null && !fontPkgName.equals(themeConfig.getFontPkgName()))) {
+ changed |= ActivityInfo.CONFIG_THEME_FONT;
+ }
+ }
return changed;
}
@@ -1103,7 +1174,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* @return Return true if the resource needs to be loaded, else false.
*/
public static boolean needNewResources(int configChanges, int interestingChanges) {
- return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0;
+ return (configChanges & (interestingChanges |
+ ActivityInfo.CONFIG_FONT_SCALE |
+ ActivityInfo.CONFIG_THEME_RESOURCE)) != 0;
}
/**
@@ -1176,6 +1249,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
dest.writeInt(compatScreenHeightDp);
dest.writeInt(compatSmallestScreenWidthDp);
dest.writeInt(seq);
+ dest.writeParcelable(themeConfig, flags);
}
public void readFromParcel(Parcel source) {
@@ -1204,6 +1278,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
compatScreenHeightDp = source.readInt();
compatSmallestScreenWidthDp = source.readInt();
seq = source.readInt();
+ themeConfig = source.readParcelable(ThemeConfig.class.getClassLoader());
}
public static final Parcelable.Creator<Configuration> CREATOR
@@ -1271,7 +1346,12 @@ public final class Configuration implements Parcelable, Comparable<Configuration
n = this.smallestScreenWidthDp - that.smallestScreenWidthDp;
if (n != 0) return n;
n = this.densityDpi - that.densityDpi;
- //if (n != 0) return n;
+ if (n != 0) return n;
+ if (this.themeConfig == null) {
+ if (that.themeConfig != null) return 1;
+ } else {
+ n = this.themeConfig.compareTo(that.themeConfig);
+ }
return n;
}
@@ -1308,6 +1388,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
result = 31 * result + screenHeightDp;
result = 31 * result + smallestScreenWidthDp;
result = 31 * result + densityDpi;
+ result = 31 * result + (this.themeConfig != null ?
+ this.themeConfig.hashCode() : 0);
return result;
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 731903c..7fa04f9 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -21,6 +21,9 @@ import android.annotation.ColorInt;
import android.annotation.StyleRes;
import android.annotation.StyleableRes;
import com.android.internal.util.GrowingArrayUtils;
+import android.app.ComposedIconInfo;
+import android.app.IconPackHelper;
+import android.app.IconPackHelper.IconCustomizer;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -45,6 +48,7 @@ import android.annotation.RawRes;
import android.annotation.StringRes;
import android.annotation.XmlRes;
import android.content.pm.ActivityInfo;
+import android.content.pm.PackageItemInfo;
import android.graphics.Movie;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -59,6 +63,7 @@ import android.util.Log;
import android.util.LongSparseArray;
import android.util.Pools.SynchronizedPool;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.TypedValue;
import android.view.ViewDebug;
import android.view.ViewHierarchyEncoder;
@@ -108,6 +113,22 @@ public class Resources {
private static final int ID_OTHER = 0x01000004;
+ // Package IDs for themes. Aapt will compile the res table with this id.
+ /** @hide */
+ public static final int THEME_FRAMEWORK_PKG_ID = 0x60;
+ /** @hide */
+ public static final int THEME_APP_PKG_ID = 0x61;
+ /** @hide */
+ public static final int THEME_ICON_PKG_ID = 0x62;
+ /** @hide */
+ public static final int THEME_CM_PKG_ID = 0x63;
+ /**
+ * The common resource pkg id needs to be less than the THEME_FRAMEWORK_PKG_ID
+ * otherwise aapt will complain and fail
+ * @hide
+ */
+ public static final int THEME_COMMON_PKG_ID = THEME_FRAMEWORK_PKG_ID - 1;
+
private static final Object sSync = new Object();
// Information about preloaded resources. Note that they are not
@@ -158,6 +179,9 @@ public class Resources {
private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+ private SparseArray<PackageItemInfo> mIcons;
+ private ComposedIconInfo mComposedIconInfo;
+
static {
sPreloadedDrawables = new LongSparseArray[2];
sPreloadedDrawables[0] = new LongSparseArray<>();
@@ -268,7 +292,7 @@ public class Resources {
mCompatibilityInfo = compatInfo;
}
updateConfiguration(config, metrics);
- assets.ensureStringBlocks();
+ assets.recreateStringBlocks();
}
/**
@@ -793,6 +817,19 @@ public class Resources {
*/
@Nullable
public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme) throws NotFoundException {
+ return getDrawable(id, theme, true);
+ }
+
+ /** @hide */
+ @Nullable
+ public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme, boolean supportComposedIcons)
+ throws NotFoundException {
+ //Check if an icon is themed
+ PackageItemInfo info = mIcons != null ? mIcons.get(id) : null;
+ if (info != null && info.themedIcon != 0) {
+ id = info.themedIcon;
+ }
+
TypedValue value;
synchronized (mAccessLock) {
value = mTmpValue;
@@ -801,9 +838,24 @@ public class Resources {
} else {
mTmpValue = null;
}
- getValue(id, value, true);
+ getValue(id, value, true, supportComposedIcons);
+ }
+ Drawable res = null;
+ try {
+ res = loadDrawable(value, id, theme);
+ } catch (NotFoundException e) {
+ // The below statement will be true if we were trying to load a composed icon.
+ // Since we received a NotFoundException, try to load the original if this
+ // condition is true, otherwise throw the original exception.
+ if (supportComposedIcons && mComposedIconInfo != null && info != null &&
+ info.themedIcon == 0) {
+ Log.e(TAG, "Failed to retrieve composed icon.", e);
+ getValue(id, value, true, false);
+ res = loadDrawable(value, id, theme);
+ } else {
+ throw e;
+ }
}
- final Drawable res = loadDrawable(value, id, theme);
synchronized (mAccessLock) {
if (mTmpValue == null) {
mTmpValue = value;
@@ -860,6 +912,19 @@ public class Resources {
*/
@Nullable
public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
+ return getDrawableForDensity(id, density, theme, true);
+ }
+
+ /** @hide */
+ @Nullable
+ public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme,
+ boolean supportComposedIcons) {
+ //Check if an icon was themed
+ PackageItemInfo info = mIcons != null ? mIcons.get(id) : null;
+ if (info != null && info.themedIcon != 0) {
+ id = info.themedIcon;
+ }
+
TypedValue value;
synchronized (mAccessLock) {
value = mTmpValue;
@@ -868,7 +933,7 @@ public class Resources {
} else {
mTmpValue = null;
}
- getValueForDensity(id, density, value, true);
+ getValueForDensity(id, density, value, true, supportComposedIcons);
/*
* Pretend the requested density is actually the display density. If
@@ -1344,8 +1409,24 @@ public class Resources {
*/
public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
throws NotFoundException {
+ getValue(id, outValue, resolveRefs, true);
+ }
+
+ /** @hide */
+ public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs,
+ boolean supportComposedIcons) throws NotFoundException {
+ //Check if an icon was themed
+ PackageItemInfo info = mIcons != null ? mIcons.get(id) : null;
+ if (info != null && info.themedIcon != 0) {
+ id = info.themedIcon;
+ }
boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
if (found) {
+ if (supportComposedIcons && IconPackHelper.shouldComposeIcon(mComposedIconInfo)
+ && info != null && info.themedIcon == 0) {
+ Drawable dr = loadDrawable(outValue, id, null);
+ IconCustomizer.getValue(this, id, outValue, dr);
+ }
return;
}
throw new NotFoundException("Resource ID #0x"
@@ -1367,8 +1448,45 @@ public class Resources {
*/
public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
boolean resolveRefs) throws NotFoundException {
+ getValueForDensity(id, density, outValue, resolveRefs, true);
+ }
+
+ /** @hide */
+ public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
+ boolean resolveRefs, boolean supportComposedIcons) throws NotFoundException {
+ //Check if an icon was themed
+ PackageItemInfo info = mIcons != null ? mIcons.get(id) : null;
+ if (info != null && info.themedIcon != 0) {
+ id = info.themedIcon;
+ }
+
boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
if (found) {
+ if (supportComposedIcons && IconPackHelper.shouldComposeIcon(mComposedIconInfo) &&
+ info != null && info.themedIcon == 0) {
+ int tmpDensity = outValue.density;
+ /*
+ * Pretend the requested density is actually the display density. If
+ * the drawable returned is not the requested density, then force it
+ * to be scaled later by dividing its density by the ratio of
+ * requested density to actual device density. Drawables that have
+ * undefined density or no density don't need to be handled here.
+ */
+ if (outValue.density > 0 && outValue.density != TypedValue.DENSITY_NONE) {
+ if (outValue.density == density) {
+ outValue.density = mMetrics.densityDpi;
+ } else {
+ outValue.density = (outValue.density * mMetrics.densityDpi) / density;
+ }
+ }
+ Drawable dr = loadDrawable(outValue, id, null);
+
+ // Return to original density. If we do not do this then
+ // the caller will get the wrong density for the given id and perform
+ // more of its own scaling in loadDrawable
+ outValue.density = tmpDensity;
+ IconCustomizer.getValue(this, id, outValue, dr);
+ }
return;
}
throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
@@ -1438,10 +1556,12 @@ public class Resources {
* if not already defined in the theme.
*/
public void applyStyle(int resId, boolean force) {
- AssetManager.applyThemeStyle(mTheme, resId, force);
+ synchronized (mKey) {
+ AssetManager.applyThemeStyle(mTheme, resId, force);
- mThemeResId = resId;
- mKey.append(resId, force);
+ mThemeResId = resId;
+ mKey.append(resId, force);
+ }
}
/**
@@ -1454,10 +1574,14 @@ public class Resources {
* @param other The existing Theme to copy from.
*/
public void setTo(Theme other) {
- AssetManager.copyTheme(mTheme, other.mTheme);
+ synchronized (mKey) {
+ synchronized (other.mKey) {
+ AssetManager.copyTheme(mTheme, other.mTheme);
- mThemeResId = other.mThemeResId;
- mKey.setTo(other.getKey());
+ mThemeResId = other.mThemeResId;
+ mKey.setTo(other.getKey());
+ }
+ }
}
/**
@@ -1480,11 +1604,13 @@ public class Resources {
* @see #obtainStyledAttributes(AttributeSet, int[], int, int)
*/
public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
- final int len = attrs.length;
- final TypedArray array = TypedArray.obtain(Resources.this, len);
- array.mTheme = this;
- AssetManager.applyStyle(mTheme, 0, 0, 0, attrs, array.mData, array.mIndices);
- return array;
+ synchronized (mKey) {
+ final int len = attrs.length;
+ final TypedArray array = TypedArray.obtain(Resources.this, len);
+ array.mTheme = this;
+ AssetManager.applyStyle(mTheme, 0, 0, 0, attrs, array.mData, array.mIndices);
+ return array;
+ }
}
/**
@@ -1494,7 +1620,7 @@ public class Resources {
* <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
* with the array.
*
- * @param resid The desired style resource.
+ * @param resId The desired style resource.
* @param attrs The desired attributes in the style.
*
* @throws NotFoundException Throws NotFoundException if the given ID does not exist.
@@ -1507,39 +1633,15 @@ public class Resources {
* @see #obtainStyledAttributes(int[])
* @see #obtainStyledAttributes(AttributeSet, int[], int, int)
*/
- public TypedArray obtainStyledAttributes(@StyleRes int resid, @StyleableRes int[] attrs)
+ public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs)
throws NotFoundException {
- final int len = attrs.length;
- final TypedArray array = TypedArray.obtain(Resources.this, len);
- array.mTheme = this;
- if (false) {
- int[] data = array.mData;
-
- System.out.println("**********************************************************");
- System.out.println("**********************************************************");
- System.out.println("**********************************************************");
- System.out.println("Attributes:");
- String s = " Attrs:";
- int i;
- for (i=0; i<attrs.length; i++) {
- s = s + " 0x" + Integer.toHexString(attrs[i]);
- }
- System.out.println(s);
- s = " Found:";
- TypedValue value = new TypedValue();
- for (i=0; i<attrs.length; i++) {
- int d = i*AssetManager.STYLE_NUM_ENTRIES;
- value.type = data[d+AssetManager.STYLE_TYPE];
- value.data = data[d+AssetManager.STYLE_DATA];
- value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE];
- value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID];
- s = s + " 0x" + Integer.toHexString(attrs[i])
- + "=" + value;
- }
- System.out.println(s);
+ synchronized (mKey) {
+ final int len = attrs.length;
+ final TypedArray array = TypedArray.obtain(Resources.this, len);
+ array.mTheme = this;
+ AssetManager.applyStyle(mTheme, 0, resId, 0, attrs, array.mData, array.mIndices);
+ return array;
}
- AssetManager.applyStyle(mTheme, 0, resid, 0, attrs, array.mData, array.mIndices);
- return array;
}
/**
@@ -1592,50 +1694,23 @@ public class Resources {
*/
public TypedArray obtainStyledAttributes(AttributeSet set,
@StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
- final int len = attrs.length;
- final TypedArray array = TypedArray.obtain(Resources.this, len);
-
- // XXX note that for now we only work with compiled XML files.
- // To support generic XML files we will need to manually parse
- // out the attributes from the XML file (applying type information
- // contained in the resources and such).
- final XmlBlock.Parser parser = (XmlBlock.Parser)set;
- AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
- parser != null ? parser.mParseState : 0, attrs, array.mData, array.mIndices);
+ synchronized (mKey) {
+ final int len = attrs.length;
+ final TypedArray array = TypedArray.obtain(Resources.this, len);
- array.mTheme = this;
- array.mXml = parser;
+ // XXX note that for now we only work with compiled XML files.
+ // To support generic XML files we will need to manually parse
+ // out the attributes from the XML file (applying type information
+ // contained in the resources and such).
+ final XmlBlock.Parser parser = (XmlBlock.Parser) set;
+ AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
+ parser != null ? parser.mParseState : 0,
+ attrs, array.mData, array.mIndices);
+ array.mTheme = this;
+ array.mXml = parser;
- if (false) {
- int[] data = array.mData;
-
- System.out.println("Attributes:");
- String s = " Attrs:";
- int i;
- for (i=0; i<set.getAttributeCount(); i++) {
- s = s + " " + set.getAttributeName(i);
- int id = set.getAttributeNameResource(i);
- if (id != 0) {
- s = s + "(0x" + Integer.toHexString(id) + ")";
- }
- s = s + "=" + set.getAttributeValue(i);
- }
- System.out.println(s);
- s = " Found:";
- TypedValue value = new TypedValue();
- for (i=0; i<attrs.length; i++) {
- int d = i*AssetManager.STYLE_NUM_ENTRIES;
- value.type = data[d+AssetManager.STYLE_TYPE];
- value.data = data[d+AssetManager.STYLE_DATA];
- value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE];
- value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID];
- s = s + " 0x" + Integer.toHexString(attrs[i])
- + "=" + value;
- }
- System.out.println(s);
+ return array;
}
-
- return array;
}
/**
@@ -1654,18 +1729,20 @@ public class Resources {
*/
@NonNull
public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) {
- final int len = attrs.length;
- if (values == null || len != values.length) {
- throw new IllegalArgumentException(
- "Base attribute values must the same length as attrs");
- }
+ synchronized (mKey) {
+ final int len = attrs.length;
+ if (values == null || len != values.length) {
+ throw new IllegalArgumentException(
+ "Base attribute values must the same length as attrs");
+ }
- final TypedArray array = TypedArray.obtain(Resources.this, len);
- AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
- array.mTheme = this;
- array.mXml = null;
+ final TypedArray array = TypedArray.obtain(Resources.this, len);
+ AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
+ array.mTheme = this;
+ array.mXml = null;
- return array;
+ return array;
+ }
}
/**
@@ -1686,14 +1763,9 @@ public class Resources {
* <var>outValue</var> is valid, else false.
*/
public boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
- boolean got = mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
- if (false) {
- System.out.println(
- "resolveAttribute #" + Integer.toHexString(resid)
- + " got=" + got + ", type=0x" + Integer.toHexString(outValue.type)
- + ", data=0x" + Integer.toHexString(outValue.data));
+ synchronized (mKey) {
+ return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
}
- return got;
}
/**
@@ -1739,8 +1811,11 @@ public class Resources {
* @see ActivityInfo
*/
public int getChangingConfigurations() {
- final int nativeChangingConfig = AssetManager.getThemeChangingConfigurations(mTheme);
- return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
+ synchronized (mKey) {
+ final int nativeChangingConfig =
+ AssetManager.getThemeChangingConfigurations(mTheme);
+ return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
+ }
}
/**
@@ -1751,7 +1826,9 @@ public class Resources {
* @param prefix Text to prefix each line printed.
*/
public void dump(int priority, String tag, String prefix) {
- AssetManager.dumpTheme(mTheme, priority, tag, prefix);
+ synchronized (mKey) {
+ AssetManager.dumpTheme(mTheme, priority, tag, prefix);
+ }
}
@Override
@@ -1801,19 +1878,21 @@ public class Resources {
*/
@ViewDebug.ExportedProperty(category = "theme", hasAdjacentMapping = true)
public String[] getTheme() {
- final int N = mKey.mCount;
- final String[] themes = new String[N * 2];
- for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
- final int resId = mKey.mResId[j];
- final boolean forced = mKey.mForce[j];
- try {
- themes[i] = getResourceName(resId);
- } catch (NotFoundException e) {
- themes[i] = Integer.toHexString(i);
+ synchronized (mKey) {
+ final int N = mKey.mCount;
+ final String[] themes = new String[N * 2];
+ for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
+ final int resId = mKey.mResId[j];
+ final boolean forced = mKey.mForce[j];
+ try {
+ themes[i] = getResourceName(resId);
+ } catch (NotFoundException e) {
+ themes[i] = Integer.toHexString(i);
+ }
+ themes[i + 1] = forced ? "forced" : "not forced";
}
- themes[i + 1] = forced ? "forced" : "not forced";
+ return themes;
}
- return themes;
}
/** @hide */
@@ -1834,13 +1913,15 @@ public class Resources {
* @hide
*/
public void rebase() {
- AssetManager.clearTheme(mTheme);
-
- // Reapply the same styles in the same order.
- for (int i = 0; i < mKey.mCount; i++) {
- final int resId = mKey.mResId[i];
- final boolean force = mKey.mForce[i];
- AssetManager.applyThemeStyle(mTheme, resId, force);
+ synchronized (mKey) {
+ AssetManager.clearTheme(mTheme);
+
+ // Reapply the same styles in the same order.
+ for (int i = 0; i < mKey.mCount; i++) {
+ final int resId = mKey.mResId[i];
+ final boolean force = mKey.mForce[i];
+ AssetManager.applyThemeStyle(mTheme, resId, force);
+ }
}
}
}
@@ -2005,8 +2086,13 @@ public class Resources {
mConfiguration.setLayoutDirection(mConfiguration.locale);
}
if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
- mMetrics.densityDpi = mConfiguration.densityDpi;
- mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ if (DisplayMetrics.DENSITY_DEVICE_DEFAULT == mCompatibilityInfo.applicationDensity
+ && (config != null
+ && config.densityDpi == DisplayMetrics.DENSITY_DEVICE_DEFAULT)) {
+ mMetrics.setDensity(DisplayMetrics.DENSITY_PREFERRED);
+ } else {
+ mMetrics.setDensity(mConfiguration.densityDpi);
+ }
}
mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
@@ -2083,7 +2169,15 @@ public class Resources {
mTmpConfig.setLayoutDirection(mTmpConfig.locale);
}
configChanges = mConfiguration.updateFrom(mTmpConfig);
- configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
+
+ /* This is ugly, but modifying the activityInfoConfigToNative
+ * adapter would be messier */
+ if ((configChanges & ActivityInfo.CONFIG_THEME_RESOURCE) != 0) {
+ configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
+ configChanges |= ActivityInfo.CONFIG_THEME_RESOURCE;
+ } else {
+ configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
+ }
}
return configChanges;
}
@@ -2428,7 +2522,7 @@ public class Resources {
}
sPreloaded = true;
mPreloading = true;
- sPreloadedDensity = DisplayMetrics.DENSITY_DEVICE;
+ sPreloadedDensity = DisplayMetrics.DENSITY_PREFERRED;
mConfiguration.densityDpi = sPreloadedDensity;
updateConfiguration(null, null);
}
@@ -2526,9 +2620,10 @@ public class Resources {
// attributes.
final ConstantState cs;
if (isColorDrawable) {
- cs = sPreloadedColorDrawables.get(key);
+ cs = mAssets.hasThemedAssets() ? null : sPreloadedColorDrawables.get(key);
} else {
- cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
+ cs = mAssets.hasThemedAssets() ? null :
+ sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
}
Drawable dr;
@@ -2666,7 +2761,7 @@ public class Resources {
if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
&& value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
final android.content.res.ConstantState<ColorStateList> factory =
- sPreloadedColorStateLists.get(key);
+ mAssets.hasThemedAssets() ? null : sPreloadedColorStateLists.get(key);
if (factory != null) {
return factory.newInstance();
}
@@ -2690,7 +2785,7 @@ public class Resources {
}
final android.content.res.ConstantState<ColorStateList> factory =
- sPreloadedColorStateLists.get(key);
+ mAssets.hasThemedAssets() ? null : sPreloadedColorStateLists.get(key);
if (factory != null) {
csl = factory.newInstance(this, theme);
}
@@ -2845,6 +2940,28 @@ public class Resources {
return theme.obtainStyledAttributes(set, attrs, 0, 0);
}
+ /** @hide */
+ public void setIconResources(SparseArray<PackageItemInfo> icons) {
+ mIcons = icons;
+ }
+
+ /** @hide */
+ public void setComposedIconInfo(ComposedIconInfo iconInfo) {
+ mComposedIconInfo = iconInfo;
+ }
+
+ /** @hide */
+ public ComposedIconInfo getComposedIconInfo() {
+ return mComposedIconInfo;
+ }
+
+ /** @hide */
+ public final void updateStringCache() {
+ synchronized (mAccessLock) {
+ mAssets.recreateStringBlocks();
+ }
+ }
+
private Resources() {
mAssets = AssetManager.getSystem();
// NOTE: Intentionally leaving this uninitialized (all values set
diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java
index 2620571..6cbf1d7 100644
--- a/core/java/android/content/res/ResourcesKey.java
+++ b/core/java/android/content/res/ResourcesKey.java
@@ -24,25 +24,31 @@ import java.util.Objects;
public final class ResourcesKey {
private final String mResDir;
private final float mScale;
+ private final boolean mIsThemeable;
private final int mHash;
+ private final ThemeConfig mThemeConfig;
public final int mDisplayId;
@NonNull
public final Configuration mOverrideConfiguration;
public ResourcesKey(String resDir, int displayId, Configuration overrideConfiguration,
- float scale) {
+ float scale, boolean isThemeable, ThemeConfig themeConfig) {
mResDir = resDir;
mDisplayId = displayId;
mOverrideConfiguration = overrideConfiguration != null
? overrideConfiguration : Configuration.EMPTY;
mScale = scale;
+ mIsThemeable = isThemeable;
+ mThemeConfig = themeConfig;
int hash = 17;
hash = 31 * hash + (mResDir == null ? 0 : mResDir.hashCode());
hash = 31 * hash + mDisplayId;
hash = 31 * hash + mOverrideConfiguration.hashCode();
hash = 31 * hash + Float.floatToIntBits(mScale);
+ hash = 31 * hash + (mIsThemeable ? 1 : 0);
+ hash = 31 * hash + (themeConfig != null ? themeConfig.hashCode() : 0);
mHash = hash;
}
@@ -74,6 +80,17 @@ public final class ResourcesKey {
if (mScale != peer.mScale) {
return false;
}
+ if (mIsThemeable != peer.mIsThemeable) {
+ return false;
+ }
+ if (mThemeConfig != peer.mThemeConfig) {
+ if (mThemeConfig == null || peer.mThemeConfig == null) {
+ return false;
+ }
+ if (!mThemeConfig.equals(peer.mThemeConfig)) {
+ return false;
+ }
+ }
return true;
}
diff --git a/core/java/android/content/res/ThemeConfig.java b/core/java/android/content/res/ThemeConfig.java
new file mode 100644
index 0000000..f304801
--- /dev/null
+++ b/core/java/android/content/res/ThemeConfig.java
@@ -0,0 +1,579 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod Project
+ * Portions copyright (C) 2014, T-Mobile USA, Inc.
+ *
+ * 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.content.res;
+
+import android.content.ContentResolver;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.JsonReader;
+import android.util.JsonToken;
+import android.util.JsonWriter;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * The Theme Configuration allows lookup of a theme element (fonts, icon, overlay) for a given
+ * application. If there isn't a particular theme designated to an app, it will fallback on the
+ * default theme. If there isn't a default theme then it will simply fallback to holo.
+ *
+ * @hide
+ */
+public class ThemeConfig implements Cloneable, Parcelable, Comparable<ThemeConfig> {
+ public static final String TAG = ThemeConfig.class.getCanonicalName();
+ public static final String SYSTEM_DEFAULT = "system";
+
+ /**
+ * Special package name for theming the navbar separate from the rest of SystemUI
+ */
+ public static final String SYSTEMUI_NAVBAR_PKG = "com.android.systemui.navbar";
+ public static final String SYSTEMUI_STATUS_BAR_PKG = "com.android.systemui";
+
+ // Key for any app which does not have a specific theme applied
+ private static final String KEY_DEFAULT_PKG = "default";
+ private static final SystemConfig mSystemConfig = new SystemConfig();
+ private static final SystemAppTheme mSystemAppTheme = new SystemAppTheme();
+
+ // Maps pkgname to theme (ex com.angry.birds -> red theme)
+ protected final Map<String, AppTheme> mThemes = new ArrayMap<>();
+
+ public ThemeConfig(Map<String, AppTheme> appThemes) {
+ mThemes.putAll(appThemes);
+ }
+
+ public String getOverlayPkgName() {
+ AppTheme theme = getDefaultTheme();
+ return theme.mOverlayPkgName;
+ }
+
+ public String getOverlayForStatusBar() {
+ return getOverlayPkgNameForApp(SYSTEMUI_STATUS_BAR_PKG);
+ }
+
+ public String getOverlayForNavBar() {
+ return getOverlayPkgNameForApp(SYSTEMUI_NAVBAR_PKG);
+ }
+
+ public String getOverlayPkgNameForApp(String appPkgName) {
+ AppTheme theme = getThemeFor(appPkgName);
+ return theme.mOverlayPkgName;
+ }
+
+ public String getIconPackPkgName() {
+ AppTheme theme = getDefaultTheme();
+ return theme.mIconPkgName;
+ }
+
+ public String getIconPackPkgNameForApp(String appPkgName) {
+ AppTheme theme = getThemeFor(appPkgName);
+ return theme.mIconPkgName;
+ }
+
+ public String getFontPkgName() {
+ AppTheme defaultTheme = getDefaultTheme();
+ return defaultTheme.mFontPkgName;
+ }
+
+ public String getFontPkgNameForApp(String appPkgName) {
+ AppTheme theme = getThemeFor(appPkgName);
+ return theme.mFontPkgName;
+ }
+
+ public Map<String, AppTheme> getAppThemes() {
+ return Collections.unmodifiableMap(mThemes);
+ }
+
+ private AppTheme getThemeFor(String pkgName) {
+ AppTheme theme = mThemes.get(pkgName);
+ if (theme == null) theme = getDefaultTheme();
+ return theme;
+ }
+
+ private AppTheme getDefaultTheme() {
+ AppTheme theme = mThemes.get(KEY_DEFAULT_PKG);
+ if (theme == null) theme = mSystemAppTheme;
+ return theme;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof ThemeConfig) {
+ ThemeConfig o = (ThemeConfig) object;
+
+ Map<String, AppTheme> currThemes = (mThemes == null) ?
+ new ArrayMap<String, AppTheme>() : mThemes;
+ Map<String, AppTheme> newThemes = (o.mThemes == null) ?
+ new ArrayMap<String, AppTheme>() : o.mThemes;
+
+ return currThemes.equals(newThemes);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+ if (mThemes != null) {
+ result.append("themes:");
+ result.append(mThemes);
+ }
+ return result.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 17;
+ hash = 31 * hash + mThemes.hashCode();
+ return hash;
+ }
+
+ public String toJson() {
+ return JsonSerializer.toJson(this);
+ }
+
+ public static ThemeConfig fromJson(String json) {
+ return JsonSerializer.fromJson(json);
+ }
+
+ /**
+ * Represents the theme that the device booted into. This is used to
+ * simulate a "default" configuration based on the user's last known
+ * preference until the theme is switched at runtime.
+ */
+ public static ThemeConfig getBootTheme(ContentResolver resolver) {
+ return getBootThemeForUser(resolver, UserHandle.USER_OWNER);
+ }
+
+ public static ThemeConfig getBootThemeForUser(ContentResolver resolver, int userHandle) {
+ ThemeConfig bootTheme = mSystemConfig;
+ try {
+ String json = Settings.Secure.getStringForUser(resolver,
+ Configuration.THEME_PKG_CONFIGURATION_PERSISTENCE_PROPERTY, userHandle);
+ bootTheme = ThemeConfig.fromJson(json);
+
+ // Handle upgrade Case: Previously the theme configuration was in separate fields
+ if (bootTheme == null) {
+ String overlayPkgName = Settings.Secure.getStringForUser(resolver,
+ Configuration.THEME_PACKAGE_NAME_PERSISTENCE_PROPERTY, userHandle);
+ String iconPackPkgName = Settings.Secure.getStringForUser(resolver,
+ Configuration.THEME_ICONPACK_PACKAGE_NAME_PERSISTENCE_PROPERTY, userHandle);
+ String fontPkgName = Settings.Secure.getStringForUser(resolver,
+ Configuration.THEME_FONT_PACKAGE_NAME_PERSISTENCE_PROPERTY, userHandle);
+
+ Builder builder = new Builder();
+ builder.defaultOverlay(overlayPkgName);
+ builder.defaultIcon(iconPackPkgName);
+ builder.defaultFont(fontPkgName);
+ bootTheme = builder.build();
+ }
+ } catch (SecurityException e) {
+ Log.w(TAG, "Could not get boot theme");
+ }
+ return bootTheme;
+ }
+
+ /**
+ * Represents the system framework theme, perceived by the system as there
+ * being no theme applied.
+ */
+ public static ThemeConfig getSystemTheme() {
+ return mSystemConfig;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ String json = JsonSerializer.toJson(this);
+ dest.writeString(json);
+ }
+
+ public static final Parcelable.Creator<ThemeConfig> CREATOR =
+ new Parcelable.Creator<ThemeConfig>() {
+ public ThemeConfig createFromParcel(Parcel source) {
+ String json = source.readString();
+ ThemeConfig themeConfig = JsonSerializer.fromJson(json);
+ return themeConfig;
+ }
+
+ public ThemeConfig[] newArray(int size) {
+ return new ThemeConfig[size];
+ }
+ };
+
+ @Override
+ public int compareTo(ThemeConfig o) {
+ if (o == null) return -1;
+ int n = 0;
+ n = mThemes.equals(o.mThemes) ? 0 : 1;
+ return n;
+ }
+
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ Log.d(TAG, "clone not supported", e);
+ return null;
+ }
+ }
+
+ public static class AppTheme implements Cloneable, Comparable<AppTheme> {
+ // If any field is modified or added here be sure to change the serializer accordingly
+ String mOverlayPkgName;
+ String mIconPkgName;
+ String mFontPkgName;
+
+ public AppTheme(String overlayPkgName, String iconPkgName, String fontPkgName) {
+ mOverlayPkgName = overlayPkgName;
+ mIconPkgName = iconPkgName;
+ mFontPkgName = fontPkgName;
+ }
+
+ public String getIconPackPkgName() {
+ return mIconPkgName;
+ }
+
+ public String getOverlayPkgName() {
+ return mOverlayPkgName;
+ }
+
+ public String getFontPackPkgName() {
+ return mFontPkgName;
+ }
+
+ @Override
+ public synchronized int hashCode() {
+ int hash = 17;
+ hash = 31 * hash + (mOverlayPkgName == null ? 0 : mOverlayPkgName.hashCode());
+ hash = 31 * hash + (mIconPkgName == null ? 0 : mIconPkgName.hashCode());
+ hash = 31 * hash + (mFontPkgName == null ? 0 : mFontPkgName.hashCode());
+ return hash;
+ }
+
+ @Override
+ public int compareTo(AppTheme o) {
+ if (o == null) return -1;
+ int n = 0;
+ n = mIconPkgName.compareTo(o.mIconPkgName);
+ if (n != 0) return n;
+ n = mFontPkgName.compareTo(o.mFontPkgName);
+ if (n != 0) return n;
+ n = mOverlayPkgName.equals(o.mOverlayPkgName) ? 0 : 1;
+ return n;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof AppTheme) {
+ AppTheme o = (AppTheme) object;
+ String currentOverlayPkgName = (mOverlayPkgName == null)? "" : mOverlayPkgName;
+ String newOverlayPkgName = (o.mOverlayPkgName == null)? "" : o.mOverlayPkgName;
+ String currentIconPkgName = (mIconPkgName == null)? "" : mIconPkgName;
+ String newIconPkgName = (o.mIconPkgName == null)? "" : o.mIconPkgName;
+ String currentFontPkgName = (mFontPkgName == null)? "" : mFontPkgName;
+ String newFontPkgName = (o.mFontPkgName == null)? "" : o.mFontPkgName;
+
+
+ return (currentIconPkgName.equals(newIconPkgName) &&
+ currentFontPkgName.equals(newFontPkgName) &&
+ currentOverlayPkgName.equals(newOverlayPkgName));
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+ if (mOverlayPkgName != null) {
+ result.append("overlay:");
+ result.append(mOverlayPkgName);
+ }
+
+ if (!TextUtils.isEmpty(mIconPkgName)) {
+ result.append(", iconPack:");
+ result.append(mIconPkgName);
+ }
+
+ if (!TextUtils.isEmpty(mFontPkgName)) {
+ result.append(", fontPkg:");
+ result.append(mFontPkgName);
+ }
+ return result.toString();
+ }
+ }
+
+
+ public static class Builder {
+ private Map<String, String> mOverlays = new ArrayMap<>();
+ private Map<String, String> mIcons = new ArrayMap<>();
+ private Map<String, String> mFonts = new ArrayMap<>();
+
+ public Builder() {}
+
+ public Builder(ThemeConfig theme) {
+ for(Map.Entry<String, AppTheme> entry : theme.mThemes.entrySet()) {
+ String key = entry.getKey();
+ AppTheme appTheme = entry.getValue();
+ mFonts.put(key, appTheme.getFontPackPkgName());
+ mIcons.put(key, appTheme.getIconPackPkgName());
+ mOverlays.put(key, appTheme.getOverlayPkgName());
+ }
+ }
+
+ /**
+ * For uniquely theming a specific app. ex. "Dialer gets red theme,
+ * Calculator gets blue theme"
+ */
+ public Builder defaultOverlay(String themePkgName) {
+ if (themePkgName != null) {
+ mOverlays.put(KEY_DEFAULT_PKG, themePkgName);
+ } else {
+ mOverlays.remove(KEY_DEFAULT_PKG);
+ }
+ return this;
+ }
+
+ public Builder defaultFont(String themePkgName) {
+ if (themePkgName != null) {
+ mFonts.put(KEY_DEFAULT_PKG, themePkgName);
+ } else {
+ mFonts.remove(KEY_DEFAULT_PKG);
+ }
+ return this;
+ }
+
+ public Builder defaultIcon(String themePkgName) {
+ if (themePkgName != null) {
+ mIcons.put(KEY_DEFAULT_PKG, themePkgName);
+ } else {
+ mIcons.remove(KEY_DEFAULT_PKG);
+ }
+ return this;
+ }
+
+ public Builder icon(String appPkgName, String themePkgName) {
+ if (themePkgName != null) {
+ mIcons.put(appPkgName, themePkgName);
+ } else {
+ mIcons.remove(appPkgName);
+ }
+ return this;
+ }
+
+ public Builder overlay(String appPkgName, String themePkgName) {
+ if (themePkgName != null) {
+ mOverlays.put(appPkgName, themePkgName);
+ } else {
+ mOverlays.remove(appPkgName);
+ }
+ return this;
+ }
+
+ public Builder font(String appPkgName, String themePkgName) {
+ if (themePkgName != null) {
+ mFonts.put(appPkgName, themePkgName);
+ } else {
+ mFonts.remove(appPkgName);
+ }
+ return this;
+ }
+
+ public ThemeConfig build() {
+ ArraySet<String> appPkgSet = new ArraySet<>();
+ appPkgSet.addAll(mOverlays.keySet());
+ appPkgSet.addAll(mIcons.keySet());
+ appPkgSet.addAll(mFonts.keySet());
+
+ Map<String, AppTheme> appThemes = new ArrayMap<>();
+ for(String appPkgName : appPkgSet) {
+ String icon = mIcons.get(appPkgName);
+ String overlay = mOverlays.get(appPkgName);
+ String font = mFonts.get(appPkgName);
+
+ // Remove app theme if all items are null
+ if (overlay == null && icon == null && font == null) {
+ if (appThemes.containsKey(appPkgName)) {
+ appThemes.remove(appPkgName);
+ }
+ } else {
+ AppTheme appTheme = new AppTheme(overlay, icon, font);
+ appThemes.put(appPkgName, appTheme);
+ }
+ }
+ ThemeConfig themeConfig = new ThemeConfig(appThemes);
+ return themeConfig;
+ }
+ }
+
+
+ public static class JsonSerializer {
+ private static final String NAME_OVERLAY_PKG = "mOverlayPkgName";
+ private static final String NAME_ICON_PKG = "mIconPkgName";
+ private static final String NAME_FONT_PKG = "mFontPkgName";
+
+ public static String toJson(ThemeConfig theme) {
+ String json = null;
+ Writer writer = null;
+ JsonWriter jsonWriter = null;
+ try {
+ writer = new StringWriter();
+ jsonWriter = new JsonWriter(writer);
+ writeTheme(jsonWriter, theme);
+ json = writer.toString();
+ } catch(IOException e) {
+ Log.e(TAG, "Could not write theme mapping", e);
+ } finally {
+ closeQuietly(writer);
+ closeQuietly(jsonWriter);
+ }
+ return json;
+ }
+
+ private static void writeTheme(JsonWriter writer, ThemeConfig theme)
+ throws IOException {
+ writer.beginObject();
+ for(Map.Entry<String, AppTheme> entry : theme.mThemes.entrySet()) {
+ String appPkgName = entry.getKey();
+ AppTheme appTheme = entry.getValue();
+ writer.name(appPkgName);
+ writeAppTheme(writer, appTheme);
+ }
+ writer.endObject();
+ }
+
+ private static void writeAppTheme(JsonWriter writer, AppTheme appTheme) throws IOException {
+ writer.beginObject();
+ writer.name(NAME_OVERLAY_PKG).value(appTheme.mOverlayPkgName);
+ writer.name(NAME_ICON_PKG).value(appTheme.mIconPkgName);
+ writer.name(NAME_FONT_PKG).value(appTheme.mFontPkgName);
+ writer.endObject();
+ }
+
+ public static ThemeConfig fromJson(String json) {
+ if (json == null) return null;
+ Map<String, AppTheme> map = new ArrayMap<>();
+ StringReader reader = null;
+ JsonReader jsonReader = null;
+ try {
+ reader = new StringReader(json);
+ jsonReader = new JsonReader(reader);
+ jsonReader.beginObject();
+ while (jsonReader.hasNext()) {
+ String appPkgName = jsonReader.nextName();
+ AppTheme appTheme = readAppTheme(jsonReader);
+ map.put(appPkgName, appTheme);
+ }
+ jsonReader.endObject();
+ } catch(Exception e) {
+ Log.e(TAG, "Could not parse ThemeConfig from: " + json, e);
+ } finally {
+ closeQuietly(reader);
+ closeQuietly(jsonReader);
+ }
+ return new ThemeConfig(map);
+ }
+
+ private static AppTheme readAppTheme(JsonReader reader) throws IOException {
+ String overlay = null;
+ String icon = null;
+ String font = null;
+
+ reader.beginObject();
+ while(reader.hasNext()) {
+ String name = reader.nextName();
+ if (NAME_OVERLAY_PKG.equals(name) && reader.peek() != JsonToken.NULL) {
+ overlay = reader.nextString();
+ } else if (NAME_ICON_PKG.equals(name) && reader.peek() != JsonToken.NULL) {
+ icon = reader.nextString();
+ } else if (NAME_FONT_PKG.equals(name) && reader.peek() != JsonToken.NULL) {
+ font = reader.nextString();
+ } else {
+ reader.skipValue();
+ }
+ }
+ reader.endObject();
+
+ return new AppTheme(overlay, icon, font);
+ }
+
+ private static void closeQuietly(Reader reader) {
+ try {
+ if (reader != null) reader.close();
+ } catch(IOException e) {
+ }
+ }
+
+ private static void closeQuietly(JsonReader reader) {
+ try {
+ if (reader != null) reader.close();
+ } catch(IOException e) {
+ }
+ }
+
+ private static void closeQuietly(Writer writer) {
+ try {
+ if (writer != null) writer.close();
+ } catch(IOException e) {
+ }
+ }
+
+ private static void closeQuietly(JsonWriter writer) {
+ try {
+ if (writer != null) writer.close();
+ } catch(IOException e) {
+ }
+ }
+ }
+
+ public static class SystemConfig extends ThemeConfig {
+ public SystemConfig() {
+ super(new ArrayMap<String, AppTheme>());
+ }
+ }
+
+ public static class SystemAppTheme extends AppTheme {
+ public SystemAppTheme() {
+ super(SYSTEM_DEFAULT, SYSTEM_DEFAULT, SYSTEM_DEFAULT);
+ }
+
+ @Override
+ public String toString() {
+ return "No Theme Applied (System)";
+ }
+ }
+}
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 3cda39a..6ab9637 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -387,6 +387,8 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
} finally {
execute(success ? "COMMIT" : "ROLLBACK", null, null);
}
+ } catch (SQLiteDatabaseCorruptException ex) {
+ throw ex;
} catch (RuntimeException ex) {
throw new SQLiteException("Failed to change locale for db '" + mConfiguration.label
+ "' to '" + newLocale + "'.", ex);
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 1fc69c0..dd15d38 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -40,6 +40,7 @@ import android.util.Log;
import android.text.TextUtils;
import android.view.Surface;
import android.view.SurfaceHolder;
+import android.os.SystemProperties;
import java.io.IOException;
import java.lang.ref.WeakReference;
@@ -153,6 +154,10 @@ public class Camera {
private static final int CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x200;
private static final int CAMERA_MSG_PREVIEW_METADATA = 0x400;
private static final int CAMERA_MSG_FOCUS_MOVE = 0x800;
+ /* ### QC ADD-ONS: START */
+ private static final int CAMERA_MSG_STATS_DATA = 0x1000;
+ private static final int CAMERA_MSG_META_DATA = 0x2000;
+ /* ### QC ADD-ONS: END */
private long mNativeContext; // accessed by native methods
private EventHandler mEventHandler;
@@ -180,6 +185,10 @@ public class Camera {
private static final int ENOSYS = -38;
private static final int EUSERS = -87;
private static final int EOPNOTSUPP = -95;
+ /* ### QC ADD-ONS: START */
+ private CameraDataCallback mCameraDataCallback;
+ private CameraMetaDataCallback mCameraMetaDataCallback;
+ /* ### QC ADD-ONS: END */
/**
* Broadcast Action: A new picture is taken by the camera, and the entry of
@@ -266,6 +275,17 @@ public class Camera {
*/
public static final int CAMERA_FACING_FRONT = 1;
+ /* ### QC ADD-ONS: START TBD*/
+ /** @hide
+ * camera is in ZSL mode.
+ */
+ public static final int CAMERA_SUPPORT_MODE_ZSL = 2;
+
+ /** @hide
+ * camera is in non-ZSL mode.
+ */
+ public static final int CAMERA_SUPPORT_MODE_NONZSL = 3;
+ /* ### QC ADD-ONS: END */
/**
* The direction that the camera faces. It should be
* CAMERA_FACING_BACK or CAMERA_FACING_FRONT.
@@ -450,6 +470,10 @@ public class Camera {
mPostviewCallback = null;
mUsingPreviewAllocation = false;
mZoomListener = null;
+ /* ### QC ADD-ONS: START */
+ mCameraDataCallback = null;
+ mCameraMetaDataCallback = null;
+ /* ### QC ADD-ONS: END */
Looper looper;
if ((looper = Looper.myLooper()) != null) {
@@ -460,8 +484,21 @@ public class Camera {
mEventHandler = null;
}
- return native_setup(new WeakReference<Camera>(this), cameraId, halVersion,
- ActivityThread.currentOpPackageName());
+ String packageName = ActivityThread.currentOpPackageName();
+
+ //Force HAL1 if the package name falls in this bucket
+ String packageList = SystemProperties.get("camera.hal1.packagelist", "");
+ if (packageList.length() > 0) {
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(packageList);
+ for (String str : splitter) {
+ if (packageName.equals(str)) {
+ halVersion = CAMERA_HAL_API_VERSION_1_0;
+ break;
+ }
+ }
+ }
+ return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName);
}
private int cameraInitNormal(int cameraId) {
@@ -766,6 +803,7 @@ public class Camera {
* @see android.media.MediaActionSound
*/
public final void setPreviewCallback(PreviewCallback cb) {
+ android.util.SeempLog.record(66);
mPreviewCallback = cb;
mOneShot = false;
mWithBuffer = false;
@@ -792,6 +830,7 @@ public class Camera {
* @see android.media.MediaActionSound
*/
public final void setOneShotPreviewCallback(PreviewCallback cb) {
+ android.util.SeempLog.record(68);
mPreviewCallback = cb;
mOneShot = true;
mWithBuffer = false;
@@ -830,6 +869,7 @@ public class Camera {
* @see android.media.MediaActionSound
*/
public final void setPreviewCallbackWithBuffer(PreviewCallback cb) {
+ android.util.SeempLog.record(67);
mPreviewCallback = cb;
mOneShot = false;
mWithBuffer = true;
@@ -1152,7 +1192,23 @@ public class Camera {
mAutoFocusMoveCallback.onAutoFocusMoving(msg.arg1 == 0 ? false : true, mCamera);
}
return;
+ /* ### QC ADD-ONS: START */
+ case CAMERA_MSG_STATS_DATA:
+ int statsdata[] = new int[257];
+ for(int i =0; i<257; i++ ) {
+ statsdata[i] = byteToInt( (byte[])msg.obj, i*4);
+ }
+ if (mCameraDataCallback != null) {
+ mCameraDataCallback.onCameraData(statsdata, mCamera);
+ }
+ return;
+ case CAMERA_MSG_META_DATA:
+ if (mCameraMetaDataCallback != null) {
+ mCameraMetaDataCallback.onCameraMetaData((byte[])msg.obj, mCamera);
+ }
+ return;
+ /* ### QC ADD-ONS: END */
default:
Log.e(TAG, "Unknown message type " + msg.what);
return;
@@ -1376,6 +1432,7 @@ public class Camera {
*/
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback jpeg) {
+ android.util.SeempLog.record(65);
takePicture(shutter, raw, null, jpeg);
}
private native final void native_takePicture(int msgType);
@@ -1411,6 +1468,7 @@ public class Camera {
*/
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback postview, PictureCallback jpeg) {
+ android.util.SeempLog.record(65);
mShutterCallback = shutter;
mRawImageCallback = raw;
mPostviewCallback = postview;
@@ -1579,6 +1637,20 @@ public class Camera {
private native final boolean _enableShutterSound(boolean enabled);
/**
+ * Send a vendor-specific camera command
+ *
+ * @hide
+ */
+ public final void sendVendorCommand(int cmd, int arg1, int arg2) {
+ if (cmd < 1000) {
+ throw new IllegalArgumentException("Command numbers must be at least 1000");
+ }
+ _sendVendorCommand(cmd, arg1, arg2);
+ }
+
+ private native final void _sendVendorCommand(int cmd, int arg1, int arg2);
+
+ /**
* Callback interface for zoom changes during a smooth zoom operation.
*
* @see #setZoomChangeListener(OnZoomChangeListener)
@@ -1800,6 +1872,23 @@ public class Camera {
* as a set. Either they are all valid, or none of them are.
*/
public Point mouth = null;
+
+ /**
+ * {@hide}
+ */
+ public int smileDegree = 0;
+ /**
+ * {@hide}
+ */
+ public int smileScore = 0;
+ /**
+ * {@hide}
+ */
+ public int blinkDetected = 0;
+ /**
+ * {@hide}
+ */
+ public int faceRecognised = 0;
}
/**
@@ -1892,6 +1981,27 @@ public class Camera {
return p;
}
+ /** @hide
+ * Returns the current cct value of white balance.
+ *
+ * If it's in AWB mode, cct is determined by stats/awb module.
+ *
+ * If it's in Manual WB mode, it actually returns cct value
+ * set by user via {@link #setParameters(Camera.Parameters)}.
+ */
+ public int getWBCurrentCCT() {
+ Parameters p = new Parameters();
+ String s = native_getParameters();
+ p.unflatten(s);
+
+ int cct = 0;
+ if (p.getWBCurrentCCT() != null) {
+ cct = Integer.parseInt(p.getWBCurrentCCT());
+ }
+
+ return cct;
+ }
+
/**
* Returns an empty {@link Parameters} for testing purpose.
*
@@ -1904,6 +2014,166 @@ public class Camera {
return camera.new Parameters();
}
+ /* ### QC ADD-ONS: START */
+ private static int byteToInt(byte[] b, int offset) {
+ int value = 0;
+ for (int i = 0; i < 4; i++) {
+ int shift = (4 - 1 - i) * 8;
+ value += (b[(3-i) + offset] & 0x000000FF) << shift;
+ }
+ return value;
+ }
+ /** @hide
+ * Handles the callback for when Camera Data is available.
+ * data is read from the camera.
+ */
+ public interface CameraDataCallback {
+ /**
+ * Callback for when camera data is available.
+ *
+ * @param data a int array of the camera data
+ * @param camera the Camera service object
+ */
+ void onCameraData(int[] data, Camera camera);
+ };
+
+ /** @hide
+ * Set camera histogram mode and registers a callback function to run.
+ * Only valid after startPreview() has been called.
+ *
+ * @param cb the callback to run
+ */
+ public final void setHistogramMode(CameraDataCallback cb)
+ {
+ mCameraDataCallback = cb;
+ native_setHistogramMode(cb!=null);
+ }
+ private native final void native_setHistogramMode(boolean mode);
+
+ /** @hide
+ * Set camera histogram command to send data.
+ *
+ */
+ public final void sendHistogramData()
+ {
+ native_sendHistogramData();
+ }
+ private native final void native_sendHistogramData();
+
+ /** @hide
+ * Handles the callback for when Camera Meta Data is available.
+ * Meta data is read from the camera.
+ */
+ public interface CameraMetaDataCallback {
+ /**
+ * Callback for when camera meta data is available.
+ *
+ * @param data a byte array of the camera meta data
+ * @param camera the Camera service object
+ */
+ void onCameraMetaData(byte[] data, Camera camera);
+ };
+
+ /** @hide
+ * Set camera meta data and registers a callback function to run.
+ * Only valid after startPreview() has been called.
+ *
+ * @param cb the callback to run
+ */
+ public final void setMetadataCb(CameraMetaDataCallback cb)
+ {
+ mCameraMetaDataCallback = cb;
+ native_setMetadataCb(cb!=null);
+ }
+ private native final void native_setMetadataCb(boolean mode);
+
+ /** @hide
+ * Set camera face detection command to send meta data.
+ */
+ public final void sendMetaData()
+ {
+ native_sendMetaData();
+ }
+ private native final void native_sendMetaData();
+
+ /** @hide
+ * Configure longshot mode. Available only in ZSL.
+ *
+ * @param enable enable/disable this mode
+ */
+ public final void setLongshot(boolean enable)
+ {
+ native_setLongshot(enable);
+ }
+ private native final void native_setLongshot(boolean enable);
+
+ /** @hide
+ * Stop longshot. Available only in ZSL.
+ */
+ public final void stopLongshot()
+ {
+ native_stopLongshot();
+ }
+ private native final void native_stopLongshot();
+
+ /** @hide
+ * Handles the Touch Co-ordinate.
+ */
+ public class Coordinate {
+ /**
+ * Sets the x,y co-ordinates for a touch event
+ *
+ * @param x the x co-ordinate (pixels)
+ * @param y the y co-ordinate (pixels)
+ */
+ public Coordinate(int x, int y) {
+ xCoordinate = x;
+ yCoordinate = y;
+ }
+ /**
+ * Compares {@code obj} to this co-ordinate.
+ *
+ * @param obj the object to compare this co-ordinate with.
+ * @return {@code true} if the xCoordinate and yCoordinate of {@code obj} is the
+ * same as those of this coordinate. {@code false} otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Coordinate)) {
+ return false;
+ }
+ Coordinate c = (Coordinate) obj;
+ return xCoordinate == c.xCoordinate && yCoordinate == c.yCoordinate;
+ }
+
+ /** x co-ordinate for the touch event*/
+ public int xCoordinate;
+
+ /** y co-ordinate for the touch event */
+ public int yCoordinate;
+ };
+
+ /** @hide
+ * Returns the current focus position.
+ *
+ * If it's in AF mode, it's the lens position after af is done.
+ *
+ * If it's in Manual Focus mode, it actually returns the value
+ * set by user via {@link #setParameters(Camera.Parameters)}.
+ */
+ public int getCurrentFocusPosition() {
+ Parameters p = new Parameters();
+ String s = native_getParameters();
+ p.unflatten(s);
+
+ int focus_pos = -1;
+ if (p.getCurrentFocusPosition() != null) {
+ focus_pos = Integer.parseInt(p.getCurrentFocusPosition());
+ }
+ return focus_pos;
+ }
+
+ /* ### QC ADD-ONS: END */
/**
* Returns a copied {@link Parameters}; for shim use only.
*
@@ -2151,6 +2421,10 @@ public class Camera {
public static final String WHITE_BALANCE_CLOUDY_DAYLIGHT = "cloudy-daylight";
public static final String WHITE_BALANCE_TWILIGHT = "twilight";
public static final String WHITE_BALANCE_SHADE = "shade";
+ /** @hide
+ * wb manual cct mode.
+ */
+ public static final String WHITE_BALANCE_MANUAL_CCT = "manual-cct";
// Values for color effect settings.
public static final String EFFECT_NONE = "none";
@@ -2198,6 +2472,11 @@ public class Camera {
*/
public static final String FLASH_MODE_TORCH = "torch";
+ /** @hide
+ * Scene mode is off.
+ */
+ public static final String SCENE_MODE_ASD = "asd";
+
/**
* Scene mode is off.
*/
@@ -2274,6 +2553,14 @@ public class Camera {
* Capture the naturally warm color of scenes lit by candles.
*/
public static final String SCENE_MODE_CANDLELIGHT = "candlelight";
+ /** @hide
+ * SCENE_MODE_BACKLIGHT
+ **/
+ public static final String SCENE_MODE_BACKLIGHT = "backlight";
+ /** @hide
+ * SCENE_MODE_FLOWERS
+ **/
+ public static final String SCENE_MODE_FLOWERS = "flowers";
/**
* Applications are looking for a barcode. Camera driver will be
@@ -2316,6 +2603,13 @@ public class Camera {
*/
public static final String FOCUS_MODE_FIXED = "fixed";
+ /** @hide
+ * Normal focus mode. Applications should call
+ * {@link #autoFocus(AutoFocusCallback)} to start the focus in this
+ * mode.
+ */
+ public static final String FOCUS_MODE_NORMAL = "normal";
+
/**
* Extended depth of field (EDOF). Focusing is done digitally and
* continuously. Applications should not call {@link
@@ -2368,6 +2662,11 @@ public class Camera {
*/
public static final String FOCUS_MODE_CONTINUOUS_PICTURE = "continuous-picture";
+ /** @hide
+ * manual focus mode
+ */
+ public static final String FOCUS_MODE_MANUAL_POSITION = "manual";
+
// Indices for focus distance array.
/**
* The array index of near focus distance for use with
@@ -2404,11 +2703,15 @@ public class Camera {
// Formats for setPreviewFormat and setPictureFormat.
private static final String PIXEL_FORMAT_YUV422SP = "yuv422sp";
private static final String PIXEL_FORMAT_YUV420SP = "yuv420sp";
+ private static final String PIXEL_FORMAT_YUV420SP_ADRENO = "yuv420sp-adreno";
private static final String PIXEL_FORMAT_YUV422I = "yuv422i-yuyv";
private static final String PIXEL_FORMAT_YUV420P = "yuv420p";
private static final String PIXEL_FORMAT_RGB565 = "rgb565";
private static final String PIXEL_FORMAT_JPEG = "jpeg";
private static final String PIXEL_FORMAT_BAYER_RGGB = "bayer-rggb";
+ private static final String PIXEL_FORMAT_RAW = "raw";
+ private static final String PIXEL_FORMAT_YV12 = "yv12";
+ private static final String PIXEL_FORMAT_NV12 = "nv12";
/**
* Order matters: Keys that are {@link #set(String, String) set} later
@@ -3182,8 +3485,8 @@ public class Camera {
}
/**
- * Sets GPS processing method. It will store up to 32 characters
- * in JPEG EXIF header.
+ * Sets GPS processing method. The method will be stored in a UTF-8 string up to 31 bytes
+ * long, in the JPEG EXIF header.
*
* @param processing_method The processing method to get this location.
*/
@@ -3196,8 +3499,11 @@ public class Camera {
* parameters.
*/
public void removeGpsData() {
+ remove(KEY_QC_GPS_LATITUDE_REF);
remove(KEY_GPS_LATITUDE);
+ remove(KEY_QC_GPS_LONGITUDE_REF);
remove(KEY_GPS_LONGITUDE);
+ remove(KEY_QC_GPS_ALTITUDE_REF);
remove(KEY_GPS_ALTITUDE);
remove(KEY_GPS_TIMESTAMP);
remove(KEY_GPS_PROCESSING_METHOD);
@@ -4088,6 +4394,7 @@ public class Camera {
splitter.setString(str);
int index = 0;
for (String s : splitter) {
+ s = s.replaceAll("\\s","");
output[index++] = Integer.parseInt(s);
}
}
@@ -4158,7 +4465,7 @@ public class Camera {
// Example string: "(10000,26623),(10000,30000)". Return null if the
// passing string is null or the size is 0.
private ArrayList<int[]> splitRange(String str) {
- if (str == null || str.charAt(0) != '('
+ if (str == null || str.isEmpty() || str.charAt(0) != '('
|| str.charAt(str.length() - 1) != ')') {
Log.e(TAG, "Invalid range list string=" + str);
return null;
@@ -4183,7 +4490,7 @@ public class Camera {
// Example string: "(-10,-10,0,0,300),(0,0,10,10,700)". Return null if
// the passing string is null or the size is 0 or (0,0,0,0,0).
private ArrayList<Area> splitArea(String str) {
- if (str == null || str.charAt(0) != '('
+ if (str == null || str.isEmpty() || str.charAt(0) != '('
|| str.charAt(str.length() - 1) != ')') {
Log.e(TAG, "Invalid area string=" + str);
return null;
@@ -4220,5 +4527,1231 @@ public class Camera {
if (s1 != null && s1.equals(s2)) return true;
return false;
}
+ /* ### QC ADD-ONS: START */
+
+ /* ### QC ADDED PARAMETER KEYS*/
+ private static final String KEY_QC_HFR_SIZE = "hfr-size";
+ private static final String KEY_QC_PREVIEW_FRAME_RATE_MODE = "preview-frame-rate-mode";
+ private static final String KEY_QC_PREVIEW_FRAME_RATE_AUTO_MODE = "frame-rate-auto";
+ private static final String KEY_QC_PREVIEW_FRAME_RATE_FIXED_MODE = "frame-rate-fixed";
+ private static final String KEY_QC_GPS_LATITUDE_REF = "gps-latitude-ref";
+ private static final String KEY_QC_GPS_LONGITUDE_REF = "gps-longitude-ref";
+ private static final String KEY_QC_GPS_ALTITUDE_REF = "gps-altitude-ref";
+ private static final String KEY_QC_GPS_STATUS = "gps-status";
+ private static final String KEY_QC_EXIF_DATETIME = "exif-datetime";
+ private static final String KEY_QC_TOUCH_AF_AEC = "touch-af-aec";
+ private static final String KEY_QC_TOUCH_INDEX_AEC = "touch-index-aec";
+ private static final String KEY_QC_TOUCH_INDEX_AF = "touch-index-af";
+ private static final String KEY_QC_MANUAL_FOCUS_POSITION = "manual-focus-position";
+ private static final String KEY_QC_MANUAL_FOCUS_POS_TYPE = "manual-focus-pos-type";
+ private static final String KEY_QC_SCENE_DETECT = "scene-detect";
+ private static final String KEY_QC_ISO_MODE = "iso";
+ private static final String KEY_QC_EXPOSURE_TIME = "exposure-time";
+ private static final String KEY_QC_MIN_EXPOSURE_TIME = "min-exposure-time";
+ private static final String KEY_QC_MAX_EXPOSURE_TIME = "max-exposure-time";
+ private static final String KEY_QC_LENSSHADE = "lensshade";
+ private static final String KEY_QC_HISTOGRAM = "histogram";
+ private static final String KEY_QC_SKIN_TONE_ENHANCEMENT = "skinToneEnhancement";
+ private static final String KEY_QC_AUTO_EXPOSURE = "auto-exposure";
+ private static final String KEY_QC_SHARPNESS = "sharpness";
+ private static final String KEY_QC_MAX_SHARPNESS = "max-sharpness";
+ private static final String KEY_QC_CONTRAST = "contrast";
+ private static final String KEY_QC_MAX_CONTRAST = "max-contrast";
+ private static final String KEY_QC_SATURATION = "saturation";
+ private static final String KEY_QC_MAX_SATURATION = "max-saturation";
+ private static final String KEY_QC_DENOISE = "denoise";
+ private static final String KEY_QC_CONTINUOUS_AF = "continuous-af";
+ private static final String KEY_QC_SELECTABLE_ZONE_AF = "selectable-zone-af";
+ private static final String KEY_QC_FACE_DETECTION = "face-detection";
+ private static final String KEY_QC_MEMORY_COLOR_ENHANCEMENT = "mce";
+ private static final String KEY_QC_REDEYE_REDUCTION = "redeye-reduction";
+ private static final String KEY_QC_ZSL = "zsl";
+ private static final String KEY_QC_CAMERA_MODE = "camera-mode";
+ private static final String KEY_QC_VIDEO_HIGH_FRAME_RATE = "video-hfr";
+ private static final String KEY_QC_VIDEO_HDR = "video-hdr";
+ private static final String KEY_QC_POWER_MODE = "power-mode";
+ private static final String KEY_QC_POWER_MODE_SUPPORTED = "power-mode-supported";
+ private static final String KEY_QC_WB_MANUAL_CCT = "wb-manual-cct";
+ private static final String KEY_QC_MIN_WB_CCT = "min-wb-cct";
+ private static final String KEY_QC_MAX_WB_CCT = "max-wb-cct";
+ private static final String KEY_QC_AUTO_HDR_ENABLE = "auto-hdr-enable";
+ private static final String KEY_QC_VIDEO_ROTATION = "video-rotation";
+
+ /** @hide
+ * KEY_QC_AE_BRACKET_HDR
+ **/
+ public static final String KEY_QC_AE_BRACKET_HDR = "ae-bracket-hdr";
+
+ /* ### QC ADDED PARAMETER VALUES*/
+
+ // Values for touch af/aec settings.
+ /** @hide
+ * TOUCH_AF_AEC_OFF
+ **/
+ public static final String TOUCH_AF_AEC_OFF = "touch-off";
+ /** @hide
+ * TOUCH_AF_AEC_ON
+ **/
+ public static final String TOUCH_AF_AEC_ON = "touch-on";
+
+ // Values for auto exposure settings.
+ /** @hide
+ * Auto exposure frame-avg
+ **/
+ public static final String AUTO_EXPOSURE_FRAME_AVG = "frame-average";
+ /** @hide
+ * Auto exposure center weighted
+ **/
+ public static final String AUTO_EXPOSURE_CENTER_WEIGHTED = "center-weighted";
+ /** @hide
+ * Auto exposure spot metering
+ **/
+ public static final String AUTO_EXPOSURE_SPOT_METERING = "spot-metering";
+
+ //Values for ISO settings
+ /** @hide
+ * ISO_AUTO
+ **/
+ public static final String ISO_AUTO = "auto";
+ /** @hide
+ * ISO_HJR
+ **/
+ public static final String ISO_HJR = "ISO_HJR";
+ /** @hide
+ * ISO_100
+ **/
+ public static final String ISO_100 = "ISO100";
+ /** @hide
+ * ISO_200
+ **/
+ public static final String ISO_200 = "ISO200";
+ /** @hide
+ * ISO_400
+ **/
+ public static final String ISO_400 = "ISO400";
+ /** @hide
+ * ISO_800
+ **/
+ public static final String ISO_800 = "ISO800";
+ /** @hide
+ * ISO_1600
+ **/
+ public static final String ISO_1600 = "ISO1600";
+
+ /** @hide
+ * ISO_3200
+ **/
+ public static final String ISO_3200 = "ISO3200";
+
+ //Values for Lens Shading
+ /** @hide
+ * LENSSHADE_ENABLE
+ **/
+ public static final String LENSSHADE_ENABLE = "enable";
+ /** @hide
+ * LENSSHADE_DISABLE
+ **/
+ public static final String LENSSHADE_DISABLE= "disable";
+
+ //Values for Histogram
+ /** @hide
+ * Histogram enable
+ **/
+ public static final String HISTOGRAM_ENABLE = "enable";
+ /** @hide
+ * Histogram disable
+ **/
+ public static final String HISTOGRAM_DISABLE= "disable";
+
+ //Values for Skin Tone Enhancement
+ /** @hide
+ * SKIN_TONE_ENHANCEMENT_ENABLE
+ **/
+ public static final String SKIN_TONE_ENHANCEMENT_ENABLE = "enable";
+ /** @hide
+ * SKIN_TONE_ENHANCEMENT_DISABLE
+ **/
+ public static final String SKIN_TONE_ENHANCEMENT_DISABLE= "disable";
+
+ // Values for MCE settings.
+ /** @hide
+ * MCE_ENaBLE
+ **/
+ public static final String MCE_ENABLE = "enable";
+ /** @hide
+ * MCE_DISABLE
+ **/
+ public static final String MCE_DISABLE = "disable";
+
+ // Values for ZSL settings.
+ /** @hide
+ * ZSL_ON
+ **/
+ public static final String ZSL_ON = "on";
+ /** @hide
+ * ZSL_OFF
+ **/
+ public static final String ZSL_OFF = "off";
+
+ // Values for HDR Bracketing settings.
+
+ /** @hide
+ * AEC bracketing off
+ **/
+ public static final String AE_BRACKET_HDR_OFF = "Off";
+ /** @hide
+ * AEC bracketing hdr
+ **/
+ public static final String AE_BRACKET_HDR = "HDR";
+ /** @hide
+ * AEC bracketing aec-bracket
+ **/
+ public static final String AE_BRACKET = "AE-Bracket";
+
+ // Values for Power mode.
+ /** @hide
+ * LOW_POWER
+ **/
+ public static final String LOW_POWER = "Low_Power";
+ /** @hide
+ * NORMAL_POWER
+ **/
+ public static final String NORMAL_POWER = "Normal_Power";
+
+ // Values for HFR settings.
+ /** @hide
+ * VIDEO_HFR_OFF
+ **/
+ public static final String VIDEO_HFR_OFF = "off";
+ /** @hide
+ * VIDEO_HFR_2X
+ **/
+ public static final String VIDEO_HFR_2X = "60";
+ /** @hide
+ * VIDEO_HFR_3X
+ **/
+ public static final String VIDEO_HFR_3X = "90";
+ /** @hide
+ * VIDEO_HFR_4X
+ **/
+ public static final String VIDEO_HFR_4X = "120";
+
+ // Values for auto scene detection settings.
+ /** @hide
+ * SCENE_DETECT_OFF
+ **/
+ public static final String SCENE_DETECT_OFF = "off";
+ /** @hide
+ * SCENE_DETECT_ON
+ **/
+ public static final String SCENE_DETECT_ON = "on";
+
+ //Values for Continuous AF
+
+ /** @hide
+ * CAF off
+ **/
+ public static final String CONTINUOUS_AF_OFF = "caf-off";
+ /** @hide
+ * CAF on
+ **/
+ public static final String CONTINUOUS_AF_ON = "caf-on";
+ /** @hide
+ * Denoise off
+ **/
+ public static final String DENOISE_OFF = "denoise-off";
+ /** @hide
+ * Denoise on
+ **/
+ public static final String DENOISE_ON = "denoise-on";
+
+ // Values for Redeye Reduction settings.
+ /** @hide
+ * REDEYE_REDUCTION_ENABLE
+ **/
+ public static final String REDEYE_REDUCTION_ENABLE = "enable";
+ /** @hide
+ * REDEYE_REDUCTION_DISABLE
+ **/
+ public static final String REDEYE_REDUCTION_DISABLE = "disable";
+
+ // Values for selectable zone af settings.
+ /** @hide
+ * SELECTABLE_ZONE_AF_AUTO
+ **/
+ public static final String SELECTABLE_ZONE_AF_AUTO = "auto";
+ /** @hide
+ * SELECTABLE_ZONE_AF_SPOTMETERING
+ **/
+ public static final String SELECTABLE_ZONE_AF_SPOTMETERING = "spot-metering";
+ /** @hide
+ * SELECTABLE_ZONE_AF_CENTER_WEIGHTED
+ **/
+ public static final String SELECTABLE_ZONE_AF_CENTER_WEIGHTED = "center-weighted";
+ /** @hide
+ * SELECTABLE_ZONE_AF_FRAME_AVERAGE
+ **/
+ public static final String SELECTABLE_ZONE_AF_FRAME_AVERAGE = "frame-average";
+
+ // Values for Face Detection settings.
+ /** @hide
+ * Face Detection off
+ **/
+ public static final String FACE_DETECTION_OFF = "off";
+ /** @hide
+ * Face Detction on
+ **/
+ public static final String FACE_DETECTION_ON = "on";
+
+ // Values for video rotation settings.
+
+ /** @hide
+ * VIDEO_ROTATION_0
+ **/
+ public static final String VIDEO_ROTATION_0 = "0";
+ /** @hide
+ * VIDEO_ROTATION_90
+ **/
+ public static final String VIDEO_ROTATION_90 = "90";
+ /** @hide
+ * VIDEO_ROTATION_180
+ **/
+ public static final String VIDEO_ROTATION_180 = "180";
+ /** @hide
+ * VIDEO_ROTATION_270
+ **/
+ public static final String VIDEO_ROTATION_270 = "270";
+
+ /* ### QC ADDED PARAMETER APIS*/
+ /** @hide
+ * Gets the supported preview sizes in high frame rate recording mode.
+ *
+ * @return a list of Size object. This method will always return a list
+ * with at least one element.
+ */
+ public List<Size> getSupportedHfrSizes() {
+ String str = get(KEY_QC_HFR_SIZE + SUPPORTED_VALUES_SUFFIX);
+ return splitSize(str);
+ }
+
+ /** @hide
+ * Gets the supported Touch AF/AEC setting.
+ *
+ * @return a List of TOUCH_AF_AEC_XXX string constants. null if TOUCH AF/AEC
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedTouchAfAec() {
+ String str = get(KEY_QC_TOUCH_AF_AEC + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /**
+ * Gets the supported Touch AF/AEC setting.
+ *
+ * @return a List of TOUCH_AF_AEC_XXX string constants. null if TOUCH AF/AEC
+ * setting is not supported.
+ *
+ */
+
+ /** @hide
+ * Gets the supported frame rate modes.
+ *
+ * @return a List of FRAME_RATE_XXX_MODE string constant. null if this
+ * setting is not supported.
+ */
+ public List<String> getSupportedPreviewFrameRateModes() {
+ String str = get(KEY_QC_PREVIEW_FRAME_RATE_MODE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported auto scene detection modes.
+ *
+ * @return a List of SCENE_DETECT_XXX string constant. null if scene detection
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedSceneDetectModes() {
+ String str = get(KEY_QC_SCENE_DETECT + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported ISO values.
+ *
+ * @return a List of FLASH_MODE_XXX string constants. null if flash mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedIsoValues() {
+ String str = get(KEY_QC_ISO_MODE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Lensshade modes.
+ *
+ * @return a List of LENS_MODE_XXX string constants. null if lens mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedLensShadeModes() {
+ String str = get(KEY_QC_LENSSHADE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Histogram modes.
+ *
+ * @return a List of HISTOGRAM_XXX string constants. null if histogram mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedHistogramModes() {
+ String str = get(KEY_QC_HISTOGRAM + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Skin Tone Enhancement modes.
+ *
+ * @return a List of SKIN_TONE_ENHANCEMENT_XXX string constants. null if skin tone enhancement
+ * setting is not supported.
+ */
+ public List<String> getSupportedSkinToneEnhancementModes() {
+ String str = get(KEY_QC_SKIN_TONE_ENHANCEMENT + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported auto exposure setting.
+ *
+ * @return a List of AUTO_EXPOSURE_XXX string constants. null if auto exposure
+ * setting is not supported.
+ */
+ public List<String> getSupportedAutoexposure() {
+ String str = get(KEY_QC_AUTO_EXPOSURE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported MCE modes.
+ *
+ * @return a List of MCE_ENABLE/DISABLE string constants. null if MCE mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedMemColorEnhanceModes() {
+ String str = get(KEY_QC_MEMORY_COLOR_ENHANCEMENT + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported ZSL modes.
+ *
+ * @return a List of ZSL_OFF/OFF string constants. null if ZSL mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedZSLModes() {
+ String str = get(KEY_QC_ZSL + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Video HDR modes.
+ *
+ * @return a List of Video HDR_OFF/OFF string constants. null if
+ * Video HDR mode setting is not supported.
+ */
+ public List<String> getSupportedVideoHDRModes() {
+ String str = get(KEY_QC_VIDEO_HDR + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported HFR modes.
+ *
+ * @return a List of VIDEO_HFR_XXX string constants. null if hfr mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedVideoHighFrameRateModes() {
+ String str = get(KEY_QC_VIDEO_HIGH_FRAME_RATE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Continuous AF modes.
+ *
+ * @return a List of CONTINUOUS_AF_XXX string constant. null if continuous AF
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedContinuousAfModes() {
+ String str = get(KEY_QC_CONTINUOUS_AF + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported DENOISE modes.
+ *
+ * @return a List of DENOISE_XXX string constant. null if DENOISE
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedDenoiseModes() {
+ String str = get(KEY_QC_DENOISE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported selectable zone af setting.
+ *
+ * @return a List of SELECTABLE_ZONE_AF_XXX string constants. null if selectable zone af
+ * setting is not supported.
+ */
+ public List<String> getSupportedSelectableZoneAf() {
+ String str = get(KEY_QC_SELECTABLE_ZONE_AF + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported face detection modes.
+ *
+ * @return a List of FACE_DETECTION_XXX string constant. null if face detection
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedFaceDetectionModes() {
+ String str = get(KEY_QC_FACE_DETECTION + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported redeye reduction modes.
+ *
+ * @return a List of REDEYE_REDUCTION_XXX string constant. null if redeye reduction
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedRedeyeReductionModes() {
+ String str = get(KEY_QC_REDEYE_REDUCTION + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Sets GPS altitude reference. This will be stored in JPEG EXIF header.
+ * @param altRef reference GPS altitude in meters.
+ */
+ public void setGpsAltitudeRef(double altRef) {
+ set(KEY_QC_GPS_ALTITUDE_REF, Double.toString(altRef));
+ }
+
+ /** @hide
+ * Sets GPS Status. This will be stored in JPEG EXIF header.
+ *
+ * @param status GPS status (UTC in seconds since January 1,
+ * 1970).
+ */
+ public void setGpsStatus(double status) {
+ set(KEY_QC_GPS_STATUS, Double.toString(status));
+ }
+
+ /** @hide
+ * Sets the touch co-ordinate for Touch AEC.
+ *
+ * @param x the x co-ordinate of the touch event
+ * @param y the y co-ordinate of the touch event
+ *
+ */
+ public void setTouchIndexAec(int x, int y) {
+ String v = Integer.toString(x) + "x" + Integer.toString(y);
+ set(KEY_QC_TOUCH_INDEX_AEC, v);
+ }
+
+ /** @hide
+ * Returns the touch co-ordinates of the touch event.
+ *
+ * @return a Index object with the x and y co-ordinated
+ * for the touch event
+ *
+ */
+ public Coordinate getTouchIndexAec() {
+ String pair = get(KEY_QC_TOUCH_INDEX_AEC);
+ return strToCoordinate(pair);
+ }
+
+ /** @hide
+ * Sets the touch co-ordinate for Touch AF.
+ *
+ * @param x the x co-ordinate of the touch event
+ * @param y the y co-ordinate of the touch event
+ *
+ */
+ public void setTouchIndexAf(int x, int y) {
+ String v = Integer.toString(x) + "x" + Integer.toString(y);
+ set(KEY_QC_TOUCH_INDEX_AF, v);
+ }
+
+ /** @hide
+ * Returns the touch co-ordinates of the touch event.
+ *
+ * @return a Index object with the x and y co-ordinated
+ * for the touch event
+ *
+ */
+ public Coordinate getTouchIndexAf() {
+ String pair = get(KEY_QC_TOUCH_INDEX_AF);
+ return strToCoordinate(pair);
+ }
+ /** @hide
+ * Set Sharpness Level
+ *
+ * @param sharpness level
+ */
+ public void setSharpness(int sharpness){
+ if((sharpness < 0) || (sharpness > getMaxSharpness()) )
+ throw new IllegalArgumentException(
+ "Invalid Sharpness " + sharpness);
+
+ set(KEY_QC_SHARPNESS, String.valueOf(sharpness));
+ }
+
+ /** @hide
+ * Set Contrast Level
+ *
+ * @param contrast level
+ */
+ public void setContrast(int contrast){
+ if((contrast < 0 ) || (contrast > getMaxContrast()))
+ throw new IllegalArgumentException(
+ "Invalid Contrast " + contrast);
+
+ set(KEY_QC_CONTRAST, String.valueOf(contrast));
+ }
+
+ /** @hide
+ * Set Saturation Level
+ *
+ * @param saturation level
+ */
+ public void setSaturation(int saturation){
+ if((saturation < 0 ) || (saturation > getMaxSaturation()))
+ throw new IllegalArgumentException(
+ "Invalid Saturation " + saturation);
+
+ set(KEY_QC_SATURATION, String.valueOf(saturation));
+ }
+
+ /** @hide
+ * @return true if full size video snapshot is supported.
+ */
+ public boolean isPowerModeSupported() {
+ String str = get(KEY_QC_POWER_MODE_SUPPORTED);
+ return TRUE.equals(str);
+ }
+
+ /** @hide
+ * Get Sharpness level
+ *
+ * @return sharpness level
+ */
+ public int getSharpness(){
+ return getInt(KEY_QC_SHARPNESS);
+ }
+
+ /** @hide
+ * Get Max Sharpness Level
+ *
+ * @return max sharpness level
+ */
+ public int getMaxSharpness(){
+ return getInt(KEY_QC_MAX_SHARPNESS);
+ }
+
+ /** @hide
+ * Get Contrast level
+ *
+ * @return contrast level
+ */
+ public int getContrast(){
+ return getInt(KEY_QC_CONTRAST);
+ }
+
+ /** @hide
+ * Get Max Contrast Level
+ *
+ * @return max contrast level
+ */
+ public int getMaxContrast(){
+ return getInt(KEY_QC_MAX_CONTRAST);
+ }
+
+ /** @hide
+ * Get Saturation level
+ *
+ * @return saturation level
+ */
+ public int getSaturation(){
+ return getInt(KEY_QC_SATURATION);
+ }
+
+ /** @hide
+ * Get Max Saturation Level
+ *
+ * @return max contrast level
+ */
+ public int getMaxSaturation(){
+ return getInt(KEY_QC_MAX_SATURATION);
+ }
+
+ /** @hide
+ * Sets GPS latitude reference coordinate. This will be stored in JPEG EXIF
+ * header.
+ * @param latRef GPS latitude reference coordinate.
+ */
+ public void setGpsLatitudeRef(String latRef) {
+ set(KEY_QC_GPS_LATITUDE_REF, latRef);
+ }
+
+ /** @hide
+ * Sets GPS longitude reference coordinate. This will be stored in JPEG EXIF
+ * header.
+ * @param lonRef GPS longitude reference coordinate.
+ */
+ public void setGpsLongitudeRef(String lonRef) {
+ set(KEY_QC_GPS_LONGITUDE_REF, lonRef);
+ }
+
+ /** @hide
+ * Sets system timestamp. This will be stored in JPEG EXIF header.
+ *
+ * @param dateTime current timestamp (UTC in seconds since January 1,
+ * 1970).
+ */
+ public void setExifDateTime(String dateTime) {
+ set(KEY_QC_EXIF_DATETIME, dateTime);
+ }
+
+ /** @hide
+ * Gets the current Touch AF/AEC setting.
+ *
+ * @return one of TOUCH_AF_AEC_XXX string constant. null if Touch AF/AEC
+ * setting is not supported.
+ *
+ */
+ public String getTouchAfAec() {
+ return get(KEY_QC_TOUCH_AF_AEC);
+ }
+
+ /** @hide
+ * Sets the current TOUCH AF/AEC setting.
+ *
+ * @param value TOUCH_AF_AEC_XXX string constants.
+ *
+ */
+ public void setTouchAfAec(String value) {
+ set(KEY_QC_TOUCH_AF_AEC, value);
+ }
+
+ /** @hide
+ * Gets the current redeye reduction setting.
+ *
+ * @return one of REDEYE_REDUCTION_XXX string constant. null if redeye reduction
+ * setting is not supported.
+ *
+ */
+ public String getRedeyeReductionMode() {
+ return get(KEY_QC_REDEYE_REDUCTION);
+ }
+
+ /** @hide
+ * Sets the redeye reduction. Other parameters may be changed after changing
+ * redeye reduction. After setting redeye reduction,
+ * applications should call getParameters to know if some parameters are
+ * changed.
+ *
+ * @param value REDEYE_REDUCTION_XXX string constants.
+ *
+ */
+ public void setRedeyeReductionMode(String value) {
+ set(KEY_QC_REDEYE_REDUCTION, value);
+ }
+
+ /** @hide
+ * Gets the frame rate mode setting.
+ *
+ * @return one of FRAME_RATE_XXX_MODE string constant. null if this
+ * setting is not supported.
+ */
+ public String getPreviewFrameRateMode() {
+ return get(KEY_QC_PREVIEW_FRAME_RATE_MODE);
+ }
+
+ /** @hide
+ * Sets the frame rate mode.
+ *
+ * @param value FRAME_RATE_XXX_MODE string constants.
+ */
+ public void setPreviewFrameRateMode(String value) {
+ set(KEY_QC_PREVIEW_FRAME_RATE_MODE, value);
+ }
+
+ /** @hide
+ * Gets the current auto scene detection setting.
+ *
+ * @return one of SCENE_DETECT_XXX string constant. null if auto scene detection
+ * setting is not supported.
+ *
+ */
+ public String getSceneDetectMode() {
+ return get(KEY_QC_SCENE_DETECT);
+ }
+
+ /** @hide
+ * Sets the auto scene detect. Other parameters may be changed after changing
+ * scene detect. After setting auto scene detection,
+ * applications should call getParameters to know if some parameters are
+ * changed.
+ *
+ * @param value SCENE_DETECT_XXX string constants.
+ *
+ */
+ public void setSceneDetectMode(String value) {
+ set(KEY_QC_SCENE_DETECT, value);
+ }
+
+ /** @hide
+ * Gets the current hdr bracketing mode setting.
+ *
+ * @return current hdr bracketing mode.
+ * @see #KEY_AE_BRACKET_OFF
+ * @see #KEY_AE_BRACKET_HDR
+ * @see #KEY_AE_BRACKET_BRACKATING
+ */
+ public String getAEBracket() {
+ return get(KEY_QC_AE_BRACKET_HDR);
+ }
+
+ /** @hide
+ * Sets the Power mode.
+ *
+ * @param value Power mode.
+ * @see #getPowerMode()
+ */
+ public void setPowerMode(String value) {
+ set(KEY_QC_POWER_MODE, value);
+ }
+
+ /** @hide
+ * Gets the current power mode setting.
+ *
+ * @return current power mode. null if power mode setting is not
+ * supported.
+ * @see #POWER_MODE_LOW
+ * @see #POWER_MODE_NORMAL
+ */
+ public String getPowerMode() {
+ return get(KEY_QC_POWER_MODE);
+ }
+
+ /** @hide
+ * Set HDR-Bracketing Level
+ *
+ * @param value HDR-Bracketing
+ */
+ public void setAEBracket(String value){
+ set(KEY_QC_AE_BRACKET_HDR, value);
+ }
+
+ /** @hide
+ * Gets the current ISO setting.
+ *
+ * @return one of ISO_XXX string constant. null if ISO
+ * setting is not supported.
+ */
+ public String getISOValue() {
+ return get(KEY_QC_ISO_MODE);
+ }
+
+ /** @hide
+ * Sets the ISO.
+ *
+ * @param iso ISO_XXX string constant.
+ */
+ public void setISOValue(String iso) {
+ set(KEY_QC_ISO_MODE, iso);
+ }
+
+ /** @hide
+ * Sets the exposure time.
+ *
+ * @param value exposure time.
+ */
+ public void setExposureTime(int value) {
+ set(KEY_QC_EXPOSURE_TIME, Integer.toString(value));
+ }
+
+ /** @hide
+ * Gets the current exposure time.
+ *
+ * @return exposure time.
+ */
+ public String getExposureTime() {
+ return get(KEY_QC_EXPOSURE_TIME);
+ }
+
+ /** @hide
+ * Gets the min supported exposure time.
+ *
+ * @return min supported exposure time.
+ */
+ public String getMinExposureTime() {
+ return get(KEY_QC_MIN_EXPOSURE_TIME);
+ }
+
+ /** @hide
+ * Gets the max supported exposure time.
+ *
+ * @return max supported exposure time.
+ */
+ public String getMaxExposureTime() {
+ return get(KEY_QC_MAX_EXPOSURE_TIME);
+ }
+
+ /** @hide
+ * Gets the current LensShade Mode.
+ *
+ * @return LensShade Mode
+ */
+ public String getLensShade() {
+ return get(KEY_QC_LENSSHADE);
+ }
+
+ /** @hide
+ * Sets the current LensShade Mode.
+ *
+ * @return LensShade Mode
+ */
+ public void setLensShade(String lensshade) {
+ set(KEY_QC_LENSSHADE, lensshade);
+ }
+
+ /** @hide
+ * Gets the current auto exposure setting.
+ *
+ * @return one of AUTO_EXPOSURE_XXX string constant. null if auto exposure
+ * setting is not supported.
+ */
+ public String getAutoExposure() {
+ return get(KEY_QC_AUTO_EXPOSURE);
+ }
+
+ /** @hide
+ * Sets the current auto exposure setting.
+ *
+ * @param value AUTO_EXPOSURE_XXX string constants.
+ */
+ public void setAutoExposure(String value) {
+ set(KEY_QC_AUTO_EXPOSURE, value);
+ }
+
+ /** @hide
+ * Gets the current MCE Mode.
+ *
+ * @return MCE value
+ */
+ public String getMemColorEnhance() {
+ return get(KEY_QC_MEMORY_COLOR_ENHANCEMENT);
+ }
+
+ /** @hide
+ * Sets the current MCE Mode.
+ *
+ * @return MCE Mode
+ */
+ public void setMemColorEnhance(String mce) {
+ set(KEY_QC_MEMORY_COLOR_ENHANCEMENT, mce);
+ }
+
+ /** @hide
+ * Set white balance manual cct value.
+ *
+ * @param cct user CCT setting.
+ */
+ public void setWBManualCCT(int cct) {
+ set(KEY_QC_WB_MANUAL_CCT, Integer.toString(cct));
+ }
+
+ /** @hide
+ * Gets the WB min supported CCT.
+ *
+ * @return min cct value.
+ */
+ public String getWBMinCCT() {
+ return get(KEY_QC_MIN_WB_CCT);
+ }
+
+ /** @hide
+ * Gets the WB max supported CCT.
+ *
+ * @return max cct value.
+ */
+ public String getMaxWBCCT() {
+ return get(KEY_QC_MAX_WB_CCT);
+ }
+
+ /** @hide
+ * Gets the current WB CCT.
+ *
+ * @return CCT value
+ */
+ public String getWBCurrentCCT() {
+ return get(KEY_QC_WB_MANUAL_CCT);
+ }
+
+ /** @hide
+ * Gets the current ZSL Mode.
+ *
+ * @return ZSL mode value
+ */
+ public String getZSLMode() {
+ return get(KEY_QC_ZSL);
+ }
+
+ /** @hide
+ * Sets the current ZSL Mode. ZSL mode is set as a 0th bit in KEY_CAMERA_MODE.
+ *
+ * @return null
+ */
+ public void setZSLMode(String zsl) {
+ set(KEY_QC_ZSL, zsl);
+ }
+
+ /** @hide
+ * Sets the current Auto HDR Mode.
+ * @ auto_hdr auto hdr string for enable/disable
+ * @return null
+ */
+ public void setAutoHDRMode(String auto_hdr){
+ set(KEY_QC_AUTO_HDR_ENABLE,auto_hdr);
+ }
+
+ /** @hide
+ * Gets the current Camera Mode Flag. Camera mode includes a
+ * flag(byte) which indicates different camera modes.
+ * For now support for ZSL added at bit0
+ *
+ * @return Camera Mode.
+ */
+ public String getCameraMode() {
+ return get(KEY_QC_CAMERA_MODE);
+ }
+
+ /** @hide
+ * Sets the current Camera Mode.
+ *
+ * @return null
+ */
+ public void setCameraMode(int cameraMode) {
+ set(KEY_QC_CAMERA_MODE, cameraMode);
+ }
+
+ private static final int MANUAL_FOCUS_POS_TYPE_INDEX = 0;
+ private static final int MANUAL_FOCUS_POS_TYPE_DAC = 1;
+ /** @hide
+ * Set focus position.
+ *
+ * @param pos user setting of focus position.
+ */
+ public void setFocusPosition(int type, int pos) {
+ set(KEY_QC_MANUAL_FOCUS_POS_TYPE, Integer.toString(type));
+ set(KEY_QC_MANUAL_FOCUS_POSITION, Integer.toString(pos));
+ }
+
+ /** @hide
+ * Gets the current focus position.
+ *
+ * @return current focus position
+ */
+ public String getCurrentFocusPosition() {
+ return get(KEY_QC_MANUAL_FOCUS_POSITION);
+ }
+
+
+ /** @hide
+ * Gets the current HFR Mode.
+ *
+ * @return VIDEO_HFR_XXX string constants
+ */
+ public String getVideoHighFrameRate() {
+ return get(KEY_QC_VIDEO_HIGH_FRAME_RATE);
+ }
+
+ /** @hide
+ * Sets the current HFR Mode.
+ *
+ * @param hfr VIDEO_HFR_XXX string constants
+ */
+ public void setVideoHighFrameRate(String hfr) {
+ set(KEY_QC_VIDEO_HIGH_FRAME_RATE, hfr);
+ }
+
+ /** @hide
+ * Gets the current Video HDR Mode.
+ *
+ * @return Video HDR mode value
+ */
+ public String getVideoHDRMode() {
+ return get(KEY_QC_VIDEO_HDR);
+ }
+
+ /** @hide
+ * Sets the current Video HDR Mode.
+ *
+ * @return null
+ */
+ public void setVideoHDRMode(String videohdr) {
+ set(KEY_QC_VIDEO_HDR, videohdr);
+ }
+
+ /** @hide
+ * Gets the current DENOISE setting.
+ *
+ * @return one of DENOISE_XXX string constant. null if Denoise
+ * setting is not supported.
+ *
+ */
+ public String getDenoise() {
+ return get(KEY_QC_DENOISE);
+ }
+
+ /** @hide
+ * Gets the current Continuous AF setting.
+ *
+ * @return one of CONTINUOUS_AF_XXX string constant. null if continuous AF
+ * setting is not supported.
+ *
+ */
+ public String getContinuousAf() {
+ return get(KEY_QC_CONTINUOUS_AF);
+ }
+
+ /** @hide
+ * Sets the current Denoise mode.
+ * @param value DENOISE_XXX string constants.
+ *
+ */
+
+ public void setDenoise(String value) {
+ set(KEY_QC_DENOISE, value);
+ }
+
+ /** @hide
+ * Sets the current Continuous AF mode.
+ * @param value CONTINUOUS_AF_XXX string constants.
+ *
+ */
+ public void setContinuousAf(String value) {
+ set(KEY_QC_CONTINUOUS_AF, value);
+ }
+
+ /** @hide
+ * Gets the current selectable zone af setting.
+ *
+ * @return one of SELECTABLE_ZONE_AF_XXX string constant. null if selectable zone af
+ * setting is not supported.
+ */
+ public String getSelectableZoneAf() {
+ return get(KEY_QC_SELECTABLE_ZONE_AF);
+ }
+
+ /** @hide
+ * Sets the current selectable zone af setting.
+ *
+ * @param value SELECTABLE_ZONE_AF_XXX string constants.
+ */
+ public void setSelectableZoneAf(String value) {
+ set(KEY_QC_SELECTABLE_ZONE_AF, value);
+ }
+
+ /** @hide
+ * Gets the current face detection setting.
+ *
+ * @return one of FACE_DETECTION_XXX string constant. null if face detection
+ * setting is not supported.
+ *
+ */
+ public String getFaceDetectionMode() {
+ return get(KEY_QC_FACE_DETECTION);
+ }
+
+ /** @hide
+ * Sets the auto scene detect. Other settings like Touch AF/AEC might be
+ * changed after setting face detection.
+ *
+ * @param value FACE_DETECTION_XXX string constants.
+ *
+ */
+ public void setFaceDetectionMode(String value) {
+ set(KEY_QC_FACE_DETECTION, value);
+ }
+
+ /** @hide
+ * Gets the current video rotation setting.
+ *
+ * @return one of VIDEO_QC_ROTATION_XXX string constant. null if video rotation
+ * setting is not supported.
+ */
+ public String getVideoRotation() {
+ return get(KEY_QC_VIDEO_ROTATION);
+ }
+
+ /** @hide
+ * Sets the current video rotation setting.
+ *
+ * @param value VIDEO_QC_ROTATION_XXX string constants.
+ */
+ public void setVideoRotation(String value) {
+ set(KEY_QC_VIDEO_ROTATION, value);
+ }
+ /** @hide
+ * Gets the supported video rotation modes.
+ *
+ * @return a List of VIDEO_QC_ROTATION_XXX string constant. null if this
+ * setting is not supported.
+ */
+ public List<String> getSupportedVideoRotationValues() {
+ String str = get(KEY_QC_VIDEO_ROTATION + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ // Splits a comma delimited string to an ArrayList of Coordinate.
+ // Return null if the passing string is null or the Coordinate is 0.
+ private ArrayList<Coordinate> splitCoordinate(String str) {
+ if (str == null) return null;
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(str);
+ ArrayList<Coordinate> coordinateList = new ArrayList<Coordinate>();
+ for (String s : splitter) {
+ Coordinate coordinate = strToCoordinate(s);
+ if (coordinate != null) coordinateList.add(coordinate);
+ }
+ if (coordinateList.size() == 0) return null;
+ return coordinateList;
+ }
+
+ // Parses a string (ex: "500x500") to Coordinate object.
+ // Return null if the passing string is null.
+ private Coordinate strToCoordinate(String str) {
+ if (str == null) return null;
+
+ int pos = str.indexOf('x');
+ if (pos != -1) {
+ String x = str.substring(0, pos);
+ String y = str.substring(pos + 1);
+ return new Coordinate(Integer.parseInt(x),
+ Integer.parseInt(y));
+ }
+ Log.e(TAG, "Invalid Coordinate parameter string=" + str);
+ return null;
+ }
+ /* ### QC ADD-ONS: END */
};
}
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 2fe8fb6..ba0d5be 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -101,6 +101,7 @@ public class SystemSensorManager extends SensorManager {
@Override
protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
+ android.util.SeempLog.record_sensor_rate(381, sensor, delayUs);
if (listener == null || sensor == null) {
Log.e(TAG, "sensor or listener is null");
return false;
@@ -142,6 +143,7 @@ public class SystemSensorManager extends SensorManager {
/** @hide */
@Override
protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
+ android.util.SeempLog.record_sensor(382, sensor);
// Trigger Sensors should use the cancelTriggerSensor call.
if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
return;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index a2ef078..7464211 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -398,17 +398,24 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* this camera device.</p>
* <p>For devices at the LEGACY level or above:</p>
* <ul>
- * <li>This list will always include (30, 30).</li>
- * <li>Also, for constant-framerate recording, for each normal
+ * <li>
+ * <p>For constant-framerate recording, for each normal
+ * {@link android.media.CamcorderProfile CamcorderProfile}, that is, a
* {@link android.media.CamcorderProfile CamcorderProfile} that has
* {@link android.media.CamcorderProfile#quality quality} in
* the range [{@link android.media.CamcorderProfile#QUALITY_LOW QUALITY_LOW},
* {@link android.media.CamcorderProfile#QUALITY_2160P QUALITY_2160P}], if the profile is
* supported by the device and has
* {@link android.media.CamcorderProfile#videoFrameRate videoFrameRate} <code>x</code>, this list will
- * always include (<code>x</code>,<code>x</code>).</li>
- * <li>For preview streaming use case, this list will always include (<code>min</code>, <code>max</code>) where
- * <code>min</code> &lt;= 15 and <code>max</code> &gt;= 30.</li>
+ * always include (<code>x</code>,<code>x</code>).</p>
+ * </li>
+ * <li>
+ * <p>Also, a camera device must either not support any
+ * {@link android.media.CamcorderProfile CamcorderProfile},
+ * or support at least one
+ * normal {@link android.media.CamcorderProfile CamcorderProfile} that has
+ * {@link android.media.CamcorderProfile#videoFrameRate videoFrameRate} <code>x</code> &gt;= 24.</p>
+ * </li>
* </ul>
* <p>For devices at the LIMITED level or above:</p>
* <ul>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 35a1d96..f61892e 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -472,13 +472,13 @@ public abstract class CameraMetadata<TKey> {
* <li>The maximum available resolution for RAW_SENSOR streams
* will match either the value in
* {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize} or
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</li>
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.</li>
* <li>All DNG-related optional metadata entries are provided
* by the camera device.</li>
* </ul>
*
- * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 3f566eb..67835a0 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -556,6 +556,10 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* Set a capture request field to a value. The field definitions can be
* found in {@link CaptureRequest}.
*
+ * <p>Setting a field to {@code null} will remove that field from the capture request.
+ * Unless the field is optional, removing it will likely produce an error from the camera
+ * device when the request is submitted.</p>
+ *
* @param key The metadata field to write.
* @param value The value to set the field to, which must be of a matching
* type to the key.
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 4866598..c26d07d 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -81,6 +81,7 @@ public class RequestThreadManager {
private static final int PREVIEW_FRAME_TIMEOUT = 1000; // ms
private static final int JPEG_FRAME_TIMEOUT = 4000; // ms (same as CTS for API2)
+ private static final int HDR_TIMEOUT = 20000; //ms
private static final int REQUEST_COMPLETE_TIMEOUT = JPEG_FRAME_TIMEOUT;
private static final float ASPECT_RATIO_TOLERANCE = 0.01f;
@@ -825,7 +826,9 @@ public class RequestThreadManager {
if (holder.hasJpegTargets()) {
doJpegCapture(holder);
- if (!mReceivedJpeg.block(JPEG_FRAME_TIMEOUT)) {
+ if (!mReceivedJpeg.block(
+ mParams.getSceneMode().equals(mParams.SCENE_MODE_HDR)
+ ? HDR_TIMEOUT : JPEG_FRAME_TIMEOUT)) {
Log.e(TAG, "Hit timeout for jpeg callback!");
mCaptureCollector.failNextJpeg();
}
@@ -920,6 +923,9 @@ public class RequestThreadManager {
mDeviceState.setError(
CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
}
+ if (mPreviewTexture != null) {
+ mPreviewTexture.setOnFrameAvailableListener(null);
+ }
if (mGLThreadManager != null) {
mGLThreadManager.quit();
mGLThreadManager = null;
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index bc80fc1..86eb01d 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -433,6 +433,20 @@ public class SurfaceTextureRenderer {
EGL14.eglChooseConfig(mEGLDisplay, attribList, /*offset*/ 0, configs, /*offset*/ 0,
configs.length, numConfigs, /*offset*/ 0);
checkEglError("eglCreateContext RGB888+recordable ES2");
+ if (numConfigs[0] == 0) {
+ Log.w(TAG, "eglChooseConfig returned no configs, retrying without EGL_RECORDABLE_ANDROID");
+ int[] attribList2 = {
+ EGL14.EGL_RED_SIZE, EGL_COLOR_BITLENGTH,
+ EGL14.EGL_GREEN_SIZE, EGL_COLOR_BITLENGTH,
+ EGL14.EGL_BLUE_SIZE, EGL_COLOR_BITLENGTH,
+ EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
+ EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT | EGL14.EGL_WINDOW_BIT,
+ EGL14.EGL_NONE
+ };
+ EGL14.eglChooseConfig(mEGLDisplay, attribList2, /*offset*/ 0, configs, /*offset*/ 0,
+ configs.length, numConfigs, /*offset*/ 0);
+ checkEglError("eglCreateContext RGB888 ES2");
+ }
mConfigs = configs[0];
int[] attrib_list = {
EGL14.EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index ff7a300..5e9cd97 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -317,6 +317,11 @@ public class InputMethodService extends AbstractInputMethodService {
final Insets mTmpInsets = new Insets();
final int[] mTmpLocation = new int[2];
+ int mVolumeKeyCursorControl;
+ private static final int VOLUME_CURSOR_OFF = 0;
+ private static final int VOLUME_CURSOR_ON = 1;
+ private static final int VOLUME_CURSOR_ON_REVERSE = 2;
+
final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
new ViewTreeObserver.OnComputeInternalInsetsListener() {
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
@@ -1856,6 +1861,26 @@ public class InputMethodService extends AbstractInputMethodService {
}
return false;
}
+ if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) {
+ mVolumeKeyCursorControl = Settings.System.getInt(getContentResolver(),
+ Settings.System.VOLUME_KEY_CURSOR_CONTROL, 0);
+ if (isInputViewShown() && (mVolumeKeyCursorControl != VOLUME_CURSOR_OFF)) {
+ sendDownUpKeyEvents((mVolumeKeyCursorControl == VOLUME_CURSOR_ON_REVERSE)
+ ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT);
+ return true;
+ }
+ return false;
+ }
+ if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN) {
+ mVolumeKeyCursorControl = Settings.System.getInt(getContentResolver(),
+ Settings.System.VOLUME_KEY_CURSOR_CONTROL, 0);
+ if (isInputViewShown() && (mVolumeKeyCursorControl != VOLUME_CURSOR_OFF)) {
+ sendDownUpKeyEvents((mVolumeKeyCursorControl == VOLUME_CURSOR_ON_REVERSE)
+ ? KeyEvent.KEYCODE_DPAD_LEFT : KeyEvent.KEYCODE_DPAD_RIGHT);
+ return true;
+ }
+ return false;
+ }
return doMovementKey(keyCode, event, MOVEMENT_DOWN);
}
@@ -1906,6 +1931,15 @@ public class InputMethodService extends AbstractInputMethodService {
return handleBack(true);
}
}
+ if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP
+ || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+ mVolumeKeyCursorControl = Settings.System.getInt(getContentResolver(),
+ Settings.System.VOLUME_KEY_CURSOR_CONTROL, 0);
+ if (isInputViewShown() && (mVolumeKeyCursorControl != VOLUME_CURSOR_OFF)) {
+ return true;
+ }
+ return false;
+ }
return doMovementKey(keyCode, event, MOVEMENT_UP);
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4d9b759..6bbd9c8 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.NetworkUtils;
+import android.net.wifi.WifiDevice;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.Handler;
@@ -49,6 +50,7 @@ import com.android.internal.util.Protocol;
import java.net.InetAddress;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.HashMap;
+import java.util.List;
import libcore.net.event.NetworkEventDispatcher;
@@ -283,6 +285,15 @@ public class ConnectivityManager {
"android.net.conn.TETHER_STATE_CHANGED";
/**
+ * Broadcast intent action indicating that a Station is connected
+ * or disconnected.
+ *
+ * @hide
+ */
+ public static final String TETHER_CONNECT_STATE_CHANGED =
+ "codeaurora.net.conn.TETHER_CONNECT_STATE_CHANGED";
+
+ /**
* @hide
* gives a String[] listing all the interfaces configured for
* tethering and currently available for tethering.
@@ -1838,6 +1849,20 @@ public class ConnectivityManager {
}
}
+ /**
+ * Get the list of Stations connected to Hotspot.
+ *
+ * @return a list of {@link WifiDevice} objects.
+ * {@hide}
+ */
+ public List<WifiDevice> getTetherConnectedSta() {
+ try {
+ return mService.getTetherConnectedSta();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
/** {@hide} */
public static final int TETHER_ERROR_NO_ERROR = 0;
/** {@hide} */
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d4dd669..c6de7a5 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -26,6 +26,7 @@ import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.ProxyInfo;
+import android.net.wifi.WifiDevice;
import android.os.IBinder;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
@@ -36,6 +37,8 @@ import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
+import java.util.List;
+
/**
* Interface that answers queries about, and allows changing, the
* state of network connectivity.
@@ -92,6 +95,8 @@ interface IConnectivityManager
int setUsbTethering(boolean enable);
+ List<WifiDevice> getTetherConnectedSta();
+
void reportInetCondition(int networkType, int percentage);
void reportNetworkConnectivity(in Network network, boolean hasConnectivity);
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl
index b7af374..5a70ff1 100644
--- a/core/java/android/net/INetworkManagementEventObserver.aidl
+++ b/core/java/android/net/INetworkManagementEventObserver.aidl
@@ -92,6 +92,13 @@ interface INetworkManagementEventObserver {
void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos);
/**
+ * Message is received from network interface.
+ *
+ * @param message The message
+ */
+ void interfaceMessageRecevied(String message);
+
+ /**
* Information about available DNS servers has been received.
*
* @param iface The interface on which the information was received.
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 7f5f377..9e639e8 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -48,6 +48,9 @@ interface INetworkPolicyManager {
/** Snooze limit on policy matching given template. */
void snoozeLimit(in NetworkTemplate template);
+ /** Snooze warning on policy matching given template. */
+ void snoozeWarning(in NetworkTemplate template);
+
/** Control if background data is restricted system-wide. */
void setRestrictBackground(boolean restrictBackground);
boolean getRestrictBackground();
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 6436e42..17033c4 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -57,4 +57,5 @@ interface INetworkStatsService {
/** Advise persistance threshold; may be overridden internally. */
void advisePersistThreshold(long thresholdBytes);
+ void resetDataUsageHistoryForAllUid(in NetworkTemplate template);
}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index c4de4a2..49dc93b 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -57,6 +57,8 @@ public final class LinkProperties implements Parcelable {
private int mMtu;
// in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
private String mTcpBufferSizes;
+ private int mTcpDelayedAckSegments = 1;
+ private int mTcpUserCfg = 0;
private static final int MIN_MTU = 68;
private static final int MIN_MTU_V6 = 1280;
@@ -156,6 +158,8 @@ public final class LinkProperties implements Parcelable {
}
setMtu(source.getMtu());
mTcpBufferSizes = source.mTcpBufferSizes;
+ mTcpDelayedAckSegments = source.mTcpDelayedAckSegments;
+ mTcpUserCfg = source.mTcpUserCfg;
}
}
@@ -439,6 +443,45 @@ public final class LinkProperties implements Parcelable {
return mTcpBufferSizes;
}
+ /**
+ * Number of full MSS to receive before Acking RFC2581
+ * @param segments The number of segments to receive
+ *
+ * @hide
+ */
+ public void setTcpDelayedAckSegments(int segments) {
+ mTcpDelayedAckSegments = segments;
+ }
+
+ /**
+ * Gets the number of segments before acking
+ *
+ * @hide
+ */
+ public int getTcpDelayedAckSegments() {
+ return mTcpDelayedAckSegments;
+ }
+
+ /**
+ * Sets the value for TCP usercfg
+ *
+ * @param value 0/1 currently to disable/enable
+ *
+ * @hide
+ */
+ public void setTcpUserCfg(int value) {
+ mTcpUserCfg = value;
+ }
+
+ /**
+ * Gets the value of TCP usercfg
+ *
+ * @hide
+ */
+ public int getTcpUserCfg() {
+ return mTcpUserCfg;
+ }
+
private RouteInfo routeWithInterface(RouteInfo route) {
return new RouteInfo(
route.getDestination(),
@@ -599,6 +642,8 @@ public final class LinkProperties implements Parcelable {
mStackedLinks.clear();
mMtu = 0;
mTcpBufferSizes = null;
+ mTcpDelayedAckSegments = 1;
+ mTcpUserCfg = 0;
}
/**
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index a83e722..7f4d6e3 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.GET_SIGNATURES;
import static android.net.NetworkPolicy.CYCLE_NONE;
import static android.text.format.Time.MONTH_DAY;
+import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -48,6 +49,12 @@ public class NetworkPolicyManager {
public static final int POLICY_REJECT_METERED_BACKGROUND = 0x1;
/** Allow network use (metered or not) in the background in battery save mode. */
public static final int POLICY_ALLOW_BACKGROUND_BATTERY_SAVE = 0x2;
+ /** Reject application network traffic on wifi network **/
+ public static final int POLICY_REJECT_ON_WLAN = 0x8000;
+ /** Reject application network traffic on cellular network **/
+ public static final int POLICY_REJECT_ON_DATA = 0x10000;
+ /** Reject application background network traffic on WiFi network **/
+ public static final int POLICY_REJECT_ON_WLAN_BACKGROUND = 0x20000;
/* RULE_* are not masks and they must be exclusive */
public static final int RULE_UNKNOWN = -1;
@@ -81,6 +88,54 @@ public class NetworkPolicyManager {
*/
public static final String EXTRA_NETWORK_TEMPLATE = "android.net.NETWORK_TEMPLATE";
+ /**
+ * Broadcast intent action for informing a custom component about a network policy
+ * notification.
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_SHOW_NETWORK_POLICY_NOTIFICATION =
+ "android.net.action.SHOW_NETWORK_POLICY_NOTIFICATION";
+
+ /**
+ * The sequence number associated with the notification - a higher number
+ * indicates previous notifications may be disregarded.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_NOTIFICATION_SEQUENCE_NUMBER =
+ "android.net.extra.NOTIFICATION_SEQUENCE_NUMBER";
+
+ /**
+ * The type of notification that should be presented to the user.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_NOTIFICATION_TYPE = "android.net.extra.NOTIFICATION_TYPE";
+
+ @SystemApi
+ public static final int NOTIFICATION_TYPE_NONE = 0;
+ @SystemApi
+ public static final int NOTIFICATION_TYPE_USAGE_WARNING = 1;
+ @SystemApi
+ public static final int NOTIFICATION_TYPE_USAGE_REACHED_LIMIT = 2;
+ @SystemApi
+ public static final int NOTIFICATION_TYPE_USAGE_EXCEEDED_LIMIT = 3;
+
+ /**
+ * The number of bytes used on the network in the notification.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_BYTES_USED = "android.net.extra.BYTES_USED";
+
+ /**
+ * The network policy for the network in the notification.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_NETWORK_POLICY = "android.net.extra.NETWORK_POLICY";
+
private final Context mContext;
private INetworkPolicyManager mService;
diff --git a/core/java/android/net/wimax/WimaxHelper.java b/core/java/android/net/wimax/WimaxHelper.java
new file mode 100644
index 0000000..9a6727e
--- /dev/null
+++ b/core/java/android/net/wimax/WimaxHelper.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2011-2015 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wimax;
+
+import dalvik.system.DexClassLoader;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.provider.Settings;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * {@hide}
+ */
+public class WimaxHelper {
+
+ private static final String TAG = "WimaxHelper";
+
+ private static final String WIMAX_CONTROLLER_CLASSNAME = "com.htc.net.wimax.WimaxController";
+ private static final String WIMAX_MANAGER_CLASSNAME = "android.net.fourG.wimax.Wimax4GManager";
+
+ private static DexClassLoader sWimaxClassLoader;
+ private static String sWimaxManagerClassname, sIsWimaxEnabledMethodname,
+ sSetWimaxEnabledMethodname, sGetWimaxStateMethodname;
+
+ public static boolean isWimaxSupported(Context context) {
+ return context.getResources().getBoolean(
+ com.android.internal.R.bool.config_wimaxEnabled);
+ }
+
+ public static DexClassLoader getWimaxClassLoader(Context context) {
+ if (isWimaxSupported(context)) {
+ if (sWimaxClassLoader == null) {
+ sWimaxManagerClassname = context.getResources().getString(
+ com.android.internal.R.string.config_wimaxManagerClassname);
+
+ // WimaxController::getWimaxState == Wimax4GManager::get4GState.
+ // However, Wimax4GManager also implements a different getWimaxState
+ // method, which returns a WimaxState object describing the connection
+ // state, not the enabled state. Other methods are similarly renamed.
+ if (sWimaxManagerClassname.equals(WIMAX_CONTROLLER_CLASSNAME)) {
+ sIsWimaxEnabledMethodname = "isWimaxEnabled";
+ sSetWimaxEnabledMethodname = "setWimaxEnabled";
+ sGetWimaxStateMethodname = "getWimaxState";
+ } else if (sWimaxManagerClassname.equals(WIMAX_MANAGER_CLASSNAME)) {
+ sIsWimaxEnabledMethodname = "is4GEnabled";
+ sSetWimaxEnabledMethodname = "set4GEnabled";
+ sGetWimaxStateMethodname = "get4GState";
+ }
+
+ String wimaxJarLocation = context.getResources().getString(
+ com.android.internal.R.string.config_wimaxServiceJarLocation);
+ String wimaxLibLocation = context.getResources().getString(
+ com.android.internal.R.string.config_wimaxNativeLibLocation);
+ sWimaxClassLoader = new DexClassLoader(wimaxJarLocation,
+ new ContextWrapper(context).getCacheDir().getAbsolutePath(),
+ wimaxLibLocation,ClassLoader.getSystemClassLoader());
+ }
+ return sWimaxClassLoader;
+ }
+ return null;
+ }
+
+ public static Object createWimaxService(Context context, Handler handler) {
+ Object controller = null;
+
+ try {
+ DexClassLoader wimaxClassLoader = getWimaxClassLoader(context);
+ if (sWimaxManagerClassname.equals(WIMAX_CONTROLLER_CLASSNAME)) {
+ // Load supersonic's and speedy's WimaxController.
+ IBinder b = ServiceManager.getService(WimaxManagerConstants.WIMAX_SERVICE);
+ if (b != null) {
+ Class<?> klass = wimaxClassLoader.loadClass("com.htc.net.wimax.IWimaxController$Stub");
+ if (klass != null) {
+ Method asInterface = klass.getMethod("asInterface", IBinder.class);
+ Object wc = asInterface.invoke(null, b);
+ if (wc != null) {
+ klass = wimaxClassLoader.loadClass(WIMAX_CONTROLLER_CLASSNAME);
+ if (klass != null) {
+ Constructor<?> ctor = klass.getDeclaredConstructors()[1];
+ controller = ctor.newInstance(wc, handler);
+ }
+ }
+ }
+ }
+ } else if (sWimaxManagerClassname.equals(WIMAX_MANAGER_CLASSNAME)) {
+ // Load crespo4g's (and epicmtd's) Wimax4GManager.
+ // Note that crespo4g's implementation grabs WIMAX_SERVICE internally, so
+ // it doesn't need to be passed in. Other implementations (may) require
+ // WIMAX_SERVICE to be grabbed externally, so check Wimax4GManager::<init>.
+ Class<?> klass = wimaxClassLoader.loadClass(WIMAX_MANAGER_CLASSNAME);
+ if (klass != null) {
+ Constructor<?> ctor = klass.getDeclaredConstructors()[0];
+ controller = ctor.newInstance();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to create WimaxController instance", e);
+ }
+
+ return controller;
+ }
+
+ public static boolean isWimaxEnabled(Context context) {
+ boolean ret = false;
+ try {
+ Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE);
+ Method m = wimaxService.getClass().getMethod(sIsWimaxEnabledMethodname);
+ ret = (Boolean) m.invoke(wimaxService);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to get WiMAX enabled state!", e);
+ }
+ return ret;
+ }
+
+ public static boolean setWimaxEnabled(Context context, boolean enabled) {
+ boolean ret = false;
+ try {
+ Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE);
+ Method m = wimaxService.getClass().getMethod(sSetWimaxEnabledMethodname, boolean.class);
+ ret = (Boolean) m.invoke(wimaxService, enabled);
+ if (ret)
+ Settings.Secure.putInt(context.getContentResolver(),
+ Settings.Secure.WIMAX_ON, (Boolean) enabled ? 1 : 0);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to set WiMAX state!", e);
+ }
+ return ret;
+ }
+
+ public static int getWimaxState(Context context) {
+ int ret = 0;
+ try {
+ Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE);
+ Method m = wimaxService.getClass().getMethod(sGetWimaxStateMethodname);
+ ret = (Integer) m.invoke(wimaxService);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to get WiMAX state!", e);
+ }
+ return ret;
+ }
+
+ public static boolean wimaxRescan(Context context) {
+ boolean ret = false;
+ try {
+ Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE);
+ Method wimaxRescan = wimaxService.getClass().getMethod("wimaxRescan");
+ if (wimaxRescan != null) {
+ wimaxRescan.invoke(wimaxService);
+ ret = true;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to perform WiMAX rescan!", e);
+ }
+ return ret;
+ }
+
+ private static Object getWimaxInfo(Context context) {
+ Object wimaxInfo = null;
+ try {
+ Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE);
+ Method getConnectionInfo = wimaxService.getClass().getMethod("getConnectionInfo");
+ wimaxInfo = getConnectionInfo.invoke(wimaxService);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to get a WimaxInfo object!", e);
+ }
+ return wimaxInfo;
+ }
+} \ No newline at end of file
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 961a3f4..0107d93 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,6 +31,7 @@ import android.nfc.INfcTag;
import android.nfc.INfcCardEmulation;
import android.nfc.INfcUnlockHandler;
import android.os.Bundle;
+import android.os.IBinder;
/**
* @hide
@@ -37,6 +41,7 @@ interface INfcAdapter
INfcTag getNfcTagInterface();
INfcCardEmulation getNfcCardEmulationInterface();
INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
+ IBinder getNfcAdapterVendorInterface(in String vendor);
int getState();
boolean disable(boolean saveState);
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index d619c0a..c7d4c65 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -371,40 +371,44 @@ public final class NfcActivityManager extends IAppCallback.Stub
flags = state.flags;
activity = state.activity;
}
-
- // Make callbacks without lock
- if (ndefCallback != null) {
- message = ndefCallback.createNdefMessage(event);
- }
- if (urisCallback != null) {
- uris = urisCallback.createBeamUris(event);
- if (uris != null) {
- ArrayList<Uri> validUris = new ArrayList<Uri>();
- for (Uri uri : uris) {
- if (uri == null) {
- Log.e(TAG, "Uri not allowed to be null.");
- continue;
- }
- String scheme = uri.getScheme();
- if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
- !scheme.equalsIgnoreCase("content"))) {
- Log.e(TAG, "Uri needs to have " +
- "either scheme file or scheme content");
- continue;
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ // Make callbacks without lock
+ if (ndefCallback != null) {
+ message = ndefCallback.createNdefMessage(event);
+ }
+ if (urisCallback != null) {
+ uris = urisCallback.createBeamUris(event);
+ if (uris != null) {
+ ArrayList<Uri> validUris = new ArrayList<Uri>();
+ for (Uri uri : uris) {
+ if (uri == null) {
+ Log.e(TAG, "Uri not allowed to be null.");
+ continue;
+ }
+ String scheme = uri.getScheme();
+ if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
+ !scheme.equalsIgnoreCase("content"))) {
+ Log.e(TAG, "Uri needs to have " +
+ "either scheme file or scheme content");
+ continue;
+ }
+ uri = ContentProvider.maybeAddUserId(uri, UserHandle.myUserId());
+ validUris.add(uri);
}
- uri = ContentProvider.maybeAddUserId(uri, UserHandle.myUserId());
- validUris.add(uri);
- }
- uris = validUris.toArray(new Uri[validUris.size()]);
+ uris = validUris.toArray(new Uri[validUris.size()]);
+ }
}
- }
- if (uris != null && uris.length > 0) {
- for (Uri uri : uris) {
- // Grant the NFC process permission to read these URIs
- activity.grantUriPermission("com.android.nfc", uri,
- Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ if (uris != null && uris.length > 0) {
+ for (Uri uri : uris) {
+ // Grant the NFC process permission to read these URIs
+ activity.grantUriPermission("com.android.nfc", uri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
return new BeamShareData(message, uris, new UserHandle(UserHandle.myUserId()), flags);
}
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index 78a9401..9abf325 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -1,6 +1,9 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* 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
@@ -37,7 +40,7 @@ import android.util.Log;
*
* @hide
*/
-public final class AidGroup implements Parcelable {
+public class AidGroup implements Parcelable {
/**
* The maximum number of AIDs that can be present in any one group.
*/
@@ -45,9 +48,9 @@ public final class AidGroup implements Parcelable {
static final String TAG = "AidGroup";
- final List<String> aids;
- final String category;
- final String description;
+ protected List<String> aids;
+ protected String category;
+ protected String description;
/**
* Creates a new AidGroup object.
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 7678678..09487d7 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -48,53 +48,53 @@ import java.util.Map;
/**
* @hide
*/
-public final class ApduServiceInfo implements Parcelable {
+public class ApduServiceInfo implements Parcelable {
static final String TAG = "ApduServiceInfo";
/**
* The service that implements this
*/
- final ResolveInfo mService;
+ protected ResolveInfo mService;
/**
* Description of the service
*/
- final String mDescription;
+ protected String mDescription;
/**
* Whether this service represents AIDs running on the host CPU
*/
- final boolean mOnHost;
+ protected boolean mOnHost;
/**
* Mapping from category to static AID group
*/
- final HashMap<String, AidGroup> mStaticAidGroups;
+ protected HashMap<String, AidGroup> mStaticAidGroups;
/**
* Mapping from category to dynamic AID group
*/
- final HashMap<String, AidGroup> mDynamicAidGroups;
+ protected HashMap<String, AidGroup> mDynamicAidGroups;
/**
* Whether this service should only be started when the device is unlocked.
*/
- final boolean mRequiresDeviceUnlock;
+ protected boolean mRequiresDeviceUnlock;
/**
* The id of the service banner specified in XML.
*/
- final int mBannerResourceId;
+ protected int mBannerResourceId;
/**
* The uid of the package the service belongs to
*/
- final int mUid;
+ protected int mUid;
/**
* Settings Activity for this service
*/
- final String mSettingsActivityName;
+ protected String mSettingsActivityName;
/**
* @hide
diff --git a/core/java/android/nfc/tech/MifareClassic.java b/core/java/android/nfc/tech/MifareClassic.java
index 8c92288..302c02d 100644
--- a/core/java/android/nfc/tech/MifareClassic.java
+++ b/core/java/android/nfc/tech/MifareClassic.java
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2015 NXP Semiconductors
+ * The original Work has been changed by NXP Semiconductors.
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -173,6 +175,10 @@ public final class MifareClassic extends BasicTagTechnology {
mType = TYPE_CLASSIC;
mSize = SIZE_4K;
break;
+ case 0x19:
+ mType = TYPE_CLASSIC;
+ mSize = SIZE_2K;
+ break;
case 0x28:
mType = TYPE_CLASSIC;
mSize = SIZE_1K;
diff --git a/core/java/android/nfc/tech/NfcA.java b/core/java/android/nfc/tech/NfcA.java
index 88730f9..b7fa455 100644
--- a/core/java/android/nfc/tech/NfcA.java
+++ b/core/java/android/nfc/tech/NfcA.java
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2015 NXP Semiconductors
+ * The original Work has been changed by NXP Semiconductors.
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -66,8 +68,15 @@ public final class NfcA extends BasicTagTechnology {
/** @hide */
public NfcA(Tag tag) throws RemoteException {
super(tag, TagTechnology.NFC_A);
- Bundle extras = tag.getTechExtras(TagTechnology.NFC_A);
- mSak = extras.getShort(EXTRA_SAK);
+ Bundle extras;
+ mSak = 0;
+ if(tag.hasTech(TagTechnology.MIFARE_CLASSIC))
+ {
+ extras = tag.getTechExtras(TagTechnology.MIFARE_CLASSIC);
+ mSak = extras.getShort(EXTRA_SAK);
+ }
+ extras = tag.getTechExtras(TagTechnology.NFC_A);
+ mSak |= extras.getShort(EXTRA_SAK);
mAtqa = extras.getByteArray(EXTRA_ATQA);
}
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 1f3e9a7..050820c 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2016 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +17,7 @@
package android.os;
+import android.app.IBatteryService;
import android.content.Context;
import android.os.BatteryProperty;
import android.os.IBatteryPropertiesRegistrar;
@@ -95,6 +97,79 @@ public class BatteryManager {
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer containing the current dock status constant.
+ * @hide
+ */
+ public static final String EXTRA_DOCK_STATUS = "dock_status";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer containing the current dock health constant.
+ * @hide
+ */
+ public static final String EXTRA_DOCK_HEALTH = "dock_health";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * boolean indicating whether a dock battery is present.
+ * @hide
+ */
+ public static final String EXTRA_DOCK_PRESENT = "dock_present";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer field containing the current dock battery level, from 0 to
+ * {@link #EXTRA_SCALE}.
+ * @hide
+ */
+ public static final String EXTRA_DOCK_LEVEL = "dock_level";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer containing the maximum dock battery level.
+ * @hide
+ */
+ public static final String EXTRA_DOCK_SCALE = "dock_scale";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer containing the resource ID of a small status bar icon
+ * indicating the current dock battery state.
+ * @hide
+ */
+ public static final String EXTRA_DOCK_ICON_SMALL = "dock_icon-small";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer indicating whether the device is plugged in to a dock power
+ * source.
+ * @hide
+ */
+ public static final String EXTRA_DOCK_PLUGGED = "dock_plugged";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer containing the current dock battery voltage level.
+ * @hide
+ */
+ public static final String EXTRA_DOCK_VOLTAGE = "dock_voltage";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer containing the current dock battery temperature.
+ * @hide
+ */
+ public static final String EXTRA_DOCK_TEMPERATURE = "dock_temperature";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * String describing the technology of the current dock battery.
+ * @hide
+ */
+ public static final String EXTRA_DOCK_TECHNOLOGY = "dock_technology";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* Int value set to nonzero if an unsupported charger is attached
* to the device.
* {@hide}
@@ -133,10 +208,23 @@ public class BatteryManager {
/** Power source is wireless. */
public static final int BATTERY_PLUGGED_WIRELESS = 4;
+ // values of the "dock_plugged" field in the ACTION_BATTERY_CHANGED intent.
+ // These must be powers of 2.
+ /** Power source is an DockAC charger.
+ * @hide*/
+ public static final int BATTERY_DOCK_PLUGGED_AC = 1;
+ /** Power source is an DockUSB charger.
+ * @hide*/
+ public static final int BATTERY_DOCK_PLUGGED_USB = 2;
+
/** @hide */
public static final int BATTERY_PLUGGED_ANY =
BATTERY_PLUGGED_AC | BATTERY_PLUGGED_USB | BATTERY_PLUGGED_WIRELESS;
+ /** @hide */
+ public static final int BATTERY_DOCK_PLUGGED_ANY =
+ BATTERY_DOCK_PLUGGED_AC | BATTERY_DOCK_PLUGGED_USB;
+
/**
* Sent when the device's battery has started charging (or has reached full charge
* and the device is on power). This is a good time to do work that you would like to
@@ -191,6 +279,7 @@ public class BatteryManager {
*/
public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5;
+ private final IBatteryService mBatteryService;
private final IBatteryStats mBatteryStats;
private final IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
@@ -202,6 +291,27 @@ public class BatteryManager {
ServiceManager.getService(BatteryStats.SERVICE_NAME));
mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(
ServiceManager.getService("batteryproperties"));
+ mBatteryService = null;
+ }
+
+ /** @hide */
+ public BatteryManager(IBatteryService service) {
+ super();
+ mBatteryStats = IBatteryStats.Stub.asInterface(
+ ServiceManager.getService(BatteryStats.SERVICE_NAME));
+ mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(
+ ServiceManager.getService("batteryproperties"));
+ mBatteryService = service;
+ }
+
+ /** @hide */
+ public boolean isDockBatterySupported() {
+ try {
+ return mBatteryService != null && mBatteryService.isDockBatterySupported();
+ } catch (RemoteException ex) {
+ // Ignore
+ }
+ return false;
}
/**
@@ -223,8 +333,10 @@ public class BatteryManager {
*
* Returns the requested value, or Long.MIN_VALUE if property not
* supported on this system or on other error.
+ * fromDock determines if the property is query from the normal battery
+ * or the dock battery.
*/
- private long queryProperty(int id) {
+ private long queryProperty(int id, boolean fromDock) {
long ret;
if (mBatteryPropertiesRegistrar == null) {
@@ -234,7 +346,13 @@ public class BatteryManager {
try {
BatteryProperty prop = new BatteryProperty();
- if (mBatteryPropertiesRegistrar.getProperty(id, prop) == 0)
+ final int callResult;
+ if (!fromDock) {
+ callResult = mBatteryPropertiesRegistrar.getProperty(id, prop);
+ } else {
+ callResult = mBatteryPropertiesRegistrar.getDockProperty(id, prop);
+ }
+ if (callResult == 0)
ret = prop.getLong();
else
ret = Long.MIN_VALUE;
@@ -255,7 +373,7 @@ public class BatteryManager {
* @return the property value, or Integer.MIN_VALUE if not supported.
*/
public int getIntProperty(int id) {
- return (int)queryProperty(id);
+ return (int)queryProperty(id, false);
}
/**
@@ -268,6 +386,40 @@ public class BatteryManager {
* @return the property value, or Long.MIN_VALUE if not supported.
*/
public long getLongProperty(int id) {
- return queryProperty(id);
+ return queryProperty(id, false);
+ }
+
+ /**
+ * Return the value of a dock battery property of integer type. If the
+ * platform does not provide the property queried, this value will
+ * be Integer.MIN_VALUE.
+ *
+ * @param id identifier of the requested property
+ *
+ * @return the property value, or Integer.MIN_VALUE if not supported.
+ * @hide
+ */
+ public int getIntDockProperty(int id) {
+ if (!isDockBatterySupported()) {
+ return Integer.MIN_VALUE;
+ }
+ return (int)queryProperty(id, true);
+ }
+
+ /**
+ * Return the value of a dock battery property of long type If the
+ * platform does not provide the property queried, this value will
+ * be Long.MIN_VALUE.
+ *
+ * @param id identifier of the requested property
+ *
+ * @return the property value, or Long.MIN_VALUE if not supported.
+ * @hide
+ */
+ public long getLongDockProperty(int id) {
+ if (!isDockBatterySupported()) {
+ return Long.MIN_VALUE;
+ }
+ return queryProperty(id, true);
}
}
diff --git a/core/java/android/os/BatteryManagerInternal.java b/core/java/android/os/BatteryManagerInternal.java
index f3a95b9..1abb3d5 100644
--- a/core/java/android/os/BatteryManagerInternal.java
+++ b/core/java/android/os/BatteryManagerInternal.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2016 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,6 +44,26 @@ public abstract class BatteryManagerInternal {
public abstract boolean getBatteryLevelLow();
/**
+ * Returns whether dock batteries is supported
+ */
+ public abstract boolean isDockBatterySupported();
+
+ /**
+ * Returns the current dock plug type.
+ */
+ public abstract int getDockPlugType();
+
+ /**
+ * Returns dock battery level as a percentage.
+ */
+ public abstract int getDockBatteryLevel();
+
+ /**
+ * Returns whether we currently consider the dock battery level to be low.
+ */
+ public abstract boolean getDockBatteryLevelLow();
+
+ /**
* Returns a non-zero value if an unsupported charger is attached.
*/
public abstract int getInvalidCharger();
diff --git a/core/java/android/os/BatteryProperties.java b/core/java/android/os/BatteryProperties.java
index 29e868c..cad741a 100644
--- a/core/java/android/os/BatteryProperties.java
+++ b/core/java/android/os/BatteryProperties.java
@@ -1,4 +1,5 @@
/* Copyright 2013, The Android Open Source Project
+ * Copyright 2016, The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,6 +32,16 @@ public class BatteryProperties implements Parcelable {
public int batteryTemperature;
public String batteryTechnology;
+ public boolean dockBatterySupported;
+ public boolean chargerDockAcOnline;
+ public int dockBatteryStatus;
+ public int dockBatteryHealth;
+ public boolean dockBatteryPresent;
+ public int dockBatteryLevel;
+ public int dockBatteryVoltage;
+ public int dockBatteryTemperature;
+ public String dockBatteryTechnology;
+
public BatteryProperties() {
}
@@ -46,6 +57,16 @@ public class BatteryProperties implements Parcelable {
batteryVoltage = other.batteryVoltage;
batteryTemperature = other.batteryTemperature;
batteryTechnology = other.batteryTechnology;
+
+ dockBatterySupported = other.dockBatterySupported;
+ chargerDockAcOnline = other.chargerDockAcOnline;
+ dockBatteryStatus = other.dockBatteryStatus;
+ dockBatteryHealth = other.dockBatteryHealth;
+ dockBatteryPresent = other.dockBatteryPresent;
+ dockBatteryLevel = other.dockBatteryLevel;
+ dockBatteryVoltage = other.dockBatteryVoltage;
+ dockBatteryTemperature = other.dockBatteryTemperature;
+ dockBatteryTechnology = other.dockBatteryTechnology;
}
/*
@@ -65,6 +86,27 @@ public class BatteryProperties implements Parcelable {
batteryVoltage = p.readInt();
batteryTemperature = p.readInt();
batteryTechnology = p.readString();
+
+ dockBatterySupported = p.readInt() == 1 ? true : false;
+ if (dockBatterySupported) {
+ chargerDockAcOnline = p.readInt() == 1 ? true : false;
+ dockBatteryStatus = p.readInt();
+ dockBatteryHealth = p.readInt();
+ dockBatteryPresent = p.readInt() == 1 ? true : false;
+ dockBatteryLevel = p.readInt();
+ dockBatteryVoltage = p.readInt();
+ dockBatteryTemperature = p.readInt();
+ dockBatteryTechnology = p.readString();
+ } else {
+ chargerDockAcOnline = false;
+ dockBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
+ dockBatteryHealth = BatteryManager.BATTERY_HEALTH_UNKNOWN;
+ dockBatteryPresent = false;
+ dockBatteryLevel = 0;
+ dockBatteryVoltage = 0;
+ dockBatteryTemperature = 0;
+ dockBatteryTechnology = "";
+ }
}
public void writeToParcel(Parcel p, int flags) {
@@ -79,6 +121,18 @@ public class BatteryProperties implements Parcelable {
p.writeInt(batteryVoltage);
p.writeInt(batteryTemperature);
p.writeString(batteryTechnology);
+
+ p.writeInt(dockBatterySupported ? 1 : 0);
+ if (dockBatterySupported) {
+ p.writeInt(chargerDockAcOnline ? 1 : 0);
+ p.writeInt(dockBatteryStatus);
+ p.writeInt(dockBatteryHealth);
+ p.writeInt(dockBatteryPresent ? 1 : 0);
+ p.writeInt(dockBatteryLevel);
+ p.writeInt(dockBatteryVoltage);
+ p.writeInt(dockBatteryTemperature);
+ p.writeString(dockBatteryTechnology);
+ }
}
public static final Parcelable.Creator<BatteryProperties> CREATOR
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index f346fe7..a800ed6 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -37,6 +37,7 @@ public class Environment {
private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
private static final String ENV_OEM_ROOT = "OEM_ROOT";
private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
+ private static final String ENV_PREBUNDLED_ROOT = "PREBUNDLED_ROOT";
/** {@hide} */
public static final String DIR_ANDROID = "Android";
@@ -55,6 +56,7 @@ public class Environment {
private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
+ private static final File DIR_PREBUNDLED_ROOT = getDirectory(ENV_PREBUNDLED_ROOT, "/bundled-app");
private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
@@ -165,6 +167,15 @@ public class Environment {
}
/**
+ * Return the root directory for "prebundled" apps. These apps will be installed directly
+ * from this partition but will not be marked as system apps and will hence be uninstallable.
+ * @hide
+ */
+ public static File getPrebundledDirectory() {
+ return DIR_PREBUNDLED_ROOT;
+ }
+
+ /**
* Gets the system directory available for secure storage.
* If Encrypted File system is enabled, it returns an encrypted directory (/data/secure/system).
* Otherwise, it returns the unencrypted /data/system directory.
diff --git a/core/java/android/os/IBatteryPropertiesRegistrar.aidl b/core/java/android/os/IBatteryPropertiesRegistrar.aidl
index fd01802..43b9650 100644
--- a/core/java/android/os/IBatteryPropertiesRegistrar.aidl
+++ b/core/java/android/os/IBatteryPropertiesRegistrar.aidl
@@ -1,5 +1,6 @@
/*
** Copyright 2013, The Android Open Source Project
+** Copyright 2016, The CyanogenMod Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -27,4 +28,5 @@ interface IBatteryPropertiesRegistrar {
void registerListener(IBatteryPropertiesListener listener);
void unregisterListener(IBatteryPropertiesListener listener);
int getProperty(in int id, out BatteryProperty prop);
+ int getDockProperty(in int id, out BatteryProperty prop);
}
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index f55883a..6c7cd6d 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -35,4 +35,5 @@ interface IDeviceIdleController {
long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);
long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason);
void exitIdle(String reason);
+ int getIdleStateDetailed();
}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index cd84c8f..aa3921a 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -440,4 +440,7 @@ interface INetworkManagementService
void addInterfaceToLocalNetwork(String iface, in List<RouteInfo> routes);
void removeInterfaceFromLocalNetwork(String iface);
+
+ void restrictAppOnData(int uid, boolean restrict);
+ void restrictAppOnWlan(int uid, boolean restrict);
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 0f37ac7..4e0f329 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -60,4 +60,14 @@ interface IPowerManager
// sets the attention light (used by phone app only)
void setAttentionLight(boolean on, int color);
+ // update the uids being synchronized by network socket request manager
+ void updateBlockedUids(int uid, boolean isBlocked);
+
+ void setKeyboardVisibility(boolean visible);
+
+ void setKeyboardLight(boolean on, int key);
+
+ oneway void cpuBoost(int duration);
+
+ void wakeUpWithProximityCheck(long time, String reason, String opPackageName);
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 9a1a03e..bbee5a3 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -18,7 +18,10 @@ package android.os;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
import android.util.Log;
/**
@@ -387,7 +390,7 @@ public final class PowerManager {
* @hide
*/
public static final String REBOOT_RECOVERY = "recovery";
-
+
final Context mContext;
final IPowerManager mService;
final Handler mHandler;
@@ -674,6 +677,19 @@ public final class PowerManager {
}
/**
+ * Forces the device to wake up from sleep only if
+ * nothing is blocking the proximity sensor
+ * @see #wakeUp
+ * @hide
+ */
+ public void wakeUpWithProximityCheck(long time, String reason) {
+ try {
+ mService.wakeUpWithProximityCheck(time, reason, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Forces the device to start napping.
* <p>
* If the device is currently awake, starts dreaming, otherwise does nothing.
@@ -1235,4 +1251,68 @@ public final class PowerManager {
}
}
}
+
+ /**
+ * @hide
+ */
+ public void setKeyboardVisibility(boolean visible)
+ {
+ try {
+ if (mService != null) {
+ mService.setKeyboardVisibility(visible);
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * sets the keyboard LED state
+ *
+ * @param on boolean state
+ * @param key 1 for caps, 2 for fn
+ *
+ * {@hide}
+ */
+ public void setKeyboardLight(boolean on, int key)
+ {
+ try {
+ mService.setKeyboardLight(on, key);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Gets the default button brightness value.
+ * @hide
+ */
+ public int getDefaultButtonBrightness() {
+ return mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_buttonBrightnessSettingDefault);
+ }
+
+ /**
+ * Gets the default keyboard brightness value.
+ * @hide
+ */
+ public int getDefaultKeyboardBrightness() {
+ return mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_keyboardBrightnessSettingDefault);
+ }
+
+ /**
+ * Boost the CPU. Boosts the cpu for the given duration in microseconds.
+ *
+ * @param duration in microseconds to boost the CPU
+ *
+ * @hide
+ */
+ public void cpuBoost(int duration)
+ {
+ try {
+ if (mService != null) {
+ mService.cpuBoost(duration);
+ }
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 17bce30..39c12f0 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -117,6 +117,12 @@ public abstract class PowerManagerInternal {
public abstract void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis);
/**
+ * Used by the window manager to tell the power manager that the user is no longer actively
+ * using the device.
+ */
+ public abstract void setUserInactiveOverrideFromWindowManager();
+
+ /**
* Used by device administration to set the maximum screen off timeout.
*
* This method must only be called by the device administration policy manager.
@@ -153,4 +159,11 @@ public abstract class PowerManagerInternal {
public abstract void uidGone(int uid);
public abstract void powerHint(int hintId, int data);
+
+ public abstract boolean setPowerSaveMode(boolean mode);
+
+ public abstract void setFeature(int featureId, int data);
+
+ public abstract int getFeature(int featureId);
+
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 7234e98..65b09eb 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -487,11 +487,12 @@ public class Process {
String abi,
String instructionSet,
String appDataDir,
+ boolean refreshTheme,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
- abi, instructionSet, appDataDir, zygoteArgs);
+ abi, instructionSet, appDataDir, refreshTheme, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
@@ -610,6 +611,7 @@ public class Process {
String abi,
String instructionSet,
String appDataDir,
+ boolean refreshTheme,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
@@ -648,6 +650,9 @@ public class Process {
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
argsForZygote.add("--mount-external-write");
}
+ if (refreshTheme) {
+ argsForZygote.add("--refresh_theme");
+ }
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
//TODO optionally enable debuger
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 0c79094..a10b1ec 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -335,18 +335,27 @@ public class RecoverySystem {
throws IOException {
String filename = packageFile.getCanonicalPath();
- FileWriter uncryptFile = new FileWriter(UNCRYPT_FILE);
- try {
- uncryptFile.write(filename + "\n");
- } finally {
- uncryptFile.close();
- }
- Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
+ final String cryptoStatus = SystemProperties.get("ro.crypto.state", "unsupported");
+ final boolean isEncrypted = "encrypted".equalsIgnoreCase(cryptoStatus);
+
+ if (isEncrypted) {
+ FileWriter uncryptFile = new FileWriter(UNCRYPT_FILE);
+ try {
+ uncryptFile.write(filename + "\n");
+ } finally {
+ uncryptFile.close();
+ }
+ // UNCRYPT_FILE needs to be readable by system server on bootup.
+ if (!UNCRYPT_FILE.setReadable(true, false)) {
+ Log.e(TAG, "Error setting readable for " + UNCRYPT_FILE.getCanonicalPath());
+ }
+ Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
- // If the package is on the /data partition, write the block map file
- // into COMMAND_FILE instead.
- if (filename.startsWith("/data/")) {
- filename = "@/cache/recovery/block.map";
+ // If the package is on the /data partition, write the block map file
+ // into COMMAND_FILE instead.
+ if (filename.startsWith("/data/")) {
+ filename = "@/cache/recovery/block.map";
+ }
}
final String filenameArg = "--update_package=" + filename;
@@ -368,21 +377,21 @@ public class RecoverySystem {
* @throws SecurityException if the current user is not allowed to wipe data.
*/
public static void rebootWipeUserData(Context context) throws IOException {
- rebootWipeUserData(context, false, context.getPackageName());
+ rebootWipeUserData(context, false, context.getPackageName(), false);
}
/** {@hide} */
public static void rebootWipeUserData(Context context, String reason) throws IOException {
- rebootWipeUserData(context, false, reason);
+ rebootWipeUserData(context, false, reason, false);
}
/** {@hide} */
public static void rebootWipeUserData(Context context, boolean shutdown)
throws IOException {
- rebootWipeUserData(context, shutdown, context.getPackageName());
+ rebootWipeUserData(context, shutdown, context.getPackageName(), false);
}
- /**
+ /**
* Reboots the device and wipes the user data and cache
* partitions. This is sometimes called a "factory reset", which
* is something of a misnomer because the system partition is not
@@ -400,8 +409,8 @@ public class RecoverySystem {
*
* @hide
*/
- public static void rebootWipeUserData(Context context, boolean shutdown, String reason)
- throws IOException {
+ public static void rebootWipeUserData(Context context, boolean shutdown, String reason,
+ boolean wipeMedia) throws IOException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
if (um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
throw new SecurityException("Wiping data is not allowed for this user.");
@@ -433,7 +442,13 @@ public class RecoverySystem {
}
final String localeArg = "--locale=" + Locale.getDefault().toString();
- bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);
+
+ String cmd = "--wipe_data\n";
+ if (wipeMedia) {
+ cmd += "--wipe_media\n";
+ }
+
+ bootCommand(context, shutdownArg, cmd, reasonArg, localeArg);
}
/**
@@ -501,6 +516,25 @@ public class RecoverySystem {
Log.e(TAG, "Error reading recovery log", e);
}
+ if (UNCRYPT_FILE.exists()) {
+ String filename = null;
+ try {
+ filename = FileUtils.readTextFile(UNCRYPT_FILE, 0, null);
+ } catch (IOException e) {
+ Log.e(TAG, "Error reading uncrypt file", e);
+ }
+
+ // Remove the OTA package on /data that has been (possibly
+ // partially) processed. (Bug: 24973532)
+ if (filename != null && filename.startsWith("/data")) {
+ if (UNCRYPT_FILE.delete()) {
+ Log.i(TAG, "Deleted: " + filename);
+ } else {
+ Log.e(TAG, "Can't delete: " + filename);
+ }
+ }
+ }
+
// Delete everything in RECOVERY_DIR except those beginning
// with LAST_PREFIX
String[] names = RECOVERY_DIR.list();
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index f10b982..f76a7c2 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1928,9 +1928,9 @@ public final class StrictMode {
// so we'll report it and bail on all of the current strict mode violations
// we currently are maintaining for this thread.
// First, drain the remaining violations from the parcel.
- while (i < numViolations) {
+ i++; // Skip the current entry.
+ for (; i < numViolations; i++) {
info = new ViolationInfo(p, !currentlyGathering);
- i++;
}
// Next clear out all gathered violations.
clearGatheredViolations();
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 045c1e8..5b532a3 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -489,6 +489,18 @@ public class UserManager {
*/
public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
+ /**
+ * Specifies if the user is not allowed to use SU commands.
+ * The default value is <code>false</code>.
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ * @hide
+ */
+ public static final String DISALLOW_SU = "no_su";
+
/** @hide */
public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
/** @hide */
@@ -853,6 +865,7 @@ public class UserManager {
Bundle guestRestrictions = mService.getDefaultGuestRestrictions();
guestRestrictions.putBoolean(DISALLOW_SMS, true);
guestRestrictions.putBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
+ guestRestrictions.putBoolean(DISALLOW_SU, true);
mService.setUserRestrictions(guestRestrictions, guest.id);
} catch (RemoteException re) {
Log.w(TAG, "Could not update guest restrictions");
@@ -892,6 +905,7 @@ public class UserManager {
private static void addDefaultUserRestrictions(Bundle restrictions) {
restrictions.putBoolean(DISALLOW_OUTGOING_CALLS, true);
restrictions.putBoolean(DISALLOW_SMS, true);
+ restrictions.putBoolean(DISALLOW_SU, true);
}
/**
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index 9114107..db0b0fd 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -47,6 +47,8 @@ public class DiskInfo implements Parcelable {
public static final int FLAG_DEFAULT_PRIMARY = 1 << 1;
public static final int FLAG_SD = 1 << 2;
public static final int FLAG_USB = 1 << 3;
+ public static final int FLAG_EMMC = 1 << 4;
+ public static final int FLAG_NON_REMOVABLE = 1 << 5;
public final String id;
public final int flags;
@@ -128,6 +130,10 @@ public class DiskInfo implements Parcelable {
return (flags & FLAG_USB) != 0;
}
+ public boolean isNonRemovable() {
+ return (flags & FLAG_NON_REMOVABLE) != 0;
+ }
+
@Override
public String toString() {
final CharArrayWriter writer = new CharArrayWriter();
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 9f71ce1..5f84351 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -645,6 +645,24 @@ public interface IMountService extends IInterface {
return _result;
}
+ public int encryptWipeStorage(int type, String password) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ int _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(type);
+ _data.writeString(password);
+ mRemote.transact(Stub.TRANSACTION_encryptWipeStorage, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
public int changeEncryptionPassword(int type, String password) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
@@ -1326,6 +1344,8 @@ public interface IMountService extends IInterface {
static final int TRANSACTION_benchmark = IBinder.FIRST_CALL_TRANSACTION + 59;
static final int TRANSACTION_setDebugFlags = IBinder.FIRST_CALL_TRANSACTION + 60;
+ static final int TRANSACTION_encryptWipeStorage = IBinder.FIRST_CALL_TRANSACTION + 61;
+
static final int TRANSACTION_createNewUserDir = IBinder.FIRST_CALL_TRANSACTION + 62;
static final int TRANSACTION_deleteUserKey = IBinder.FIRST_CALL_TRANSACTION + 63;
@@ -1631,6 +1651,15 @@ public interface IMountService extends IInterface {
reply.writeInt(result);
return true;
}
+ case TRANSACTION_encryptWipeStorage: {
+ data.enforceInterface(DESCRIPTOR);
+ int type = data.readInt();
+ String password = data.readString();
+ int result = encryptWipeStorage(type, password);
+ reply.writeNoException();
+ reply.writeInt(result);
+ return true;
+ }
case TRANSACTION_changeEncryptionPassword: {
data.enforceInterface(DESCRIPTOR);
int type = data.readInt();
@@ -2065,7 +2094,8 @@ public interface IMountService extends IInterface {
* Returns whether or not the external storage is emulated.
*/
public boolean isExternalStorageEmulated() throws RemoteException;
-
+ /** The volume has been encrypted succesfully and MDTP state is 'activated'. */
+ static final int ENCRYPTION_STATE_OK_MDTP_ACTIVATED = 2;
/** The volume is not encrypted. */
static final int ENCRYPTION_STATE_NONE = 1;
/** The volume has been encrypted succesfully. */
@@ -2078,6 +2108,8 @@ public interface IMountService extends IInterface {
static final int ENCRYPTION_STATE_ERROR_INCONSISTENT = -3;
/** Underlying data is corrupt */
static final int ENCRYPTION_STATE_ERROR_CORRUPT = -4;
+ /** The volume is in a bad state and MDTP state is 'activated'.*/
+ static final int ENCRYPTION_STATE_ERROR_MDTP_ACTIVATED = -5;
/**
* Determines the encryption state of the volume.
@@ -2096,6 +2128,11 @@ public interface IMountService extends IInterface {
public int encryptStorage(int type, String password) throws RemoteException;
/**
+ * Encrypts and wipes storage.
+ */
+ public int encryptWipeStorage(int type, String password) throws RemoteException;
+
+ /**
* Changes the encryption password.
*/
public int changeEncryptionPassword(int type, String password)
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 1408202..4dbd0a6 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -196,15 +196,20 @@ public class StorageVolume implements Parcelable {
}
/**
- * Parse and return volume UUID as FAT volume ID, or return -1 if unable to
+ * Parse and return volume UUID as volume ID, or return -1 if unable to
* parse or UUID is unknown.
*/
- public int getFatVolumeId() {
- if (mFsUuid == null || mFsUuid.length() != 9) {
+ public int getVolumeId() {
+ String id = mFsUuid;
+ if (id == null) {
return -1;
}
+ id = id.replace("-", "");
+ if (id.length() > 8) {
+ id = id.substring(0, 8);
+ }
try {
- return (int) Long.parseLong(mFsUuid.replace("-", ""), 16);
+ return (int) Long.parseLong(id, 16);
} catch (NumberFormatException e) {
return -1;
}
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index 3d57b4d..1aec3ec 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -285,6 +285,22 @@ public abstract class DialogPreference extends Preference implements
* @param state Optional instance state to restore on the dialog
*/
protected void showDialog(Bundle state) {
+ // Create the dialog
+ final Dialog dialog = mDialog = createDialog();
+ if (state != null) {
+ dialog.onRestoreInstanceState(state);
+ }
+ if (needInputMethod()) {
+ requestInputMethod(dialog);
+ }
+ dialog.setOnDismissListener(this);
+ dialog.show();
+ }
+
+ /**
+ * @hide
+ */
+ protected Dialog createDialog() {
Context context = getContext();
mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
@@ -306,17 +322,8 @@ public abstract class DialogPreference extends Preference implements
onPrepareDialogBuilder(mBuilder);
getPreferenceManager().registerOnActivityDestroyListener(this);
-
- // Create the dialog
- final Dialog dialog = mDialog = mBuilder.create();
- if (state != null) {
- dialog.onRestoreInstanceState(state);
- }
- if (needInputMethod()) {
- requestInputMethod(dialog);
- }
- dialog.setOnDismissListener(this);
- dialog.show();
+
+ return mBuilder.create();
}
/**
diff --git a/core/java/android/preference/MultiSelectListPreference.java b/core/java/android/preference/MultiSelectListPreference.java
index 138bd87..6acfd8d 100644..100755
--- a/core/java/android/preference/MultiSelectListPreference.java
+++ b/core/java/android/preference/MultiSelectListPreference.java
@@ -220,7 +220,7 @@ public class MultiSelectListPreference extends DialogPreference {
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
final CharSequence[] defaultValues = a.getTextArray(index);
- final int valueCount = defaultValues.length;
+ final int valueCount = defaultValues != null ? defaultValues.length : 0;
final Set<String> result = new HashSet<String>();
for (int i = 0; i < valueCount; i++) {
@@ -247,7 +247,20 @@ public class MultiSelectListPreference extends DialogPreference {
myState.values = getValues();
return myState;
}
-
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (!state.getClass().equals(SavedState.class)) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ setValues(myState.values);
+ }
+
private static class SavedState extends BaseSavedState {
Set<String> values;
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 3b482eb..b15a7e5 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -1377,10 +1377,18 @@ public class Preference implements Comparable<Preference> {
mDefaultValue = defaultValue;
}
+ /**
+ * Returns whether the preference can be found in persistent storage
+ * @hide
+ */
+ protected boolean isPersisted() {
+ return getSharedPreferences().contains(mKey);
+ }
+
private void dispatchSetInitialValue() {
// By now, we know if we are persistent.
final boolean shouldPersist = shouldPersist();
- if (!shouldPersist || !getSharedPreferences().contains(mKey)) {
+ if (!shouldPersist || !isPersisted()) {
if (mDefaultValue != null) {
onSetInitialValue(false, mDefaultValue);
}
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index 66642de..db04c71 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -214,6 +214,9 @@ public abstract class PreferenceFragment extends Fragment implements
@Override
public void onDestroyView() {
+ if (mList != null) {
+ mList.setOnKeyListener(null);
+ }
mList = null;
mHandler.removeCallbacks(mRequestFocus);
mHandler.removeMessages(MSG_BIND_PREFERENCES);
diff --git a/core/java/android/preference/PreferenceGroup.java b/core/java/android/preference/PreferenceGroup.java
index 5e84086..f17506b 100644
--- a/core/java/android/preference/PreferenceGroup.java
+++ b/core/java/android/preference/PreferenceGroup.java
@@ -148,16 +148,15 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
}
}
- int insertionIndex = Collections.binarySearch(mPreferenceList, preference);
- if (insertionIndex < 0) {
- insertionIndex = insertionIndex * -1 - 1;
- }
-
if (!onPrepareAddPreference(preference)) {
return false;
}
synchronized(this) {
+ int insertionIndex = Collections.binarySearch(mPreferenceList, preference);
+ if (insertionIndex < 0) {
+ insertionIndex = insertionIndex * -1 - 1;
+ }
mPreferenceList.add(insertionIndex, preference);
}
diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java
index a76bb09..c730329 100644
--- a/core/java/android/preference/RingtonePreference.java
+++ b/core/java/android/preference/RingtonePreference.java
@@ -48,8 +48,10 @@ public class RingtonePreference extends Preference implements
private int mRingtoneType;
private boolean mShowDefault;
private boolean mShowSilent;
+ private int mDialogStyle;
private int mRequestCode;
+ private int mSubscriptionID = 0; /* Sub-1 by default */
public RingtonePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
@@ -62,6 +64,8 @@ public class RingtonePreference extends Preference implements
true);
mShowSilent = a.getBoolean(com.android.internal.R.styleable.RingtonePreference_showSilent,
true);
+ mDialogStyle = a.getResourceId(
+ com.android.internal.R.styleable.RingtonePreference_dialogStyle, 0);
a.recycle();
}
@@ -98,6 +102,28 @@ public class RingtonePreference extends Preference implements
}
/**
+ * Returns the subscription ID.
+ *
+ * @return The current subscription ID.
+ * @see #setSubId(int)
+ * @hide
+ */
+ public int getSubId() {
+ return mSubscriptionID;
+ }
+
+ /**
+ * Sets the subscription ID.
+ *
+ * @param subId subscription ID.
+ * @see #getSubId(int)
+ * @hide
+ */
+ public void setSubId(int subId) {
+ mSubscriptionID = subId;
+ }
+
+ /**
* Returns whether to a show an item for the default sound/ringtone.
*
* @return Whether to show an item for the default sound/ringtone.
@@ -136,6 +162,27 @@ public class RingtonePreference extends Preference implements
mShowSilent = showSilent;
}
+ /**
+ * Returns the resource id style of the ringtone dialog.
+ *
+ * @return The resource id of the style
+ * @hide
+ */
+ public int getDialogStyle() {
+ return mDialogStyle;
+ }
+
+ /**
+ * Sets the resource id style of the ringtone dialog.
+ *
+ * @param dialogStyle The resource id of the style.
+ * @see RingtoneManager#EXTRA_RINGTONE_DIALOG_THEME
+ * @hide
+ */
+ public void setDialogStyle(int dialogStyle) {
+ mDialogStyle = dialogStyle;
+ }
+
@Override
protected void onClick() {
// Launch the ringtone picker
@@ -163,8 +210,17 @@ public class RingtonePreference extends Preference implements
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, mShowDefault);
if (mShowDefault) {
- ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI,
+ if (getRingtoneType() == RingtoneManager.TYPE_RINGTONE) {
+ ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI,
+ RingtoneManager.getActualRingtoneUriBySubId(getContext(), getSubId()));
+ } else {
+ ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI,
RingtoneManager.getDefaultUri(getRingtoneType()));
+ }
+ }
+ if (mDialogStyle != 0) {
+ ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DIALOG_THEME,
+ mDialogStyle);
}
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, mShowSilent);
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 2445bc2..e5f71a0 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -59,6 +59,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
private final NotificationManager mNotificationManager;
private final int mStreamType;
private final int mMaxStreamVolume;
+ private final boolean mVoiceCapable;
private boolean mAffectedByRingerMode;
private boolean mNotificationOrRing;
private final Receiver mReceiver = new Receiver();
@@ -110,12 +111,19 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
}
mDefaultUri = defaultUri;
+ mVoiceCapable = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_voice_capable);
}
private static boolean isNotificationOrRing(int stream) {
return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION;
}
+ private boolean isNotificationStreamLinked() {
+ return mVoiceCapable && Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.VOLUME_LINK_NOTIFICATION, 1) == 1;
+ }
+
public void setSeekBar(SeekBar seekBar) {
if (mSeekBar != null) {
mSeekBar.setOnSeekBarChangeListener(null);
@@ -139,13 +147,19 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
mSeekBar.setProgress(mLastAudibleStreamVolume);
} else if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
mSeekBar.setProgress(0);
+ mSeekBar.setEnabled(mStreamType == AudioManager.STREAM_RING);
} else if (mMuted) {
mSeekBar.setProgress(0);
} else {
+ mSeekBar.setEnabled(enableSeekBar());
mSeekBar.setProgress(mLastProgress > -1 ? mLastProgress : mOriginalStreamVolume);
}
}
+ private boolean enableSeekBar() {
+ return !(mStreamType == AudioManager.STREAM_NOTIFICATION && isNotificationStreamLinked());
+ }
+
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
@@ -250,7 +264,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
- if (fromTouch) {
+ if (fromTouch && enableSeekBar()) {
postSetVolume(progress);
}
if (mCallback != null) {
@@ -398,10 +412,11 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
updateVolumeSlider(streamType, streamValue);
} else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
+ final int oldRingerMode = mRingerMode;
if (mNotificationOrRing) {
mRingerMode = mAudioManager.getRingerModeInternal();
}
- if (mAffectedByRingerMode) {
+ if (mAffectedByRingerMode && oldRingerMode != mRingerMode) {
updateSlider();
}
} else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) {
@@ -415,7 +430,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
private void updateVolumeSlider(int streamType, int streamValue) {
- final boolean streamMatch = mNotificationOrRing ? isNotificationOrRing(streamType)
+ final boolean streamMatch = mNotificationOrRing && isNotificationStreamLinked()
+ ? isNotificationOrRing(streamType)
: (streamType == mStreamType);
if (mSeekBar != null && streamMatch && streamValue != -1) {
final boolean muted = mAudioManager.isStreamMute(mStreamType)
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 7d05522..299a95c 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -244,6 +244,7 @@ public class Browser {
*/
public static final Cursor getAllBookmarks(ContentResolver cr) throws
IllegalStateException {
+ android.util.SeempLog.record(32);
return new MatrixCursor(new String[]{Bookmarks.URL}, 0);
}
@@ -256,6 +257,7 @@ public class Browser {
*/
public static final Cursor getAllVisitedUrls(ContentResolver cr) throws
IllegalStateException {
+ android.util.SeempLog.record(33);
return new MatrixCursor(new String[]{Combined.URL}, 0);
}
@@ -264,6 +266,7 @@ public class Browser {
}
private static final Cursor getVisitedLike(ContentResolver cr, String url) {
+ android.util.SeempLog.record(34);
boolean secure = false;
String compareString = url;
if (compareString.startsWith("http://")) {
@@ -324,6 +327,7 @@ public class Browser {
*/
@Deprecated
public static final String[] getVisitedHistory(ContentResolver cr) {
+ android.util.SeempLog.record(35);
return new String[0];
}
@@ -359,6 +363,7 @@ public class Browser {
* @removed
*/
public static final void clearHistory(ContentResolver cr) {
+ android.util.SeempLog.record(37);
}
@@ -420,6 +425,7 @@ public class Browser {
*/
public static final void requestAllIcons(ContentResolver cr, String where,
WebIconDatabase.IconListener listener) {
+ android.util.SeempLog.record(36);
// Do nothing: this is no longer used.
}
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index aa22041..2ede026 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -871,6 +871,7 @@ public final class CalendarContract {
* @return A Cursor containing all attendees for the event
*/
public static final Cursor query(ContentResolver cr, long eventId, String[] projection) {
+ android.util.SeempLog.record(54);
String[] attArgs = {Long.toString(eventId)};
return cr.query(CONTENT_URI, projection, ATTENDEES_WHERE, attArgs /* selection args */,
null /* sort order */);
@@ -1750,6 +1751,7 @@ public final class CalendarContract {
*/
public static final Cursor query(ContentResolver cr, String[] projection,
long begin, long end) {
+ android.util.SeempLog.record(54);
Uri.Builder builder = CONTENT_URI.buildUpon();
ContentUris.appendId(builder, begin);
ContentUris.appendId(builder, end);
@@ -1779,6 +1781,7 @@ public final class CalendarContract {
*/
public static final Cursor query(ContentResolver cr, String[] projection,
long begin, long end, String searchQuery) {
+ android.util.SeempLog.record(54);
Uri.Builder builder = CONTENT_SEARCH_URI.buildUpon();
ContentUris.appendId(builder, begin);
ContentUris.appendId(builder, end);
@@ -2029,6 +2032,7 @@ public final class CalendarContract {
*/
public static final Cursor query(ContentResolver cr, int startDay, int numDays,
String[] projection) {
+ android.util.SeempLog.record(54);
if (numDays < 1) {
return null;
}
@@ -2112,6 +2116,7 @@ public final class CalendarContract {
* @return A Cursor containing all reminders for the event
*/
public static final Cursor query(ContentResolver cr, long eventId, String[] projection) {
+ android.util.SeempLog.record(54);
String[] remArgs = {Long.toString(eventId)};
return cr.query(CONTENT_URI, projection, REMINDERS_WHERE, remArgs /*selection args*/,
null /* sort order */);
@@ -2262,6 +2267,7 @@ public final class CalendarContract {
*/
public static final Uri insert(ContentResolver cr, long eventId,
long begin, long end, long alarmTime, int minutes) {
+ android.util.SeempLog.record(51);
ContentValues values = new ContentValues();
values.put(CalendarAlerts.EVENT_ID, eventId);
values.put(CalendarAlerts.BEGIN, begin);
@@ -2289,6 +2295,7 @@ public final class CalendarContract {
* @hide
*/
public static final long findNextAlarmTime(ContentResolver cr, long millis) {
+ android.util.SeempLog.record(53);
String selection = ALARM_TIME + ">=" + millis;
// TODO: construct an explicit SQL query so that we can add
// "LIMIT 1" to the end and get just one result.
@@ -2412,6 +2419,7 @@ public final class CalendarContract {
*/
public static final boolean alarmExists(ContentResolver cr, long eventId,
long begin, long alarmTime) {
+ android.util.SeempLog.record(52);
// TODO: construct an explicit SQL query so that we can add
// "LIMIT 1" to the end and get just one result.
String[] projection = new String[] { ALARM_TIME };
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 4f880b1..f6c68dd 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -27,6 +27,7 @@ import android.database.Cursor;
import android.location.Country;
import android.location.CountryDetector;
import android.net.Uri;
+import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.ContactsContract.CommonDataKinds.Callable;
@@ -164,6 +165,10 @@ public class CallLog {
public static final int MISSED_TYPE = 3;
/** Call log type for voicemails. */
public static final int VOICEMAIL_TYPE = 4;
+ /** Call log type for blacklisted calls
+ * @hide
+ */
+ public static final int BLACKLIST_TYPE = 5;
/**
* Bit-mask describing features of the call (e.g. video).
@@ -397,6 +402,12 @@ public class CallLog {
private static final int MIN_DURATION_FOR_NORMALIZED_NUMBER_UPDATE_MS = 1000 * 10;
/**
+ * If a call has an origin inside of the OS, this column will be filled out.
+ * <P>Type: String </P>
+ */
+ private static final String ORIGIN = "origin";
+
+ /**
* Adds a call to the call log.
*
* @param ci the CallerInfo object to get the target contact from. Can be null
@@ -413,15 +424,16 @@ public class CallLog {
* @param duration call duration in seconds
* @param dataUsage data usage for the call in bytes, null if data usage was not tracked for
* the call.
+ * @param callExtras Bundle of extra data from the call.
* @result The URI of the call log entry belonging to the user that made or received this
* call.
* {@hide}
*/
public static Uri addCall(CallerInfo ci, Context context, String number,
int presentation, int callType, int features, PhoneAccountHandle accountHandle,
- long start, int duration, Long dataUsage) {
+ long start, int duration, Long dataUsage, Bundle callExtras) {
return addCall(ci, context, number, presentation, callType, features, accountHandle,
- start, duration, dataUsage, false, false);
+ start, duration, dataUsage, false, false, callExtras);
}
@@ -444,16 +456,17 @@ public class CallLog {
* the call.
* @param addForAllUsers If true, the call is added to the call log of all currently
* running users. The caller must have the MANAGE_USERS permission if this is true.
- *
+ * @param callExtras Bundle of extra data from the call.
* @result The URI of the call log entry belonging to the user that made or received this
* call.
* {@hide}
*/
public static Uri addCall(CallerInfo ci, Context context, String number,
int presentation, int callType, int features, PhoneAccountHandle accountHandle,
- long start, int duration, Long dataUsage, boolean addForAllUsers) {
+ long start, int duration, Long dataUsage, boolean addForAllUsers,
+ Bundle callExtras) {
return addCall(ci, context, number, presentation, callType, features, accountHandle,
- start, duration, dataUsage, addForAllUsers, false);
+ start, duration, dataUsage, addForAllUsers, false, callExtras);
}
/**
@@ -477,6 +490,7 @@ public class CallLog {
* running users. The caller must have the MANAGE_USERS permission if this is true.
* @param is_read Flag to show if the missed call log has been read by the user or not.
* Used for call log restore of missed calls.
+ * @param callExtras Bundle of extra data from the call.
*
* @result The URI of the call log entry belonging to the user that made or received this
* call.
@@ -484,7 +498,8 @@ public class CallLog {
*/
public static Uri addCall(CallerInfo ci, Context context, String number,
int presentation, int callType, int features, PhoneAccountHandle accountHandle,
- long start, int duration, Long dataUsage, boolean addForAllUsers, boolean is_read) {
+ long start, int duration, Long dataUsage, boolean addForAllUsers, boolean is_read,
+ Bundle callExtras) {
final ContentResolver resolver = context.getContentResolver();
int numberPresentation = PRESENTATION_ALLOWED;
@@ -543,6 +558,9 @@ public class CallLog {
if (dataUsage != null) {
values.put(DATA_USAGE, dataUsage);
}
+ if (callExtras != null && callExtras.containsKey(PhoneConstants.EXTRA_CALL_ORIGIN)) {
+ values.put(ORIGIN, callExtras.getString(PhoneConstants.EXTRA_CALL_ORIGIN));
+ }
values.put(PHONE_ACCOUNT_COMPONENT_NAME, accountComponentString);
values.put(PHONE_ACCOUNT_ID, accountId);
values.put(PHONE_ACCOUNT_ADDRESS, accountAddress);
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 8ce1cbf..0e7f487 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1119,7 +1119,15 @@ public final class ContactsContract {
public static final String SORT_KEY_ALTERNATIVE = "sort_key_alt";
}
- interface ContactCounts {
+ /**
+ * URI parameter and cursor extras that return counts of rows grouped by the
+ * address book index, which is usually the first letter of the sort key.
+ * When this parameter is supplied, the row counts are returned in the
+ * cursor extras bundle.
+ *
+ * @hide
+ */
+ public interface ContactCounts {
/**
* Add this query parameter to a URI to get back row counts grouped by the address book
@@ -1497,6 +1505,7 @@ public final class ContactsContract {
* {@link #CONTENT_LOOKUP_URI} to attempt refreshing.
*/
public static Uri getLookupUri(ContentResolver resolver, Uri contactUri) {
+ android.util.SeempLog.record(86);
final Cursor c = resolver.query(contactUri, new String[] {
Contacts.LOOKUP_KEY, Contacts._ID
}, null, null, null);
@@ -1524,6 +1533,7 @@ public final class ContactsContract {
* provided parameters.
*/
public static Uri getLookupUri(long contactId, String lookupKey) {
+ android.util.SeempLog.record(86);
if (TextUtils.isEmpty(lookupKey)) {
return null;
}
@@ -1537,6 +1547,7 @@ public final class ContactsContract {
* Returns null if the contact cannot be found.
*/
public static Uri lookupContact(ContentResolver resolver, Uri lookupUri) {
+ android.util.SeempLog.record(87);
if (lookupUri == null) {
return null;
}
@@ -1999,6 +2010,7 @@ public final class ContactsContract {
*/
public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri,
boolean preferHighres) {
+ android.util.SeempLog.record(88);
if (preferHighres) {
final Uri displayPhotoUri = Uri.withAppendedPath(contactUri,
Contacts.Photo.DISPLAY_PHOTO);
@@ -2046,6 +2058,7 @@ public final class ContactsContract {
* of the thumbnail the high-res picture is preferred
*/
public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri) {
+ android.util.SeempLog.record(88);
return openContactPhotoInputStream(cr, contactUri, false);
}
}
@@ -2738,6 +2751,7 @@ public final class ContactsContract {
* entry of the given {@link RawContacts} entry.
*/
public static Uri getContactLookupUri(ContentResolver resolver, Uri rawContactUri) {
+ android.util.SeempLog.record(89);
// TODO: use a lighter query by joining rawcontacts with contacts in provider
final Uri dataUri = Uri.withAppendedPath(rawContactUri, Data.CONTENT_DIRECTORY);
final Cursor cursor = resolver.query(dataUri, new String[] {
@@ -4684,6 +4698,7 @@ public final class ContactsContract {
* </p>
*/
public static Uri getContactLookupUri(ContentResolver resolver, Uri dataUri) {
+ android.util.SeempLog.record(89);
final Cursor cursor = resolver.query(dataUri, new String[] {
RawContacts.CONTACT_ID, Contacts.LOOKUP_KEY
}, null, null, null);
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index b2d9b93..961eb19 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -593,6 +593,11 @@ public final class Downloads {
public static final int STATUS_QUEUED_FOR_WIFI = 196;
/**
+ * This download is paused by manual.
+ */
+ public static final int STATUS_PAUSED_BY_MANUAL = 197;
+
+ /**
* This download couldn't be completed due to insufficient storage
* space. Typically, this is because the SD card is full.
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 14f8fdd..3ab16fe 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -64,11 +64,14 @@ import com.android.internal.widget.ILockSettings;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.regex.Pattern;
/**
* The Settings provider contains global system-level device preferences.
@@ -657,6 +660,19 @@ public final class Settings {
/**
* @hide
+ * Activity Action: Show the "app ops" details screen.
+ * <p>
+ * Input: The Intent's data URI specifies the application package name
+ * to be shown, with the "package" scheme. That is "package:com.my.app".
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_APP_OPS_DETAILS_SETTINGS =
+ "android.settings.APP_OPS_DETAILS_SETTINGS";
+
+ /**
+ * @hide
* Activity Action: Show the "app ops" settings screen.
* <p>
* Input: Nothing.
@@ -1492,6 +1508,11 @@ public final class Settings {
// At one time in System, then Global, but now back in Secure
MOVED_TO_SECURE.add(Secure.INSTALL_NON_MARKET_APPS);
+
+ MOVED_TO_SECURE.add(System.KEYBOARD_BRIGHTNESS);
+ MOVED_TO_SECURE.add(System.BUTTON_BRIGHTNESS);
+ MOVED_TO_SECURE.add(System.BUTTON_BACKLIGHT_TIMEOUT);
+ MOVED_TO_SECURE.add(Secure.VOLUME_LINK_NOTIFICATION);
}
private static final HashSet<String> MOVED_TO_GLOBAL;
@@ -1583,6 +1604,44 @@ public final class Settings {
}
};
+ /**
+ * Put a delimited list as a string
+ * @param resolver to access the database with
+ * @param name to store
+ * @param delimiter to split
+ * @param list to join and store
+ * @hide
+ */
+ public static void putListAsDelimitedString(ContentResolver resolver, String name,
+ String delimiter, List<String> list) {
+ String store = TextUtils.join(delimiter, list);
+ putString(resolver, name, store);
+ }
+
+ /**
+ * Get a delimited string returned as a list
+ * @param resolver to access the database with
+ * @param name to store
+ * @param delimiter to split the list with
+ * @return list of strings for a specific Settings.Secure item
+ * @hide
+ */
+ public static List<String> getDelimitedStringAsList(ContentResolver resolver, String name,
+ String delimiter) {
+ String baseString = getString(resolver, name);
+ List<String> list = new ArrayList<String>();
+ if (!TextUtils.isEmpty(baseString)) {
+ final String[] array = TextUtils.split(baseString, Pattern.quote(delimiter));
+ for (String item : array) {
+ if (TextUtils.isEmpty(item)) {
+ continue;
+ }
+ list.add(item);
+ }
+ }
+ return list;
+ }
+
/** @hide */
public static void getMovedToGlobalSettings(Set<String> outKeySet) {
outKeySet.addAll(MOVED_TO_GLOBAL);
@@ -1612,6 +1671,7 @@ public final class Settings {
/** @hide */
public static String getStringForUser(ContentResolver resolver, String name,
int userHandle) {
+ android.util.SeempLog.record(android.util.SeempLog.getSeempGetApiIdFromValue(name));
if (MOVED_TO_SECURE.contains(name)) {
Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+ " to android.provider.Settings.Secure, returning read-only value.");
@@ -1639,6 +1699,7 @@ public final class Settings {
/** @hide */
public static boolean putStringForUser(ContentResolver resolver, String name, String value,
int userHandle) {
+ android.util.SeempLog.record(android.util.SeempLog.getSeempPutApiIdFromValue(name));
if (MOVED_TO_SECURE.contains(name)) {
Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+ " to android.provider.Settings.Secure, value is unchanged.");
@@ -2433,6 +2494,31 @@ public final class Settings {
public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1;
/**
+ * The keyboard brightness to be used while the screen is on.
+ * Valid value range is between 0 and {@link PowerManager#getMaximumKeyboardBrightness()}
+ * @deprecated
+ * @hide
+ */
+ public static final String KEYBOARD_BRIGHTNESS = "keyboard_brightness";
+
+ /**
+ * The button brightness to be used while the screen is on or after a button press,
+ * depending on the value of {@link BUTTON_BACKLIGHT_TIMEOUT}.
+ * Valid value range is between 0 and {@link PowerManager#getMaximumButtonBrightness()}
+ * @deprecated
+ * @hide
+ */
+ public static final String BUTTON_BRIGHTNESS = "button_brightness";
+
+ /**
+ * The time in ms to keep the button backlight on after pressing a button.
+ * A value of 0 will keep the buttons on for as long as the screen is on.
+ * @deprecated
+ * @hide
+ */
+ public static final String BUTTON_BACKLIGHT_TIMEOUT = "button_backlight_timeout";
+
+ /**
* Control whether the process CPU usage meter should be shown.
*
* @deprecated Use {@link Global#SHOW_PROCESSES} instead
@@ -2596,6 +2682,55 @@ public final class Settings {
private static final Validator NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR = sBooleanValidator;
/**
+ * Whether the blacklisting feature for phone calls is enabled
+ * @hide
+ */
+ public static final String PHONE_BLACKLIST_ENABLED = "phone_blacklist_enabled";
+
+ /**
+ * Whether a notification should be shown when a call/message is blocked
+ * @hide
+ */
+ public static final String PHONE_BLACKLIST_NOTIFY_ENABLED = "phone_blacklist_notify_enabled";
+
+ /**
+ * Whether the blacklisting feature for phone calls from private numbers is enabled
+ * @hide
+ */
+ public static final String PHONE_BLACKLIST_PRIVATE_NUMBER_MODE = "phone_blacklist_private_number_enabled";
+
+ /**
+ * Whether the blacklisting feature for phone calls from unknown numbers is enabled
+ * @hide
+ */
+ public static final String PHONE_BLACKLIST_UNKNOWN_NUMBER_MODE = "phone_blacklist_unknown_number_enabled";
+
+ /**
+ * Constants to be used for {@link PHONE_BLACKLIST_PRIVATE_NUMBER_MODE} and
+ * {@link PHONE_BLACKLIST_UNKNOWN_NUMBER_MODE}.
+ * @hide
+ */
+ public static final int BLACKLIST_DO_NOT_BLOCK = 0;
+ /**
+ * @hide
+ */
+ public static final int BLACKLIST_BLOCK = 1;
+ /**
+ * @hide
+ */
+ public static final int BLACKLIST_PHONE_SHIFT = 0;
+ /**
+ * @hide
+ */
+ public static final int BLACKLIST_MESSAGE_SHIFT = 4;
+
+ /**
+ * Whether the regex blacklisting feature for phone calls is enabled
+ * @hide
+ */
+ public static final String PHONE_BLACKLIST_REGEX_ENABLED = "phone_blacklist_regex_enabled";
+
+ /**
* Whether silent mode should allow vibration feedback. This is used
* internally in AudioService and the Sound settings activity to
* coordinate decoupling of vibrate and silent modes. This setting
@@ -2644,6 +2779,30 @@ public final class Settings {
private static final Validator RINGTONE_VALIDATOR = sUriValidator;
/**
+ * Persistent store for the SIM-2 ringtone URI.
+ * <p>
+ * If you need to play SIM-2 ringtone at any given time, it is recommended
+ * you give {@link #DEFAULT_RINGTONE_URI_2} to the media player. It will resolve
+ * to the set default ringtone at the time of playing.
+ *
+ * @see #DEFAULT_RINGTONE_URI_2
+ * @hide
+ */
+ public static final String RINGTONE_2 = "ringtone_2";
+
+ /**
+ * Persistent store for the SIM-3 ringtone URI.
+ * <p>
+ * If you need to play SIM-3 ringtone at any given time, it is recommended
+ * you give {@link #DEFAULT_RINGTONE_URI_3} to the media player. It will resolve
+ * to the set default ringtone at the time of playing.
+ *
+ * @see #DEFAULT_RINGTONE_URI_3
+ * @hide
+ */
+ public static final String RINGTONE_3 = "ringtone_3";
+
+ /**
* A {@link Uri} that will point to the current default ringtone at any
* given time.
* <p>
@@ -2654,6 +2813,39 @@ public final class Settings {
public static final Uri DEFAULT_RINGTONE_URI = getUriFor(RINGTONE);
/**
+ * A {@link Uri} that will point to the current SIM-2 ringtone at any
+ * given time.
+ * <p>
+ * If the current default ringtone is in the DRM provider and the caller
+ * does not have permission, the exception will be a
+ * FileNotFoundException.
+ *
+ * @hide
+ */
+ public static final Uri DEFAULT_RINGTONE_URI_2 = getUriFor(RINGTONE_2);
+
+ /**
+ * A {@link Uri} that will point to the current SIM-3 ringtone at any
+ * given time.
+ * <p>
+ * If the current default ringtone is in the DRM provider and the caller
+ * does not have permission, the exception will be a
+ * FileNotFoundException.
+ *
+ * @hide
+ */
+ public static final Uri DEFAULT_RINGTONE_URI_3 = getUriFor(RINGTONE_3);
+
+ /**
+ * Maximum number of ringtones supported.
+ * <p>
+ * Maximum number of ringtones supported by settings. Increment this
+ * if a new URI needs to be added for ringtone.
+ * @hide
+ */
+ public static final int MAX_NUM_RINGTONES = 3;
+
+ /**
* Persistent store for the system-wide default notification sound.
*
* @see #RINGTONE
@@ -2723,6 +2915,15 @@ public final class Settings {
private static final Validator TEXT_AUTO_CAPS_VALIDATOR = sBooleanValidator;
/**
+ * Setting to show if system is in power off alarm mode. 1 = true, 0 = false
+ * @hide
+ */
+ public static final String POWER_OFF_ALARM_MODE = "power_off_alarm_mode";
+
+ /** Validator for POWER_OFF_ALARM_MODE */
+ private static final Validator POWER_OFF_ALARM_MODE_VALIDATOR = sBooleanValidator;
+
+ /**
* Setting to enable Auto Punctuate in text editors. 1 = On, 0 = Off. This
* feature converts two spaces to a "." and space.
*/
@@ -2788,6 +2989,14 @@ public final class Settings {
new DiscreteValueValidator(new String[] {"12", "24"});
/**
+ * Developer options - Navigation Bar show switch
+ * @deprecated Moved to CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR
+ * @hide
+ */
+ public static final String DEV_FORCE_SHOW_NAVBAR = "dev_force_show_navbar";
+
+
+ /**
* Date format string
* mm/dd/yyyy
* dd/mm/yyyy
@@ -2849,6 +3058,19 @@ public final class Settings {
public static final String ANIMATOR_DURATION_SCALE = Global.ANIMATOR_DURATION_SCALE;
/**
+ * Control the type of rotation which can be performed using the accelerometer
+ * if ACCELEROMETER_ROTATION is enabled.
+ * Value is a bitwise combination of
+ * 1 = 0 degrees (portrait)
+ * 2 = 90 degrees (left)
+ * 4 = 180 degrees (inverted portrait)
+ * 8 = 270 degrees (right)
+ * Setting to 0 is effectively orientation lock
+ * @hide
+ */
+ public static final String ACCELEROMETER_ROTATION_ANGLES = "accelerometer_rotation_angles";
+
+ /**
* Control whether the accelerometer will be used to change screen
* orientation. If 0, it will not be used unless explicitly requested
* by the application; if 1, it will be used by default unless explicitly
@@ -3183,6 +3405,63 @@ public final class Settings {
new InclusiveFloatRangeValidator(-7, 7);
/**
+ * Show icon when stylus is used?
+ * 0 = no
+ * 1 = yes
+ * @hide
+ */
+ public static final String STYLUS_ICON_ENABLED = "stylus_icon_enabled";
+
+ /**
+ * Enable Stylus Gestures
+ *
+ * @hide
+ */
+ public static final String ENABLE_STYLUS_GESTURES = "enable_stylus_gestures";
+
+ /**
+ * Left Swipe Action
+ *
+ * @hide
+ */
+ public static final String GESTURES_LEFT_SWIPE = "gestures_left_swipe";
+
+ /**
+ * Right Swipe Action
+ *
+ * @hide
+ */
+ public static final String GESTURES_RIGHT_SWIPE = "gestures_right_swipe";
+
+ /**
+ * Up Swipe Action
+ *
+ * @hide
+ */
+ public static final String GESTURES_UP_SWIPE = "gestures_up_swipe";
+
+ /**
+ * down Swipe Action
+ *
+ * @hide
+ */
+ public static final String GESTURES_DOWN_SWIPE = "gestures_down_swipe";
+
+ /**
+ * Long press Action
+ *
+ * @hide
+ */
+ public static final String GESTURES_LONG_PRESS = "gestures_long_press";
+
+ /**
+ * double tap Action
+ *
+ * @hide
+ */
+ public static final String GESTURES_DOUBLE_TAP = "gestures_double_tap";
+
+ /**
* Whether lock-to-app will be triggered by long-press on recents.
* @hide
*/
@@ -3219,6 +3498,44 @@ public final class Settings {
* the setting value. See an example above.
*/
+ /**
+ * Whether wifi settings will connect to access point automatically
+ * 0 = automatically
+ * 1 = manually
+ * @hide
+ */
+ public static final String WIFI_AUTO_CONNECT_TYPE = "wifi_auto_connect_type";
+
+ /**
+ * Volume keys control cursor in text fields (default is 0)
+ * 0 - Disabled
+ * 1 - Volume up/down moves cursor left/right
+ * 2 - Volume up/down moves cursor right/left
+ * @hide
+ */
+ public static final String VOLUME_KEY_CURSOR_CONTROL = "volume_key_cursor_control";
+
+ /**
+ * Whether to enable voice wakeup. The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String VOICE_WAKEUP = "voice_wakeup";
+
+ /**
+ * An intent (a flattened Uri String) to launch when user voice launch
+ * action is detected. An empty or null string will launch the default
+ * voice search activity.
+ * @hide
+ */
+ public static final String VOICE_LAUNCH_INTENT = "voice_launch_intent";
+
+ /**
+ * Volume key controls ringtone or media sound stream
+ * @hide
+ */
+ public static final String VOLUME_KEYS_CONTROL_RING_STREAM =
+ "volume_keys_control_ring_stream";
+
/**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
@@ -3270,7 +3587,12 @@ public final class Settings {
VIBRATE_WHEN_RINGING,
RINGTONE,
LOCK_TO_APP_ENABLED,
- NOTIFICATION_SOUND
+ NOTIFICATION_SOUND,
+ PHONE_BLACKLIST_ENABLED,
+ PHONE_BLACKLIST_NOTIFY_ENABLED,
+ PHONE_BLACKLIST_PRIVATE_NUMBER_MODE,
+ PHONE_BLACKLIST_UNKNOWN_NUMBER_MODE,
+ PHONE_BLACKLIST_REGEX_ENABLED,
};
/**
@@ -3323,6 +3645,7 @@ public final class Settings {
PUBLIC_SETTINGS.add(SOUND_EFFECTS_ENABLED);
PUBLIC_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
PUBLIC_SETTINGS.add(SHOW_WEB_SUGGESTIONS);
+ PUBLIC_SETTINGS.add(POWER_OFF_ALARM_MODE);
}
/**
@@ -3448,6 +3771,7 @@ public final class Settings {
VALIDATORS.put(WIFI_STATIC_NETMASK, WIFI_STATIC_NETMASK_VALIDATOR);
VALIDATORS.put(WIFI_STATIC_DNS1, WIFI_STATIC_DNS1_VALIDATOR);
VALIDATORS.put(WIFI_STATIC_DNS2, WIFI_STATIC_DNS2_VALIDATOR);
+ VALIDATORS.put(POWER_OFF_ALARM_MODE, POWER_OFF_ALARM_MODE_VALIDATOR);
}
/**
@@ -3756,6 +4080,9 @@ public final class Settings {
MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_ENABLED);
MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_VISIBLE);
MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED);
+ MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_SIZE);
+ MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_DOTS_VISIBLE);
+ MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_SHOW_ERROR_PATH);
MOVED_TO_GLOBAL = new HashSet<String>();
MOVED_TO_GLOBAL.add(Settings.Global.ADB_ENABLED);
@@ -3872,6 +4199,44 @@ public final class Settings {
MOVED_TO_GLOBAL.add(Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY);
}
+ /**
+ * Put a delimited list as a string
+ * @param resolver to access the database with
+ * @param name to store
+ * @param delimiter to split
+ * @param list to join and store
+ * @hide
+ */
+ public static void putListAsDelimitedString(ContentResolver resolver, String name,
+ String delimiter, List<String> list) {
+ String store = TextUtils.join(delimiter, list);
+ putString(resolver, name, store);
+ }
+
+ /**
+ * Get a delimited string returned as a list
+ * @param resolver to access the database with
+ * @param name to store
+ * @param delimiter to split the list with
+ * @return list of strings for a specific Settings.Secure item
+ * @hide
+ */
+ public static List<String> getDelimitedStringAsList(ContentResolver resolver, String name,
+ String delimiter) {
+ String baseString = getString(resolver, name);
+ List<String> list = new ArrayList<String>();
+ if (!TextUtils.isEmpty(baseString)) {
+ final String[] array = TextUtils.split(baseString, Pattern.quote(delimiter));
+ for (String item : array) {
+ if (TextUtils.isEmpty(item)) {
+ continue;
+ }
+ list.add(item);
+ }
+ }
+ return list;
+ }
+
/** @hide */
public static void getMovedToGlobalSettings(Set<String> outKeySet) {
outKeySet.addAll(MOVED_TO_GLOBAL);
@@ -4488,6 +4853,24 @@ public final class Settings {
LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
/**
+ * Determines the width and height of the LockPatternView widget
+ * @hide
+ */
+ public static final String LOCK_PATTERN_SIZE = "lock_pattern_size";
+
+ /**
+ * Whether lock pattern will show dots (0 = false, 1 = true)
+ * @hide
+ */
+ public static final String LOCK_DOTS_VISIBLE = "lock_pattern_dotsvisible";
+
+ /**
+ * Whether lockscreen error pattern is visible (0 = false, 1 = true)
+ * @hide
+ */
+ public static final String LOCK_SHOW_ERROR_PATH = "lock_pattern_show_error_path";
+
+ /**
* This preference allows the device to be locked given time after screen goes off,
* subject to current DeviceAdmin policy limits.
* @hide
@@ -4588,6 +4971,12 @@ public final class Settings {
public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
/**
+ * Known good originating source sms addresses
+ * @hide
+ */
+ public static final String PROTECTED_SMS_ADDRESSES = "protected_sms_addresses";
+
+ /**
* Settings classname to launch when Settings is clicked from All
* Applications. Needed because of user testing between the old
* and new Settings apps.
@@ -5155,6 +5544,12 @@ public final class Settings {
"connectivity_release_pending_intent_delay_ms";
/**
+ * Whether the Wimax should be on. Only the WiMAX service should touch this.
+ * @hide
+ */
+ public static final String WIMAX_ON = "wimax_on";
+
+ /**
* Whether background data usage is allowed.
*
* @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH},
@@ -5692,6 +6087,12 @@ public final class Settings {
public static final String ASSISTANT = "assistant";
/**
+ * Default theme to use. If empty, use system.
+ * @hide
+ */
+ public static final String DEFAULT_THEME_PACKAGE = "default_theme_package";
+
+ /**
* Whether the camera launch gesture should be disabled.
*
* @hide
@@ -5708,6 +6109,12 @@ public final class Settings {
"camera_double_tap_power_gesture_disabled";
/**
+ * Boolean value whether to link ringtone and notification volume
+ * @hide
+ */
+ public static final String VOLUME_LINK_NOTIFICATION = "volume_link_notification";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -5763,7 +6170,7 @@ public final class Settings {
MOUNT_UMS_NOTIFY_ENABLED,
SLEEP_TIMEOUT,
DOUBLE_TAP_TO_WAKE,
- CAMERA_GESTURE_DISABLED,
+ CAMERA_GESTURE_DISABLED
};
/**
@@ -6030,6 +6437,13 @@ public final class Settings {
public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios";
/**
+ * A Long representing a bitmap of profiles that should be disabled when bluetooth starts.
+ * See {@link android.bluetooth.BluetoothProfile}.
+ * {@hide}
+ */
+ public static final String BLUETOOTH_DISABLED_PROFILES = "bluetooth_disabled_profiles";
+
+ /**
* A semi-colon separated list of Bluetooth interoperability workarounds.
* Each entry is a partial Bluetooth device address string and an integer representing
* the feature to be disabled, separated by a comma. The integer must correspond
@@ -6182,6 +6596,14 @@ public final class Settings {
public static final String ADB_ENABLED = "adb_enabled";
/**
+ * String to contain power menu actions
+ * @deprecated Use {@link CMSettings.Secure#POWER_MENU_ACTIONS} instead
+ * @hide
+ */
+ @Deprecated
+ public static final String POWER_MENU_ACTIONS = "power_menu_actions";
+
+ /**
* Whether Views are allowed to save their attribute data.
* @hide
*/
@@ -7239,6 +7661,9 @@ public final class Settings {
BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX = "bluetooth_a2dp_sink_priority_";
/** {@hide} */
public static final String
+ BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX = "bluetooth_a2dp_src_priority_";
+ /** {@hide} */
+ public static final String
BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX = "bluetooth_input_device_priority_";
/** {@hide} */
public static final String
@@ -7341,6 +7766,14 @@ public final class Settings {
}
/**
+ * Get the key that retrieves a bluetooth a2dp src's priority.
+ * @hide
+ */
+ public static final String getBluetoothA2dpSrcPriorityKey(String address) {
+ return BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+ }
+
+ /**
* Get the key that retrieves a bluetooth Input Device's priority.
* @hide
*/
@@ -7571,13 +8004,22 @@ public final class Settings {
/**
* Defines global runtime overrides to window policy.
*
- * See {@link com.android.server.policy.PolicyControl} for value format.
+ * See {@link android.view.WindowManagerPolicyControl} for value format.
*
* @hide
*/
public static final String POLICY_CONTROL = "policy_control";
/**
+ * Defines global runtime overrides to window policy style.
+ *
+ * See {@link android.view.WindowManagerPolicyControl} for value definitions.
+ *
+ * @hide
+ */
+ public static final String POLICY_CONTROL_STYLE = "policy_control_style";
+
+ /**
* Defines global zen mode. ZEN_MODE_OFF, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
* or ZEN_MODE_NO_INTERRUPTIONS.
*
@@ -7667,7 +8109,7 @@ public final class Settings {
public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt";
/**
- * Whether the Volte/VT is enabled
+ * Whether the Volte is enabled
* <p>
* Type: int (0 for false, 1 for true)
* @hide
@@ -7675,6 +8117,15 @@ public final class Settings {
public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
/**
+ * Whether VT (Video Telephony over IMS) is enabled
+ * <p>
+ * Type: int (0 for false, 1 for true)
+ *
+ * @hide
+ */
+ public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+
+ /**
* Whether WFC is enabled
* <p>
* Type: int (0 for false, 1 for true)
@@ -7711,6 +8162,13 @@ public final class Settings {
public static final String LTE_SERVICE_FORCED = "lte_service_forced";
/**
+ * Whether to ignore the representation of outgoing calls set by the network.
+ *
+ * @hide
+ */
+ public static final String CONNECTED_LINE_IDENTIFICATION = "connected_line_identification";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
@@ -7757,6 +8215,7 @@ public final class Settings {
static {
MOVED_TO_SECURE = new HashSet<String>(1);
MOVED_TO_SECURE.add(Settings.Global.INSTALL_NON_MARKET_APPS);
+ MOVED_TO_SECURE.add(Settings.Global.POWER_MENU_ACTIONS);
}
/** @hide */
@@ -7765,6 +8224,44 @@ public final class Settings {
}
/**
+ * Put a delimited list as a string
+ * @param resolver to access the database with
+ * @param name to store
+ * @param delimiter to split
+ * @param list to join and store
+ * @hide
+ */
+ public static void putListAsDelimitedString(ContentResolver resolver, String name,
+ String delimiter, List<String> list) {
+ String store = TextUtils.join(delimiter, list);
+ putString(resolver, name, store);
+ }
+
+ /**
+ * Get a delimited string returned as a list
+ * @param resolver to access the database with
+ * @param name to store
+ * @param delimiter to split the list with
+ * @return list of strings for a specific Settings.Secure item
+ * @hide
+ */
+ public static List<String> getDelimitedStringAsList(ContentResolver resolver, String name,
+ String delimiter) {
+ String baseString = getString(resolver, name);
+ List<String> list = new ArrayList<String>();
+ if (!TextUtils.isEmpty(baseString)) {
+ final String[] array = TextUtils.split(baseString, Pattern.quote(delimiter));
+ for (String item : array) {
+ if (TextUtils.isEmpty(item)) {
+ continue;
+ }
+ list.add(item);
+ }
+ }
+ return list;
+ }
+
+ /**
* Look up a name in the database.
* @param resolver to access the database with
* @param name to look up in the table
@@ -7820,6 +8317,12 @@ public final class Settings {
* @return the corresponding content URI, or null if not present
*/
public static Uri getUriFor(String name) {
+ if (MOVED_TO_SECURE.contains(name)) {
+ Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Global"
+ + " to android.provider.Settings.Secure, returning Secure URI.");
+ return Secure.getUriFor(Secure.CONTENT_URI, name);
+ }
+
return getUriFor(CONTENT_URI, name);
}
@@ -8091,6 +8594,13 @@ public final class Settings {
* @hide
*/
public static final String CONTACT_METADATA_SYNC = "contact_metadata_sync";
+
+ /**
+ * Whether to enable cellular on boot.
+ * The value 1 - enable, 0 - disable
+ * @hide
+ */
+ public static final String ENABLE_CELLULAR_ON_BOOT = "enable_cellular_on_boot";
}
/**
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
index ff7cef9..c750b5e 100644
--- a/core/java/android/service/dreams/DreamManagerInternal.java
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -42,4 +42,9 @@ public abstract class DreamManagerInternal {
* Called by the power manager to determine whether a dream is running.
*/
public abstract boolean isDreaming();
+
+ /**
+ * Called by the power manager to determine whether the dream has gone to doze mode.
+ */
+ public abstract boolean isDozing();
}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index be3f3b3..78dda0c 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -30,7 +30,10 @@ interface IDreamManager {
ComponentName getDefaultDreamComponent();
void testDream(in ComponentName componentName);
boolean isDreaming();
+ boolean isDozing();
void finishSelf(in IBinder token, boolean immediate);
void startDozing(in IBinder token, int screenState, int screenBrightness);
void stopDozing(in IBinder token);
+ void setLidState(int state);
+ int getLidState();
}
diff --git a/core/java/android/service/gesture/IGestureService.aidl b/core/java/android/service/gesture/IGestureService.aidl
new file mode 100644
index 0000000..1944d50
--- /dev/null
+++ b/core/java/android/service/gesture/IGestureService.aidl
@@ -0,0 +1,11 @@
+package android.service.gesture;
+
+import android.app.PendingIntent;
+
+/** @hide */
+interface IGestureService {
+
+ void setOnLongPressPendingIntent(in PendingIntent pendingIntent);
+ void setOnDoubleClickPendingIntent(in PendingIntent pendingIntent);
+
+}
diff --git a/core/java/android/service/voice/VoiceInteractionServiceInfo.java b/core/java/android/service/voice/VoiceInteractionServiceInfo.java
index 463eb5b..8393f7e 100644
--- a/core/java/android/service/voice/VoiceInteractionServiceInfo.java
+++ b/core/java/android/service/voice/VoiceInteractionServiceInfo.java
@@ -58,6 +58,10 @@ public class VoiceInteractionServiceInfo {
}
public VoiceInteractionServiceInfo(PackageManager pm, ServiceInfo si) {
+ if (si == null) {
+ mParseError = "Service not available";
+ return;
+ }
if (!Manifest.permission.BIND_VOICE_INTERACTION.equals(si.permission)) {
mParseError = "Service does not require permission "
+ Manifest.permission.BIND_VOICE_INTERACTION;
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 88e2ede..3eb24e4 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -260,6 +260,7 @@ public class SpeechRecognizer {
* not set explicitly, default values will be used by the recognizer.
*/
public void startListening(final Intent recognizerIntent) {
+ android.util.SeempLog.record(72);
if (recognizerIntent == null) {
throw new IllegalArgumentException("intent must not be null");
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index fa347b9..22ad634 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1130,20 +1130,31 @@ public abstract class Layout {
*/
public int getOffsetForHorizontal(int line, float horiz) {
// TODO: use Paint.getOffsetForAdvance to avoid binary search
- int max = getLineEnd(line) - 1;
- int min = getLineStart(line);
+ final int lineEndOffset = getLineEnd(line);
+ final int lineStartOffset = getLineStart(line);
+
Directions dirs = getLineDirections(line);
- if (line == getLineCount() - 1)
- max++;
+ TextLine tl = TextLine.obtain();
+ // XXX: we don't care about tabs as we just use TextLine#getOffsetToLeftRightOf here.
+ tl.set(mPaint, mText, lineStartOffset, lineEndOffset, getParagraphDirection(line), dirs,
+ false, null);
- int best = min;
+ final int max;
+ if (line == getLineCount() - 1) {
+ max = lineEndOffset;
+ } else {
+ max = tl.getOffsetToLeftRightOf(lineEndOffset - lineStartOffset,
+ !isRtlCharAt(lineEndOffset - 1)) + lineStartOffset;
+ }
+ int best = lineStartOffset;
float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz);
for (int i = 0; i < dirs.mDirections.length; i += 2) {
- int here = min + dirs.mDirections[i];
+ int here = lineStartOffset + dirs.mDirections[i];
int there = here + (dirs.mDirections[i+1] & RUN_LENGTH_MASK);
- int swap = (dirs.mDirections[i+1] & RUN_RTL_FLAG) != 0 ? -1 : 1;
+ boolean isRtl = (dirs.mDirections[i+1] & RUN_RTL_FLAG) != 0;
+ int swap = isRtl ? -1 : 1;
if (there > max)
there = max;
@@ -1163,23 +1174,23 @@ public abstract class Layout {
low = here + 1;
if (low < there) {
- low = getOffsetAtStartOf(low);
-
- float dist = Math.abs(getPrimaryHorizontal(low) - horiz);
-
- int aft = TextUtils.getOffsetAfter(mText, low);
- if (aft < there) {
- float other = Math.abs(getPrimaryHorizontal(aft) - horiz);
-
- if (other < dist) {
- dist = other;
- low = aft;
+ int aft = tl.getOffsetToLeftRightOf(low - lineStartOffset, isRtl) + lineStartOffset;
+ low = tl.getOffsetToLeftRightOf(aft - lineStartOffset, !isRtl) + lineStartOffset;
+ if (low >= here && low < there) {
+ float dist = Math.abs(getPrimaryHorizontal(low) - horiz);
+ if (aft < there) {
+ float other = Math.abs(getPrimaryHorizontal(aft) - horiz);
+
+ if (other < dist) {
+ dist = other;
+ low = aft;
+ }
}
- }
- if (dist < bestdist) {
- bestdist = dist;
- best = low;
+ if (dist < bestdist) {
+ bestdist = dist;
+ best = low;
+ }
}
}
@@ -1198,6 +1209,7 @@ public abstract class Layout {
best = max;
}
+ TextLine.recycle(tl);
return best;
}
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 39e8694..3592187 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -718,13 +718,14 @@ class TextLine {
* @param bottom the bottom of the line
* @param fmi receives metrics information, can be null
* @param needWidth true if the width of the run is needed
+ * @param offset the offset for the purpose of measuring
* @return the signed width of the run based on the run direction; only
* valid if needWidth is true
*/
private float handleText(TextPaint wp, int start, int end,
int contextStart, int contextEnd, boolean runIsRtl,
Canvas c, float x, int top, int y, int bottom,
- FontMetricsInt fmi, boolean needWidth) {
+ FontMetricsInt fmi, boolean needWidth, int offset) {
// Get metrics first (even for empty strings or "0" width runs)
if (fmi != null) {
@@ -742,11 +743,11 @@ class TextLine {
if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
if (mCharsValid) {
ret = wp.getRunAdvance(mChars, start, end, contextStart, contextEnd,
- runIsRtl, end);
+ runIsRtl, offset);
} else {
int delta = mStart;
ret = wp.getRunAdvance(mText, delta + start, delta + end,
- delta + contextStart, delta + contextEnd, runIsRtl, delta + end);
+ delta + contextStart, delta + contextEnd, runIsRtl, delta + offset);
}
}
@@ -895,8 +896,8 @@ class TextLine {
TextPaint wp = mWorkPaint;
wp.set(mPaint);
final int mlimit = measureLimit;
- return handleText(wp, start, mlimit, start, limit, runIsRtl, c, x, top,
- y, bottom, fmi, needWidth || mlimit < measureLimit);
+ return handleText(wp, start, limit, start, limit, runIsRtl, c, x, top,
+ y, bottom, fmi, needWidth || mlimit < measureLimit, mlimit);
}
mMetricAffectingSpanSpanSet.init(mSpanned, mStart + start, mStart + limit);
@@ -940,13 +941,14 @@ class TextLine {
}
for (int j = i, jnext; j < mlimit; j = jnext) {
- jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + mlimit) -
+ jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + inext) -
mStart;
+ int offset = Math.min(jnext, mlimit);
wp.set(mPaint);
for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) {
// Intentionally using >= and <= as explained above
- if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + jnext) ||
+ if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + offset) ||
(mCharacterStyleSpanSet.spanEnds[k] <= mStart + j)) continue;
CharacterStyle span = mCharacterStyleSpanSet.spans[k];
@@ -958,7 +960,7 @@ class TextLine {
wp.setHyphenEdit(0);
}
x += handleText(wp, j, jnext, i, inext, runIsRtl, c, x,
- top, y, bottom, fmi, needWidth || jnext < measureLimit);
+ top, y, bottom, fmi, needWidth || jnext < measureLimit, offset);
}
}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index d8f7158..75fd2da 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1754,19 +1754,21 @@ public class TextUtils {
* Be careful: this code will need to be updated when vertical scripts will be supported
*/
public static int getLayoutDirectionFromLocale(Locale locale) {
+ boolean mirror = SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false);
if (locale != null && !locale.equals(Locale.ROOT)) {
final String scriptSubtag = ICU.addLikelySubtags(locale).getScript();
if (scriptSubtag == null) return getLayoutDirectionFromFirstChar(locale);
if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG) ||
scriptSubtag.equalsIgnoreCase(HEBR_SCRIPT_SUBTAG)) {
- return View.LAYOUT_DIRECTION_RTL;
+ // If forcing into RTL layout mode and language is RTL
+ // return LTR as default, else RTL
+ return mirror ? View.LAYOUT_DIRECTION_LTR : View.LAYOUT_DIRECTION_RTL;
}
}
- // If forcing into RTL layout mode, return RTL as default, else LTR
- return SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false)
- ? View.LAYOUT_DIRECTION_RTL
- : View.LAYOUT_DIRECTION_LTR;
+ // If forcing into RTL layout mode and language is LTR
+ // return RTL as default, else LTR
+ return mirror ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
}
/**
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 3ed37b3..998fa9d 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -177,12 +177,23 @@ public class DateFormat {
* @hide
*/
public static boolean is24HourFormat(Context context, int userHandle) {
- String value = Settings.System.getStringForUser(context.getContentResolver(),
+ String setting = Settings.System.getStringForUser(context.getContentResolver(),
Settings.System.TIME_12_24, userHandle);
+ Locale locale = context.getResources().getConfiguration().locale;
+ return is24HourFormat(setting, locale);
+ }
- if (value == null) {
- Locale locale = context.getResources().getConfiguration().locale;
-
+ /**
+ * Returns true if user preference with the given user handle is set to 24-hour format.
+ * @param setting value of the TIME_12_24 system setting, which may be null
+ * @param locale current default locale for this device
+ * @param userHandle the user handle of the user to query.
+ * @return true if 24 hour time format is selected, false otherwise.
+ *
+ * @hide
+ */
+ public static boolean is24HourFormat(String setting, Locale locale) {
+ if (setting == null) {
synchronized (sLocaleLock) {
if (sIs24HourLocale != null && sIs24HourLocale.equals(locale)) {
return sIs24Hour;
@@ -197,23 +208,23 @@ public class DateFormat {
String pattern = sdf.toPattern();
if (pattern.indexOf('H') >= 0) {
- value = "24";
+ setting = "24";
} else {
- value = "12";
+ setting = "12";
}
} else {
- value = "12";
+ setting = "12";
}
synchronized (sLocaleLock) {
sIs24HourLocale = locale;
- sIs24Hour = value.equals("24");
+ sIs24Hour = setting.equals("24");
}
return sIs24Hour;
}
- return value.equals("24");
+ return setting.equals("24");
}
/**
diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java
index e9db5fd..569ca60 100644
--- a/core/java/android/text/method/MetaKeyKeyListener.java
+++ b/core/java/android/text/method/MetaKeyKeyListener.java
@@ -23,6 +23,9 @@ import android.text.Spanned;
import android.view.KeyEvent;
import android.view.View;
import android.view.KeyCharacterMap;
+import android.os.IPowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
/**
* This base class encapsulates the behavior for tracking the state of
@@ -273,6 +276,14 @@ public abstract class MetaKeyKeyListener {
adjust(content, CAP);
adjust(content, ALT);
adjust(content, SYM);
+ try {
+ IPowerManager power = IPowerManager.Stub.asInterface(
+ ServiceManager.getService("power"));
+ if (getMetaState(content, META_SHIFT_ON) <= 0)
+ power.setKeyboardLight(false, 1);
+ if (getMetaState(content, META_ALT_ON) <= 0)
+ power.setKeyboardLight(false, 2);
+ } catch (RemoteException doe) {}
}
/**
@@ -325,12 +336,32 @@ public abstract class MetaKeyKeyListener {
public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
press(content, CAP);
+ try {
+ IPowerManager power = IPowerManager.Stub.asInterface(
+ ServiceManager.getService("power"));
+ int state = content.getSpanFlags(CAP);
+ if (state == PRESSED || state == LOCKED) {
+ power.setKeyboardLight(true, 1);
+ } else {
+ power.setKeyboardLight(false, 1);
+ }
+ } catch (RemoteException doe) {}
return true;
}
if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT
|| keyCode == KeyEvent.KEYCODE_NUM) {
press(content, ALT);
+ try {
+ IPowerManager power = IPowerManager.Stub.asInterface(
+ ServiceManager.getService("power"));
+ int state = content.getSpanFlags(ALT);
+ if (state == PRESSED || state == LOCKED) {
+ power.setKeyboardLight(true, 2);
+ } else {
+ power.setKeyboardLight(false, 2);
+ }
+ } catch (RemoteException doe) {}
return true;
}
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 9a69600..ee959e2 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -16,6 +16,7 @@
package android.util;
+import android.graphics.Bitmap;
import android.os.SystemProperties;
@@ -138,7 +139,20 @@ public class DisplayMetrics {
* density for a display in {@link #densityDpi}.
*/
@Deprecated
- public static int DENSITY_DEVICE = getDeviceDensity();
+ public static int DENSITY_DEVICE;
+
+ /** @hide */
+ public static int DENSITY_PREFERRED;
+
+ /** @hide */
+ public static int DENSITY_DEVICE_DEFAULT;
+
+ static {
+ DENSITY_DEVICE = SystemProperties.getInt("qemu.sf.lcd_density", SystemProperties
+ .getInt("ro.sf.lcd_density", DENSITY_DEFAULT));
+ DENSITY_DEVICE_DEFAULT = DENSITY_DEVICE;
+ DENSITY_PREFERRED = SystemProperties.getInt("persist.sys.lcd_density", DENSITY_DEVICE);
+ }
/**
* The absolute width of the display in pixels.
@@ -229,6 +243,24 @@ public class DisplayMetrics {
*/
public float noncompatYdpi;
+ /** @hide */
+ public void setDensity(int inDensity) {
+ density = inDensity / (float) DENSITY_DEFAULT;
+ densityDpi = inDensity;
+ scaledDensity = density;
+ xdpi = inDensity;
+ ydpi = inDensity;
+
+ noncompatDensity = density;
+ noncompatDensityDpi = densityDpi;
+ noncompatScaledDensity = scaledDensity;
+ noncompatXdpi = xdpi;
+ noncompatYdpi = ydpi;
+
+ DENSITY_DEVICE = inDensity;
+ Bitmap.setDefaultDensity(inDensity);
+ }
+
public DisplayMetrics() {
}
@@ -319,13 +351,4 @@ public class DisplayMetrics {
", height=" + heightPixels + ", scaledDensity=" + scaledDensity +
", xdpi=" + xdpi + ", ydpi=" + ydpi + "}";
}
-
- private static int getDeviceDensity() {
- // qemu.sf.lcd_density can be used to override ro.sf.lcd_density
- // when running in the emulator, allowing for dynamic configurations.
- // The reason for this is that ro.sf.lcd_density is write-once and is
- // set by the init process when it parses build.prop before anything else.
- return SystemProperties.getInt("qemu.sf.lcd_density",
- SystemProperties.getInt("ro.sf.lcd_density", DENSITY_DEFAULT));
- }
}
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 2cc91b9..f1b3feb 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -125,15 +125,35 @@ public class Patterns {
+ "|[1-9][0-9]|[0-9]))");
/**
+ * Match the characters without containing chinese characters
+ * @hide
+ */
+ private static final String GOOD_IRI_HOST_CHAR =
+ "a-zA-Z0-9\u00A0-\u2FFF\u3040-\u4DFF\u9FA6-\uD7FF"
+ + "\uF900-\uFDCF\uFDF0-\uFEFF";
+
+ /**
* RFC 1035 Section 2.3.4 limits the labels to a maximum 63 octets.
*/
- private static final String IRI
- = "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}";
+ private static final String IRI =
+ "[" + GOOD_IRI_HOST_CHAR + "]([" + GOOD_IRI_HOST_CHAR + "\\-_~]{0,61}["
+ + GOOD_IRI_HOST_CHAR + "]){0,1}";
private static final String GOOD_GTLD_CHAR =
- "a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
+ "a-zA-Z\u00A0-\u2FFF\u3040-\u4DFF\u9FA6-\uD7FF"
+ + "\uF900-\uFDCF\uFDF0-\uFEFF";
private static final String GTLD = "[" + GOOD_GTLD_CHAR + "]{2,63}";
private static final String HOST_NAME = "(" + IRI + "\\.)+" + GTLD;
+ // Halfwidth and fullwidth forms
+ private static final String HALF_FULL_WIDTH_CHAR = "\uFF00-\uFFEF";
+ // Symbols and punctuation
+ private static final String SYMBOLS_PUNCTUATION_CHAR = "\u3000-\u303F";
+ // Chinese characters
+ private static final String CHINESE_CHAR = "\u4E00-\u9FA5";
+ // Forbidden characters, should remove from URL,
+ private static final String FORBIDDEN_CHAR =
+ "[" + SYMBOLS_PUNCTUATION_CHAR + CHINESE_CHAR
+ + HALF_FULL_WIDTH_CHAR + "]";
public static final Pattern DOMAIN_NAME
= Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")");
@@ -149,11 +169,15 @@ public class Patterns {
+ "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
+ "(?:" + DOMAIN_NAME + ")"
+ "(?:\\:\\d{1,5})?)" // plus option port number
- + "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params
- + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
- + "(?:\\b|$)"); // and finally, a word boundary or end of
- // input. This is to stop foo.sure from
- // matching as foo.su
+ + "(\\/(?:(?:[" + GOOD_IRI_HOST_CHAR
+ + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params
+ + "\\-\\.\\+\\!\\*\\'\\(\\)\\_])|(?:\\,[" + GOOD_IRI_HOST_CHAR
+ + "])|(?:\\%[a-fA-F0-9]{2}))*)?"
+ + "(?:(?=" + FORBIDDEN_CHAR
+ + ")|\\b|$)");
+ // and finally, a word boundary or end of input. This is to stop
+ // foo.sure from matching as foo.su
+ // also should remove forbidden characters from end of URL.
public static final Pattern EMAIL_ADDRESS
= Pattern.compile(
diff --git a/core/java/android/util/SeempLog.java b/core/java/android/util/SeempLog.java
new file mode 100644
index 0000000..6e6cce6
--- /dev/null
+++ b/core/java/android/util/SeempLog.java
@@ -0,0 +1,758 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package android.util;
+
+import com.android.internal.os.RuntimeInit;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.UnknownHostException;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.List;
+import java.util.Iterator;
+import android.util.Log;
+import android.provider.Settings;
+
+/**
+ * SeempLog
+ *
+ * @hide
+ */
+public final class SeempLog {
+ private SeempLog() {
+ }
+
+ /**
+ * Send a log message to the seemp log.
+ * @param api The api triggering this message.
+ */
+ public static int record(int api) {
+ return seemp_println_native(api, "");
+ }
+
+ /**
+ * Send a log message to the seemp log.
+ * @param api The api triggering this message.
+ * @param msg The message you would like logged.
+ */
+ public static int record_str(int api, String msg) {
+ if ( msg != null ) {
+ return seemp_println_native(api, msg);
+ }
+ else {
+ return seemp_println_native(api, "");
+ }
+ }
+
+ public static int record_sensor(int api,
+ android.hardware.Sensor sensor) {
+ if ( sensor != null ) {
+ return seemp_println_native(api, "sensor="+sensor.getType());
+ }
+ else {
+ return seemp_println_native(api, "sensor=-1");
+ }
+ }
+
+ public static int record_sensor_rate(int api,
+ android.hardware.Sensor sensor, int rate) {
+ if ( sensor != null ) {
+ return seemp_println_native(api,
+ "sensor="+sensor.getType() + ",rate="+rate);
+ }
+ else {
+ return seemp_println_native(api, "sensor=-1,rate=" + rate);
+ }
+ }
+
+ public static int record_uri(int api, android.net.Uri uri) {
+ if ( uri != null ) {
+ return seemp_println_native(api, "uri, " + uri.toString());
+ }
+ else {
+ return seemp_println_native(api, "uri, null" );
+ }
+ }
+
+ public static int record_vg_layout(int api,
+ android.view.ViewGroup.LayoutParams params) {
+ try {
+ android.view.WindowManager.LayoutParams p =
+ (android.view.WindowManager.LayoutParams) params;
+ if ( p != null ) {
+ return seemp_println_native(api,
+ "window_type=" + p.type + ",window_flag=" + p.flags);
+ }
+ else {
+ return seemp_println_native(api, "");
+ }
+ } catch (ClassCastException cce) {
+ return seemp_println_native(api, "");
+ }
+ }
+
+ /** @hide */ public static native int seemp_println_native(int api, String msg);
+
+ public static final int SEEMP_API_android_provider_Settings__get_ANDROID_ID_ = 7;
+ public static final int SEEMP_API_android_provider_Settings__get_ACCELEROMETER_ROTATION_ = 96;
+ public static final int SEEMP_API_android_provider_Settings__get_USER_ROTATION_ = 97;
+ public static final int SEEMP_API_android_provider_Settings__get_ADB_ENABLED_ = 98;
+ public static final int SEEMP_API_android_provider_Settings__get_DEBUG_APP_ = 99;
+ public static final int SEEMP_API_android_provider_Settings__get_WAIT_FOR_DEBUGGER_ = 100;
+ public static final int SEEMP_API_android_provider_Settings__get_AIRPLANE_MODE_ON_ = 101;
+ public static final int SEEMP_API_android_provider_Settings__get_AIRPLANE_MODE_RADIOS_ = 102;
+ public static final int SEEMP_API_android_provider_Settings__get_ALARM_ALERT_ = 103;
+ public static final int SEEMP_API_android_provider_Settings__get_NEXT_ALARM_FORMATTED_ = 104;
+ public static final int SEEMP_API_android_provider_Settings__get_ALWAYS_FINISH_ACTIVITIES_ = 105;
+ public static final int SEEMP_API_android_provider_Settings__get_LOGGING_ID_ = 106;
+ public static final int SEEMP_API_android_provider_Settings__get_ANIMATOR_DURATION_SCALE_ = 107;
+ public static final int SEEMP_API_android_provider_Settings__get_WINDOW_ANIMATION_SCALE_ = 108;
+ public static final int SEEMP_API_android_provider_Settings__get_FONT_SCALE_ = 109;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_ = 110;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_MODE_ = 111;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_MODE_AUTOMATIC_ = 112;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_MODE_MANUAL_ = 113;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_OFF_TIMEOUT_ = 114;
+ public static final int SEEMP_API_android_provider_Settings__get_DIM_SCREEN_ = 115;
+ public static final int SEEMP_API_android_provider_Settings__get_TRANSITION_ANIMATION_SCALE_ = 116;
+ public static final int SEEMP_API_android_provider_Settings__get_STAY_ON_WHILE_PLUGGED_IN_ = 117;
+ public static final int SEEMP_API_android_provider_Settings__get_WALLPAPER_ACTIVITY_ = 118;
+ public static final int SEEMP_API_android_provider_Settings__get_SHOW_PROCESSES_ = 119;
+ public static final int SEEMP_API_android_provider_Settings__get_SHOW_WEB_SUGGESTIONS_ = 120;
+ public static final int SEEMP_API_android_provider_Settings__get_SHOW_GTALK_SERVICE_STATUS_ = 121;
+ public static final int SEEMP_API_android_provider_Settings__get_USE_GOOGLE_MAIL_ = 122;
+ public static final int SEEMP_API_android_provider_Settings__get_AUTO_TIME_ = 123;
+ public static final int SEEMP_API_android_provider_Settings__get_AUTO_TIME_ZONE_ = 124;
+ public static final int SEEMP_API_android_provider_Settings__get_DATE_FORMAT_ = 125;
+ public static final int SEEMP_API_android_provider_Settings__get_TIME_12_24_ = 126;
+ public static final int SEEMP_API_android_provider_Settings__get_BLUETOOTH_DISCOVERABILITY_ = 127;
+ public static final int SEEMP_API_android_provider_Settings__get_BLUETOOTH_DISCOVERABILITY_TIMEOUT_ = 128;
+ public static final int SEEMP_API_android_provider_Settings__get_BLUETOOTH_ON_ = 129;
+ public static final int SEEMP_API_android_provider_Settings__get_DEVICE_PROVISIONED_ = 130;
+ public static final int SEEMP_API_android_provider_Settings__get_SETUP_WIZARD_HAS_RUN_ = 131;
+ public static final int SEEMP_API_android_provider_Settings__get_DTMF_TONE_WHEN_DIALING_ = 132;
+ public static final int SEEMP_API_android_provider_Settings__get_END_BUTTON_BEHAVIOR_ = 133;
+ public static final int SEEMP_API_android_provider_Settings__get_RINGTONE_ = 134;
+ public static final int SEEMP_API_android_provider_Settings__get_MODE_RINGER_ = 135;
+ public static final int SEEMP_API_android_provider_Settings__get_INSTALL_NON_MARKET_APPS_ = 136;
+ public static final int SEEMP_API_android_provider_Settings__get_LOCATION_PROVIDERS_ALLOWED_ = 137;
+ public static final int SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_ENABLED_ = 138;
+ public static final int SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_ = 139;
+ public static final int SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_VISIBLE_ = 140;
+ public static final int SEEMP_API_android_provider_Settings__get_NETWORK_PREFERENCE_ = 141;
+ public static final int SEEMP_API_android_provider_Settings__get_DATA_ROAMING_ = 142;
+ public static final int SEEMP_API_android_provider_Settings__get_HTTP_PROXY_ = 143;
+ public static final int SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_ENABLED_ = 144;
+ public static final int SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_LAST_UPDATE_ = 145;
+ public static final int SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_REDIRECT_URL_ = 146;
+ public static final int SEEMP_API_android_provider_Settings__get_RADIO_BLUETOOTH_ = 147;
+ public static final int SEEMP_API_android_provider_Settings__get_RADIO_CELL_ = 148;
+ public static final int SEEMP_API_android_provider_Settings__get_RADIO_NFC_ = 149;
+ public static final int SEEMP_API_android_provider_Settings__get_RADIO_WIFI_ = 150;
+ public static final int SEEMP_API_android_provider_Settings__get_SYS_PROP_SETTING_VERSION_ = 151;
+ public static final int SEEMP_API_android_provider_Settings__get_SETTINGS_CLASSNAME_ = 152;
+ public static final int SEEMP_API_android_provider_Settings__get_TEXT_AUTO_CAPS_ = 153;
+ public static final int SEEMP_API_android_provider_Settings__get_TEXT_AUTO_PUNCTUATE_ = 154;
+ public static final int SEEMP_API_android_provider_Settings__get_TEXT_AUTO_REPLACE_ = 155;
+ public static final int SEEMP_API_android_provider_Settings__get_TEXT_SHOW_PASSWORD_ = 156;
+ public static final int SEEMP_API_android_provider_Settings__get_USB_MASS_STORAGE_ENABLED_ = 157;
+ public static final int SEEMP_API_android_provider_Settings__get_VIBRATE_ON_ = 158;
+ public static final int SEEMP_API_android_provider_Settings__get_HAPTIC_FEEDBACK_ENABLED_ = 159;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_ALARM_ = 160;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_BLUETOOTH_SCO_ = 161;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_MUSIC_ = 162;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_NOTIFICATION_ = 163;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_RING_ = 164;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_SYSTEM_ = 165;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_VOICE_ = 166;
+ public static final int SEEMP_API_android_provider_Settings__get_SOUND_EFFECTS_ENABLED_ = 167;
+ public static final int SEEMP_API_android_provider_Settings__get_MODE_RINGER_STREAMS_AFFECTED_ = 168;
+ public static final int SEEMP_API_android_provider_Settings__get_MUTE_STREAMS_AFFECTED_ = 169;
+ public static final int SEEMP_API_android_provider_Settings__get_NOTIFICATION_SOUND_ = 170;
+ public static final int SEEMP_API_android_provider_Settings__get_APPEND_FOR_LAST_AUDIBLE_ = 171;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_MAX_DHCP_RETRY_COUNT_ = 172;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_ = 173;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_ = 174;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_ = 175;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_NUM_OPEN_NETWORKS_KEPT_ = 176;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_ON_ = 177;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_ = 178;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_DEFAULT_ = 179;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_NEVER_ = 180;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED_ = 181;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_DNS1_ = 182;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_DNS2_ = 183;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_GATEWAY_ = 184;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_IP_ = 185;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_NETMASK_ = 186;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_USE_STATIC_IP_ = 187;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_ = 188;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_AP_COUNT_ = 189;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_ = 190;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_ = 191;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_ = 192;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_ = 193;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_MAX_AP_CHECKS_ = 194;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_ON_ = 195;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_COUNT_ = 196;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_DELAY_MS_ = 197;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_TIMEOUT_MS_ = 198;
+ public static final int SEEMP_API_android_provider_Settings__put_ACCELEROMETER_ROTATION_ = 199;
+ public static final int SEEMP_API_android_provider_Settings__put_USER_ROTATION_ = 200;
+ public static final int SEEMP_API_android_provider_Settings__put_ADB_ENABLED_ = 201;
+ public static final int SEEMP_API_android_provider_Settings__put_DEBUG_APP_ = 202;
+ public static final int SEEMP_API_android_provider_Settings__put_WAIT_FOR_DEBUGGER_ = 203;
+ public static final int SEEMP_API_android_provider_Settings__put_AIRPLANE_MODE_ON_ = 204;
+ public static final int SEEMP_API_android_provider_Settings__put_AIRPLANE_MODE_RADIOS_ = 205;
+ public static final int SEEMP_API_android_provider_Settings__put_ALARM_ALERT_ = 206;
+ public static final int SEEMP_API_android_provider_Settings__put_NEXT_ALARM_FORMATTED_ = 207;
+ public static final int SEEMP_API_android_provider_Settings__put_ALWAYS_FINISH_ACTIVITIES_ = 208;
+ public static final int SEEMP_API_android_provider_Settings__put_ANDROID_ID_ = 209;
+ public static final int SEEMP_API_android_provider_Settings__put_LOGGING_ID_ = 210;
+ public static final int SEEMP_API_android_provider_Settings__put_ANIMATOR_DURATION_SCALE_ = 211;
+ public static final int SEEMP_API_android_provider_Settings__put_WINDOW_ANIMATION_SCALE_ = 212;
+ public static final int SEEMP_API_android_provider_Settings__put_FONT_SCALE_ = 213;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_ = 214;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_MODE_ = 215;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_MODE_AUTOMATIC_ = 216;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_MODE_MANUAL_ = 217;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_OFF_TIMEOUT_ = 218;
+ public static final int SEEMP_API_android_provider_Settings__put_DIM_SCREEN_ = 219;
+ public static final int SEEMP_API_android_provider_Settings__put_TRANSITION_ANIMATION_SCALE_ = 220;
+ public static final int SEEMP_API_android_provider_Settings__put_STAY_ON_WHILE_PLUGGED_IN_ = 221;
+ public static final int SEEMP_API_android_provider_Settings__put_WALLPAPER_ACTIVITY_ = 222;
+ public static final int SEEMP_API_android_provider_Settings__put_SHOW_PROCESSES_ = 223;
+ public static final int SEEMP_API_android_provider_Settings__put_SHOW_WEB_SUGGESTIONS_ = 224;
+ public static final int SEEMP_API_android_provider_Settings__put_SHOW_GTALK_SERVICE_STATUS_ = 225;
+ public static final int SEEMP_API_android_provider_Settings__put_USE_GOOGLE_MAIL_ = 226;
+ public static final int SEEMP_API_android_provider_Settings__put_AUTO_TIME_ = 227;
+ public static final int SEEMP_API_android_provider_Settings__put_AUTO_TIME_ZONE_ = 228;
+ public static final int SEEMP_API_android_provider_Settings__put_DATE_FORMAT_ = 229;
+ public static final int SEEMP_API_android_provider_Settings__put_TIME_12_24_ = 230;
+ public static final int SEEMP_API_android_provider_Settings__put_BLUETOOTH_DISCOVERABILITY_ = 231;
+ public static final int SEEMP_API_android_provider_Settings__put_BLUETOOTH_DISCOVERABILITY_TIMEOUT_ = 232;
+ public static final int SEEMP_API_android_provider_Settings__put_BLUETOOTH_ON_ = 233;
+ public static final int SEEMP_API_android_provider_Settings__put_DEVICE_PROVISIONED_ = 234;
+ public static final int SEEMP_API_android_provider_Settings__put_SETUP_WIZARD_HAS_RUN_ = 235;
+ public static final int SEEMP_API_android_provider_Settings__put_DTMF_TONE_WHEN_DIALING_ = 236;
+ public static final int SEEMP_API_android_provider_Settings__put_END_BUTTON_BEHAVIOR_ = 237;
+ public static final int SEEMP_API_android_provider_Settings__put_RINGTONE_ = 238;
+ public static final int SEEMP_API_android_provider_Settings__put_MODE_RINGER_ = 239;
+ public static final int SEEMP_API_android_provider_Settings__put_INSTALL_NON_MARKET_APPS_ = 240;
+ public static final int SEEMP_API_android_provider_Settings__put_LOCATION_PROVIDERS_ALLOWED_ = 241;
+ public static final int SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_ENABLED_ = 242;
+ public static final int SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_ = 243;
+ public static final int SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_VISIBLE_ = 244;
+ public static final int SEEMP_API_android_provider_Settings__put_NETWORK_PREFERENCE_ = 245;
+ public static final int SEEMP_API_android_provider_Settings__put_DATA_ROAMING_ = 246;
+ public static final int SEEMP_API_android_provider_Settings__put_HTTP_PROXY_ = 247;
+ public static final int SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_ENABLED_ = 248;
+ public static final int SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_LAST_UPDATE_ = 249;
+ public static final int SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_REDIRECT_URL_ = 250;
+ public static final int SEEMP_API_android_provider_Settings__put_RADIO_BLUETOOTH_ = 251;
+ public static final int SEEMP_API_android_provider_Settings__put_RADIO_CELL_ = 252;
+ public static final int SEEMP_API_android_provider_Settings__put_RADIO_NFC_ = 253;
+ public static final int SEEMP_API_android_provider_Settings__put_RADIO_WIFI_ = 254;
+ public static final int SEEMP_API_android_provider_Settings__put_SYS_PROP_SETTING_VERSION_ = 255;
+ public static final int SEEMP_API_android_provider_Settings__put_SETTINGS_CLASSNAME_ = 256;
+ public static final int SEEMP_API_android_provider_Settings__put_TEXT_AUTO_CAPS_ = 257;
+ public static final int SEEMP_API_android_provider_Settings__put_TEXT_AUTO_PUNCTUATE_ = 258;
+ public static final int SEEMP_API_android_provider_Settings__put_TEXT_AUTO_REPLACE_ = 259;
+ public static final int SEEMP_API_android_provider_Settings__put_TEXT_SHOW_PASSWORD_ = 260;
+ public static final int SEEMP_API_android_provider_Settings__put_USB_MASS_STORAGE_ENABLED_ = 261;
+ public static final int SEEMP_API_android_provider_Settings__put_VIBRATE_ON_ = 262;
+ public static final int SEEMP_API_android_provider_Settings__put_HAPTIC_FEEDBACK_ENABLED_ = 263;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_ALARM_ = 264;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_BLUETOOTH_SCO_ = 265;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_MUSIC_ = 266;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_NOTIFICATION_ = 267;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_RING_ = 268;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_SYSTEM_ = 269;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_VOICE_ = 270;
+ public static final int SEEMP_API_android_provider_Settings__put_SOUND_EFFECTS_ENABLED_ = 271;
+ public static final int SEEMP_API_android_provider_Settings__put_MODE_RINGER_STREAMS_AFFECTED_ = 272;
+ public static final int SEEMP_API_android_provider_Settings__put_MUTE_STREAMS_AFFECTED_ = 273;
+ public static final int SEEMP_API_android_provider_Settings__put_NOTIFICATION_SOUND_ = 274;
+ public static final int SEEMP_API_android_provider_Settings__put_APPEND_FOR_LAST_AUDIBLE_ = 275;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_MAX_DHCP_RETRY_COUNT_ = 276;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_ = 277;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_ = 278;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_ = 279;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_NUM_OPEN_NETWORKS_KEPT_ = 280;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_ON_ = 281;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_ = 282;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_DEFAULT_ = 283;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_NEVER_ = 284;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED_ = 285;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_DNS1_ = 286;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_DNS2_ = 287;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_GATEWAY_ = 288;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_IP_ = 289;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_NETMASK_ = 290;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_USE_STATIC_IP_ = 291;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_ = 292;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_AP_COUNT_ = 293;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_ = 294;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_ = 295;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_ = 296;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_ = 297;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_MAX_AP_CHECKS_ = 298;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_ON_ = 299;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_COUNT_ = 300;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_DELAY_MS_ = 301;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_TIMEOUT_MS_ = 302;
+
+ private final static java.util.Map<String,Integer> value_to_get_map;
+ static {
+ value_to_get_map = new java.util.HashMap<String,Integer>( 198 );
+ value_to_get_map.put(Settings.System.NOTIFICATION_SOUND,
+ SEEMP_API_android_provider_Settings__get_NOTIFICATION_SOUND_);
+ value_to_get_map.put(Settings.System.DTMF_TONE_WHEN_DIALING,
+ SEEMP_API_android_provider_Settings__get_DTMF_TONE_WHEN_DIALING_);
+ value_to_get_map.put(Settings.System.LOCK_PATTERN_ENABLED,
+ SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_ENABLED_);
+ value_to_get_map.put(Settings.System.WIFI_MAX_DHCP_RETRY_COUNT,
+ SEEMP_API_android_provider_Settings__get_WIFI_MAX_DHCP_RETRY_COUNT_);
+ value_to_get_map.put(Settings.System.AUTO_TIME,
+ SEEMP_API_android_provider_Settings__get_AUTO_TIME_);
+ value_to_get_map.put(Settings.System.SETUP_WIZARD_HAS_RUN,
+ SEEMP_API_android_provider_Settings__get_SETUP_WIZARD_HAS_RUN_);
+ value_to_get_map.put(Settings.System.SYS_PROP_SETTING_VERSION,
+ SEEMP_API_android_provider_Settings__get_SYS_PROP_SETTING_VERSION_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_);
+ value_to_get_map.put(Settings.System.LOCATION_PROVIDERS_ALLOWED,
+ SEEMP_API_android_provider_Settings__get_LOCATION_PROVIDERS_ALLOWED_);
+ value_to_get_map.put(Settings.System.ALARM_ALERT,
+ SEEMP_API_android_provider_Settings__get_ALARM_ALERT_);
+ value_to_get_map.put(Settings.System.VIBRATE_ON,
+ SEEMP_API_android_provider_Settings__get_VIBRATE_ON_);
+ value_to_get_map.put(Settings.System.USB_MASS_STORAGE_ENABLED,
+ SEEMP_API_android_provider_Settings__get_USB_MASS_STORAGE_ENABLED_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_PING_DELAY_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_DELAY_MS_);
+ value_to_get_map.put(Settings.System.FONT_SCALE,
+ SEEMP_API_android_provider_Settings__get_FONT_SCALE_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_AP_COUNT,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_AP_COUNT_);
+ value_to_get_map.put(Settings.System.ALWAYS_FINISH_ACTIVITIES,
+ SEEMP_API_android_provider_Settings__get_ALWAYS_FINISH_ACTIVITIES_);
+ value_to_get_map.put(Settings.System.ACCELEROMETER_ROTATION,
+ SEEMP_API_android_provider_Settings__get_ACCELEROMETER_ROTATION_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_PING_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_TIMEOUT_MS_);
+ value_to_get_map.put(Settings.System.VOLUME_NOTIFICATION,
+ SEEMP_API_android_provider_Settings__get_VOLUME_NOTIFICATION_);
+ value_to_get_map.put(Settings.System.AIRPLANE_MODE_ON,
+ SEEMP_API_android_provider_Settings__get_AIRPLANE_MODE_ON_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_IP,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_IP_);
+ value_to_get_map.put(Settings.System.RADIO_BLUETOOTH,
+ SEEMP_API_android_provider_Settings__get_RADIO_BLUETOOTH_);
+ value_to_get_map.put(Settings.System.BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+ SEEMP_API_android_provider_Settings__get_BLUETOOTH_DISCOVERABILITY_TIMEOUT_);
+ value_to_get_map.put(Settings.System.VOLUME_RING,
+ SEEMP_API_android_provider_Settings__get_VOLUME_RING_);
+ value_to_get_map.put(Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+ SEEMP_API_android_provider_Settings__get_MODE_RINGER_STREAMS_AFFECTED_);
+ value_to_get_map.put(Settings.System.VOLUME_SYSTEM,
+ SEEMP_API_android_provider_Settings__get_VOLUME_SYSTEM_);
+ value_to_get_map.put(Settings.System.SCREEN_OFF_TIMEOUT,
+ SEEMP_API_android_provider_Settings__get_SCREEN_OFF_TIMEOUT_);
+ value_to_get_map.put(Settings.System.RADIO_WIFI,
+ SEEMP_API_android_provider_Settings__get_RADIO_WIFI_);
+ value_to_get_map.put(Settings.System.AUTO_TIME_ZONE,
+ SEEMP_API_android_provider_Settings__get_AUTO_TIME_ZONE_);
+ value_to_get_map.put(Settings.System.TEXT_AUTO_CAPS,
+ SEEMP_API_android_provider_Settings__get_TEXT_AUTO_CAPS_);
+ value_to_get_map.put(Settings.System.WALLPAPER_ACTIVITY,
+ SEEMP_API_android_provider_Settings__get_WALLPAPER_ACTIVITY_);
+ value_to_get_map.put(Settings.System.ANIMATOR_DURATION_SCALE,
+ SEEMP_API_android_provider_Settings__get_ANIMATOR_DURATION_SCALE_);
+ value_to_get_map.put(Settings.System.WIFI_NUM_OPEN_NETWORKS_KEPT,
+ SEEMP_API_android_provider_Settings__get_WIFI_NUM_OPEN_NETWORKS_KEPT_);
+ value_to_get_map.put(Settings.System.LOCK_PATTERN_VISIBLE,
+ SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_VISIBLE_);
+ value_to_get_map.put(Settings.System.VOLUME_VOICE,
+ SEEMP_API_android_provider_Settings__get_VOLUME_VOICE_);
+ value_to_get_map.put(Settings.System.DEBUG_APP,
+ SEEMP_API_android_provider_Settings__get_DEBUG_APP_);
+ value_to_get_map.put(Settings.System.WIFI_ON,
+ SEEMP_API_android_provider_Settings__get_WIFI_ON_);
+ value_to_get_map.put(Settings.System.TEXT_SHOW_PASSWORD,
+ SEEMP_API_android_provider_Settings__get_TEXT_SHOW_PASSWORD_);
+ value_to_get_map.put(Settings.System.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+ SEEMP_API_android_provider_Settings__get_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_);
+ value_to_get_map.put(Settings.System.WIFI_SLEEP_POLICY,
+ SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_);
+ value_to_get_map.put(Settings.System.VOLUME_MUSIC,
+ SEEMP_API_android_provider_Settings__get_VOLUME_MUSIC_);
+ value_to_get_map.put(Settings.System.PARENTAL_CONTROL_LAST_UPDATE,
+ SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_LAST_UPDATE_);
+ value_to_get_map.put(Settings.System.DEVICE_PROVISIONED,
+ SEEMP_API_android_provider_Settings__get_DEVICE_PROVISIONED_);
+ value_to_get_map.put(Settings.System.HTTP_PROXY,
+ SEEMP_API_android_provider_Settings__get_HTTP_PROXY_);
+ value_to_get_map.put(Settings.System.ANDROID_ID,
+ SEEMP_API_android_provider_Settings__get_ANDROID_ID_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_MAX_AP_CHECKS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_MAX_AP_CHECKS_);
+ value_to_get_map.put(Settings.System.END_BUTTON_BEHAVIOR,
+ SEEMP_API_android_provider_Settings__get_END_BUTTON_BEHAVIOR_);
+ value_to_get_map.put(Settings.System.NEXT_ALARM_FORMATTED,
+ SEEMP_API_android_provider_Settings__get_NEXT_ALARM_FORMATTED_);
+ value_to_get_map.put(Settings.System.RADIO_CELL,
+ SEEMP_API_android_provider_Settings__get_RADIO_CELL_);
+ value_to_get_map.put(Settings.System.PARENTAL_CONTROL_ENABLED,
+ SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_ENABLED_);
+ value_to_get_map.put(Settings.System.BLUETOOTH_ON,
+ SEEMP_API_android_provider_Settings__get_BLUETOOTH_ON_);
+ value_to_get_map.put(Settings.System.WINDOW_ANIMATION_SCALE,
+ SEEMP_API_android_provider_Settings__get_WINDOW_ANIMATION_SCALE_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_);
+ value_to_get_map.put(Settings.System.BLUETOOTH_DISCOVERABILITY,
+ SEEMP_API_android_provider_Settings__get_BLUETOOTH_DISCOVERABILITY_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_DNS1,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_DNS1_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_DNS2,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_DNS2_);
+ value_to_get_map.put(Settings.System.HAPTIC_FEEDBACK_ENABLED,
+ SEEMP_API_android_provider_Settings__get_HAPTIC_FEEDBACK_ENABLED_);
+ value_to_get_map.put(Settings.System.SHOW_WEB_SUGGESTIONS,
+ SEEMP_API_android_provider_Settings__get_SHOW_WEB_SUGGESTIONS_);
+ value_to_get_map.put(Settings.System.PARENTAL_CONTROL_REDIRECT_URL,
+ SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_REDIRECT_URL_);
+ value_to_get_map.put(Settings.System.DATE_FORMAT,
+ SEEMP_API_android_provider_Settings__get_DATE_FORMAT_);
+ value_to_get_map.put(Settings.System.RADIO_NFC,
+ SEEMP_API_android_provider_Settings__get_RADIO_NFC_);
+ value_to_get_map.put(Settings.System.AIRPLANE_MODE_RADIOS,
+ SEEMP_API_android_provider_Settings__get_AIRPLANE_MODE_RADIOS_);
+ value_to_get_map.put(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED,
+ SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_);
+ value_to_get_map.put(Settings.System.TIME_12_24,
+ SEEMP_API_android_provider_Settings__get_TIME_12_24_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_);
+ value_to_get_map.put(Settings.System.VOLUME_BLUETOOTH_SCO,
+ SEEMP_API_android_provider_Settings__get_VOLUME_BLUETOOTH_SCO_);
+ value_to_get_map.put(Settings.System.USER_ROTATION,
+ SEEMP_API_android_provider_Settings__get_USER_ROTATION_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_GATEWAY,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_GATEWAY_);
+ value_to_get_map.put(Settings.System.STAY_ON_WHILE_PLUGGED_IN,
+ SEEMP_API_android_provider_Settings__get_STAY_ON_WHILE_PLUGGED_IN_);
+ value_to_get_map.put(Settings.System.SOUND_EFFECTS_ENABLED,
+ SEEMP_API_android_provider_Settings__get_SOUND_EFFECTS_ENABLED_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_PING_COUNT,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_COUNT_);
+ value_to_get_map.put(Settings.System.DATA_ROAMING,
+ SEEMP_API_android_provider_Settings__get_DATA_ROAMING_);
+ value_to_get_map.put(Settings.System.SETTINGS_CLASSNAME,
+ SEEMP_API_android_provider_Settings__get_SETTINGS_CLASSNAME_);
+ value_to_get_map.put(Settings.System.TRANSITION_ANIMATION_SCALE,
+ SEEMP_API_android_provider_Settings__get_TRANSITION_ANIMATION_SCALE_);
+ value_to_get_map.put(Settings.System.WAIT_FOR_DEBUGGER,
+ SEEMP_API_android_provider_Settings__get_WAIT_FOR_DEBUGGER_);
+ value_to_get_map.put(Settings.System.INSTALL_NON_MARKET_APPS,
+ SEEMP_API_android_provider_Settings__get_INSTALL_NON_MARKET_APPS_);
+ value_to_get_map.put(Settings.System.ADB_ENABLED,
+ SEEMP_API_android_provider_Settings__get_ADB_ENABLED_);
+ value_to_get_map.put(Settings.System.WIFI_USE_STATIC_IP,
+ SEEMP_API_android_provider_Settings__get_WIFI_USE_STATIC_IP_);
+ value_to_get_map.put(Settings.System.DIM_SCREEN,
+ SEEMP_API_android_provider_Settings__get_DIM_SCREEN_);
+ value_to_get_map.put(Settings.System.VOLUME_ALARM,
+ SEEMP_API_android_provider_Settings__get_VOLUME_ALARM_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_ON,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_ON_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_NETMASK,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_NETMASK_);
+ value_to_get_map.put(Settings.System.NETWORK_PREFERENCE,
+ SEEMP_API_android_provider_Settings__get_NETWORK_PREFERENCE_);
+ value_to_get_map.put(Settings.System.SHOW_PROCESSES,
+ SEEMP_API_android_provider_Settings__get_SHOW_PROCESSES_);
+ value_to_get_map.put(Settings.System.TEXT_AUTO_REPLACE,
+ SEEMP_API_android_provider_Settings__get_TEXT_AUTO_REPLACE_);
+ value_to_get_map.put(Settings.System.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ SEEMP_API_android_provider_Settings__get_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_);
+ value_to_get_map.put(Settings.System.APPEND_FOR_LAST_AUDIBLE,
+ SEEMP_API_android_provider_Settings__get_APPEND_FOR_LAST_AUDIBLE_);
+ value_to_get_map.put(Settings.System.SHOW_GTALK_SERVICE_STATUS,
+ SEEMP_API_android_provider_Settings__get_SHOW_GTALK_SERVICE_STATUS_);
+ value_to_get_map.put(Settings.System.SCREEN_BRIGHTNESS,
+ SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_);
+ value_to_get_map.put(Settings.System.USE_GOOGLE_MAIL,
+ SEEMP_API_android_provider_Settings__get_USE_GOOGLE_MAIL_);
+ value_to_get_map.put(Settings.System.RINGTONE,
+ SEEMP_API_android_provider_Settings__get_RINGTONE_);
+ value_to_get_map.put(Settings.System.LOGGING_ID,
+ SEEMP_API_android_provider_Settings__get_LOGGING_ID_);
+ value_to_get_map.put(Settings.System.MODE_RINGER,
+ SEEMP_API_android_provider_Settings__get_MODE_RINGER_);
+ value_to_get_map.put(Settings.System.MUTE_STREAMS_AFFECTED,
+ SEEMP_API_android_provider_Settings__get_MUTE_STREAMS_AFFECTED_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_);
+ value_to_get_map.put(Settings.System.TEXT_AUTO_PUNCTUATE,
+ SEEMP_API_android_provider_Settings__get_TEXT_AUTO_PUNCTUATE_);
+ value_to_get_map.put(Settings.System.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_);
+ value_to_get_map.put(Settings.System.SCREEN_BRIGHTNESS_MODE,
+ SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_MODE_);
+ }
+
+ public static int getSeempGetApiIdFromValue( String v )
+ {
+ Integer result = value_to_get_map.get( v );
+ if (result == null)
+ {
+ result = -1;
+ }
+ return result;
+ }
+
+ private final static java.util.Map<String,Integer> value_to_put_map;
+ static {
+ value_to_put_map = new java.util.HashMap<String,Integer>( 198 );
+ value_to_put_map.put(Settings.System.NOTIFICATION_SOUND,
+ SEEMP_API_android_provider_Settings__put_NOTIFICATION_SOUND_);
+ value_to_put_map.put(Settings.System.DTMF_TONE_WHEN_DIALING,
+ SEEMP_API_android_provider_Settings__put_DTMF_TONE_WHEN_DIALING_);
+ value_to_put_map.put(Settings.System.LOCK_PATTERN_ENABLED,
+ SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_ENABLED_);
+ value_to_put_map.put(Settings.System.WIFI_MAX_DHCP_RETRY_COUNT,
+ SEEMP_API_android_provider_Settings__put_WIFI_MAX_DHCP_RETRY_COUNT_);
+ value_to_put_map.put(Settings.System.AUTO_TIME,
+ SEEMP_API_android_provider_Settings__put_AUTO_TIME_);
+ value_to_put_map.put(Settings.System.SETUP_WIZARD_HAS_RUN,
+ SEEMP_API_android_provider_Settings__put_SETUP_WIZARD_HAS_RUN_);
+ value_to_put_map.put(Settings.System.SYS_PROP_SETTING_VERSION,
+ SEEMP_API_android_provider_Settings__put_SYS_PROP_SETTING_VERSION_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_);
+ value_to_put_map.put(Settings.System.LOCATION_PROVIDERS_ALLOWED,
+ SEEMP_API_android_provider_Settings__put_LOCATION_PROVIDERS_ALLOWED_);
+ value_to_put_map.put(Settings.System.ALARM_ALERT,
+ SEEMP_API_android_provider_Settings__put_ALARM_ALERT_);
+ value_to_put_map.put(Settings.System.VIBRATE_ON,
+ SEEMP_API_android_provider_Settings__put_VIBRATE_ON_);
+ value_to_put_map.put(Settings.System.USB_MASS_STORAGE_ENABLED,
+ SEEMP_API_android_provider_Settings__put_USB_MASS_STORAGE_ENABLED_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_PING_DELAY_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_DELAY_MS_);
+ value_to_put_map.put(Settings.System.FONT_SCALE,
+ SEEMP_API_android_provider_Settings__put_FONT_SCALE_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_AP_COUNT,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_AP_COUNT_);
+ value_to_put_map.put(Settings.System.ALWAYS_FINISH_ACTIVITIES,
+ SEEMP_API_android_provider_Settings__put_ALWAYS_FINISH_ACTIVITIES_);
+ value_to_put_map.put(Settings.System.ACCELEROMETER_ROTATION,
+ SEEMP_API_android_provider_Settings__put_ACCELEROMETER_ROTATION_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_PING_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_TIMEOUT_MS_);
+ value_to_put_map.put(Settings.System.VOLUME_NOTIFICATION,
+ SEEMP_API_android_provider_Settings__put_VOLUME_NOTIFICATION_);
+ value_to_put_map.put(Settings.System.AIRPLANE_MODE_ON,
+ SEEMP_API_android_provider_Settings__put_AIRPLANE_MODE_ON_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_IP,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_IP_);
+ value_to_put_map.put(Settings.System.RADIO_BLUETOOTH,
+ SEEMP_API_android_provider_Settings__put_RADIO_BLUETOOTH_);
+ value_to_put_map.put(Settings.System.BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+ SEEMP_API_android_provider_Settings__put_BLUETOOTH_DISCOVERABILITY_TIMEOUT_);
+ value_to_put_map.put(Settings.System.VOLUME_RING,
+ SEEMP_API_android_provider_Settings__put_VOLUME_RING_);
+ value_to_put_map.put(Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+ SEEMP_API_android_provider_Settings__put_MODE_RINGER_STREAMS_AFFECTED_);
+ value_to_put_map.put(Settings.System.VOLUME_SYSTEM,
+ SEEMP_API_android_provider_Settings__put_VOLUME_SYSTEM_);
+ value_to_put_map.put(Settings.System.SCREEN_OFF_TIMEOUT,
+ SEEMP_API_android_provider_Settings__put_SCREEN_OFF_TIMEOUT_);
+ value_to_put_map.put(Settings.System.RADIO_WIFI,
+ SEEMP_API_android_provider_Settings__put_RADIO_WIFI_);
+ value_to_put_map.put(Settings.System.AUTO_TIME_ZONE,
+ SEEMP_API_android_provider_Settings__put_AUTO_TIME_ZONE_);
+ value_to_put_map.put(Settings.System.TEXT_AUTO_CAPS,
+ SEEMP_API_android_provider_Settings__put_TEXT_AUTO_CAPS_);
+ value_to_put_map.put(Settings.System.WALLPAPER_ACTIVITY,
+ SEEMP_API_android_provider_Settings__put_WALLPAPER_ACTIVITY_);
+ value_to_put_map.put(Settings.System.ANIMATOR_DURATION_SCALE,
+ SEEMP_API_android_provider_Settings__put_ANIMATOR_DURATION_SCALE_);
+ value_to_put_map.put(Settings.System.WIFI_NUM_OPEN_NETWORKS_KEPT,
+ SEEMP_API_android_provider_Settings__put_WIFI_NUM_OPEN_NETWORKS_KEPT_);
+ value_to_put_map.put(Settings.System.LOCK_PATTERN_VISIBLE,
+ SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_VISIBLE_);
+ value_to_put_map.put(Settings.System.VOLUME_VOICE,
+ SEEMP_API_android_provider_Settings__put_VOLUME_VOICE_);
+ value_to_put_map.put(Settings.System.DEBUG_APP,
+ SEEMP_API_android_provider_Settings__put_DEBUG_APP_);
+ value_to_put_map.put(Settings.System.WIFI_ON,
+ SEEMP_API_android_provider_Settings__put_WIFI_ON_);
+ value_to_put_map.put(Settings.System.TEXT_SHOW_PASSWORD,
+ SEEMP_API_android_provider_Settings__put_TEXT_SHOW_PASSWORD_);
+ value_to_put_map.put(Settings.System.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+ SEEMP_API_android_provider_Settings__put_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_);
+ value_to_put_map.put(Settings.System.WIFI_SLEEP_POLICY,
+ SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_);
+ value_to_put_map.put(Settings.System.VOLUME_MUSIC,
+ SEEMP_API_android_provider_Settings__put_VOLUME_MUSIC_);
+ value_to_put_map.put(Settings.System.PARENTAL_CONTROL_LAST_UPDATE,
+ SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_LAST_UPDATE_);
+ value_to_put_map.put(Settings.System.DEVICE_PROVISIONED,
+ SEEMP_API_android_provider_Settings__put_DEVICE_PROVISIONED_);
+ value_to_put_map.put(Settings.System.HTTP_PROXY,
+ SEEMP_API_android_provider_Settings__put_HTTP_PROXY_);
+ value_to_put_map.put(Settings.System.ANDROID_ID,
+ SEEMP_API_android_provider_Settings__put_ANDROID_ID_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_MAX_AP_CHECKS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_MAX_AP_CHECKS_);
+ value_to_put_map.put(Settings.System.END_BUTTON_BEHAVIOR,
+ SEEMP_API_android_provider_Settings__put_END_BUTTON_BEHAVIOR_);
+ value_to_put_map.put(Settings.System.NEXT_ALARM_FORMATTED,
+ SEEMP_API_android_provider_Settings__put_NEXT_ALARM_FORMATTED_);
+ value_to_put_map.put(Settings.System.RADIO_CELL,
+ SEEMP_API_android_provider_Settings__put_RADIO_CELL_);
+ value_to_put_map.put(Settings.System.PARENTAL_CONTROL_ENABLED,
+ SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_ENABLED_);
+ value_to_put_map.put(Settings.System.BLUETOOTH_ON,
+ SEEMP_API_android_provider_Settings__put_BLUETOOTH_ON_);
+ value_to_put_map.put(Settings.System.WINDOW_ANIMATION_SCALE,
+ SEEMP_API_android_provider_Settings__put_WINDOW_ANIMATION_SCALE_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_);
+ value_to_put_map.put(Settings.System.BLUETOOTH_DISCOVERABILITY,
+ SEEMP_API_android_provider_Settings__put_BLUETOOTH_DISCOVERABILITY_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_DNS1,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_DNS1_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_DNS2,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_DNS2_);
+ value_to_put_map.put(Settings.System.HAPTIC_FEEDBACK_ENABLED,
+ SEEMP_API_android_provider_Settings__put_HAPTIC_FEEDBACK_ENABLED_);
+ value_to_put_map.put(Settings.System.SHOW_WEB_SUGGESTIONS,
+ SEEMP_API_android_provider_Settings__put_SHOW_WEB_SUGGESTIONS_);
+ value_to_put_map.put(Settings.System.PARENTAL_CONTROL_REDIRECT_URL,
+ SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_REDIRECT_URL_);
+ value_to_put_map.put(Settings.System.DATE_FORMAT,
+ SEEMP_API_android_provider_Settings__put_DATE_FORMAT_);
+ value_to_put_map.put(Settings.System.RADIO_NFC,
+ SEEMP_API_android_provider_Settings__put_RADIO_NFC_);
+ value_to_put_map.put(Settings.System.AIRPLANE_MODE_RADIOS,
+ SEEMP_API_android_provider_Settings__put_AIRPLANE_MODE_RADIOS_);
+ value_to_put_map.put(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED,
+ SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_);
+ value_to_put_map.put(Settings.System.TIME_12_24,
+ SEEMP_API_android_provider_Settings__put_TIME_12_24_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_);
+ value_to_put_map.put(Settings.System.VOLUME_BLUETOOTH_SCO,
+ SEEMP_API_android_provider_Settings__put_VOLUME_BLUETOOTH_SCO_);
+ value_to_put_map.put(Settings.System.USER_ROTATION,
+ SEEMP_API_android_provider_Settings__put_USER_ROTATION_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_GATEWAY,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_GATEWAY_);
+ value_to_put_map.put(Settings.System.STAY_ON_WHILE_PLUGGED_IN,
+ SEEMP_API_android_provider_Settings__put_STAY_ON_WHILE_PLUGGED_IN_);
+ value_to_put_map.put(Settings.System.SOUND_EFFECTS_ENABLED,
+ SEEMP_API_android_provider_Settings__put_SOUND_EFFECTS_ENABLED_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_PING_COUNT,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_COUNT_);
+ value_to_put_map.put(Settings.System.DATA_ROAMING,
+ SEEMP_API_android_provider_Settings__put_DATA_ROAMING_);
+ value_to_put_map.put(Settings.System.SETTINGS_CLASSNAME,
+ SEEMP_API_android_provider_Settings__put_SETTINGS_CLASSNAME_);
+ value_to_put_map.put(Settings.System.TRANSITION_ANIMATION_SCALE,
+ SEEMP_API_android_provider_Settings__put_TRANSITION_ANIMATION_SCALE_);
+ value_to_put_map.put(Settings.System.WAIT_FOR_DEBUGGER,
+ SEEMP_API_android_provider_Settings__put_WAIT_FOR_DEBUGGER_);
+ value_to_put_map.put(Settings.System.INSTALL_NON_MARKET_APPS,
+ SEEMP_API_android_provider_Settings__put_INSTALL_NON_MARKET_APPS_);
+ value_to_put_map.put(Settings.System.ADB_ENABLED,
+ SEEMP_API_android_provider_Settings__put_ADB_ENABLED_);
+ value_to_put_map.put(Settings.System.WIFI_USE_STATIC_IP,
+ SEEMP_API_android_provider_Settings__put_WIFI_USE_STATIC_IP_);
+ value_to_put_map.put(Settings.System.DIM_SCREEN,
+ SEEMP_API_android_provider_Settings__put_DIM_SCREEN_);
+ value_to_put_map.put(Settings.System.VOLUME_ALARM,
+ SEEMP_API_android_provider_Settings__put_VOLUME_ALARM_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_ON,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_ON_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_NETMASK,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_NETMASK_);
+ value_to_put_map.put(Settings.System.NETWORK_PREFERENCE,
+ SEEMP_API_android_provider_Settings__put_NETWORK_PREFERENCE_);
+ value_to_put_map.put(Settings.System.SHOW_PROCESSES,
+ SEEMP_API_android_provider_Settings__put_SHOW_PROCESSES_);
+ value_to_put_map.put(Settings.System.TEXT_AUTO_REPLACE,
+ SEEMP_API_android_provider_Settings__put_TEXT_AUTO_REPLACE_);
+ value_to_put_map.put(Settings.System.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ SEEMP_API_android_provider_Settings__put_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_);
+ value_to_put_map.put(Settings.System.APPEND_FOR_LAST_AUDIBLE,
+ SEEMP_API_android_provider_Settings__put_APPEND_FOR_LAST_AUDIBLE_);
+ value_to_put_map.put(Settings.System.SHOW_GTALK_SERVICE_STATUS,
+ SEEMP_API_android_provider_Settings__put_SHOW_GTALK_SERVICE_STATUS_);
+ value_to_put_map.put(Settings.System.SCREEN_BRIGHTNESS,
+ SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_);
+ value_to_put_map.put(Settings.System.USE_GOOGLE_MAIL,
+ SEEMP_API_android_provider_Settings__put_USE_GOOGLE_MAIL_);
+ value_to_put_map.put(Settings.System.RINGTONE,
+ SEEMP_API_android_provider_Settings__put_RINGTONE_);
+ value_to_put_map.put(Settings.System.LOGGING_ID,
+ SEEMP_API_android_provider_Settings__put_LOGGING_ID_);
+ value_to_put_map.put(Settings.System.MODE_RINGER,
+ SEEMP_API_android_provider_Settings__put_MODE_RINGER_);
+ value_to_put_map.put(Settings.System.MUTE_STREAMS_AFFECTED,
+ SEEMP_API_android_provider_Settings__put_MUTE_STREAMS_AFFECTED_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_);
+ value_to_put_map.put(Settings.System.TEXT_AUTO_PUNCTUATE,
+ SEEMP_API_android_provider_Settings__put_TEXT_AUTO_PUNCTUATE_);
+ value_to_put_map.put(Settings.System.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_);
+ value_to_put_map.put(Settings.System.SCREEN_BRIGHTNESS_MODE,
+ SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_MODE_);
+ }
+
+ public static int getSeempPutApiIdFromValue( String v )
+ {
+ Integer result = value_to_put_map.get( v );
+ if (result == null)
+ {
+ result = -1;
+ }
+ return result;
+ }
+}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 1269ad9..7b2d299 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -778,6 +778,9 @@ public final class Display {
synchronized (this) {
updateDisplayInfoLocked();
mDisplayInfo.getAppMetrics(outMetrics, mDisplayAdjustments);
+ if (getDisplayId() == DEFAULT_DISPLAY) {
+ outMetrics.densityDpi = DisplayMetrics.DENSITY_DEVICE_DEFAULT;
+ }
}
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index ee76274..85321f9 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -564,6 +564,11 @@ public final class DisplayInfo implements Parcelable {
if (!compatInfo.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
compatInfo.applyToDisplayMetrics(outMetrics);
+ } else if (type == Display.TYPE_BUILT_IN
+ && (flags & Display.FLAG_PRESENTATION) == 0) {
+ outMetrics.setDensity(DisplayMetrics.DENSITY_PREFERRED);
+ } else {
+ outMetrics.setDensity(logicalDensityDpi);
}
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 5994d4f..b3f4046 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -130,7 +130,7 @@ interface IWindowManager
boolean inKeyguardRestrictedInputMode();
void dismissKeyguard();
void keyguardGoingAway(boolean disableWindowAnimations,
- boolean keyguardGoingToNotificationShade);
+ boolean keyguardGoingToNotificationShade, boolean keyguardShowingMedia);
void closeSystemDialogs(String reason);
@@ -232,6 +232,16 @@ interface IWindowManager
Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth, int maxHeight);
/**
+ * Get the current x offset for the wallpaper
+ */
+ int getLastWallpaperX();
+
+ /**
+ * Get the current y offset for the wallpaper
+ */
+ int getLastWallpaperY();
+
+ /**
* Called by the status bar to notify Views of changes to System UI visiblity.
*/
oneway void statusBarVisibilityChanged(int visibility);
@@ -240,6 +250,12 @@ interface IWindowManager
* Device has a software navigation bar (separate from the status bar).
*/
boolean hasNavigationBar();
+ boolean hasPermanentMenuKey();
+
+ /**
+ * Device needs a software navigation bar (because it has no hardware keys).
+ */
+ boolean needsNavigationBar();
/**
* Lock the device immediately with the specified options (can be null).
@@ -271,4 +287,6 @@ interface IWindowManager
* @return The frame statistics or null if the window does not exist.
*/
WindowContentFrameStats getWindowContentFrameStats(IBinder token);
+
+ void setLiveLockscreenEdgeDetector(boolean enable);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 73b4a6e..3956237 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -185,6 +185,16 @@ interface IWindowSession {
*/
void setWallpaperDisplayOffset(IBinder windowToken, int x, int y);
+ /**
+ * Get the current x offset for the wallpaper
+ */
+ int getLastWallpaperX();
+
+ /**
+ * Get the current y offset for the wallpaper
+ */
+ int getLastWallpaperY();
+
Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, in Bundle extras, boolean sync);
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index cc4598d..5f88c11 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -256,6 +256,15 @@ public final class InputDevice implements Parcelable {
public static final int SOURCE_TOUCH_NAVIGATION = 0x00200000 | SOURCE_CLASS_NONE;
/**
+ * The input source is a rotating encoder device whose motions should be interpreted as akin to
+ * those of a scroll wheel.
+ *
+ * @see #SOURCE_CLASS_NONE
+ * {@hide}
+ */
+ public static final int SOURCE_ROTARY_ENCODER = 0x00400000 | SOURCE_CLASS_NONE;
+
+ /**
* The input source is a joystick.
* (It may also be a {@link #SOURCE_GAMEPAD}).
*
@@ -272,6 +281,18 @@ public final class InputDevice implements Parcelable {
public static final int SOURCE_HDMI = 0x02000000 | SOURCE_CLASS_BUTTON;
/**
+ * The input source is a touch device whose motions should be interpreted as gestures.
+ *
+ * For example, an upward swipe should be treated the same as a swipe of the touchscreen.
+ * The same should apply for left, right, down swipes. Complex gestures may also be input.
+ *
+ * @see #SOURCE_CLASS_NONE
+ *
+ * @hide
+ */
+ public static final int SOURCE_GESTURE_SENSOR = 0x10000000 | SOURCE_CLASS_NONE;
+
+ /**
* A special input source constant that is used when filtering input devices
* to match devices that provide any type of input source.
*/
@@ -948,6 +969,7 @@ public final class InputDevice implements Parcelable {
appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHPAD, "touchpad");
appendSourceDescriptionIfApplicable(description, SOURCE_JOYSTICK, "joystick");
appendSourceDescriptionIfApplicable(description, SOURCE_GAMEPAD, "gamepad");
+ appendSourceDescriptionIfApplicable(description, SOURCE_GESTURE_SENSOR, "gesture");
description.append(" )\n");
final int numAxes = mMotionRanges.size();
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index a9bf92b..d128288 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -761,6 +761,19 @@ public class KeyEvent extends InputEvent implements Parcelable {
* Backs out one level of a navigation hierarchy or collapses the item that currently has
* focus. */
public static final int KEYCODE_NAVIGATE_OUT = 263;
+ /** Key code constant: Primary stem key for Wear
+ * Main power/reset button on watch.
+ * @hide */
+ public static final int KEYCODE_STEM_PRIMARY = 264;
+ /** Key code constant: Generic stem key 1 for Wear
+ * @hide */
+ public static final int KEYCODE_STEM_1 = 265;
+ /** Key code constant: Generic stem key 2 for Wear
+ * @hide */
+ public static final int KEYCODE_STEM_2 = 266;
+ /** Key code constant: Generic stem key 3 for Wear
+ * @hide */
+ public static final int KEYCODE_STEM_3 = 267;
/** Key code constant: Skip forward media key. */
public static final int KEYCODE_MEDIA_SKIP_FORWARD = 272;
/** Key code constant: Skip backward media key. */
@@ -771,8 +784,11 @@ public class KeyEvent extends InputEvent implements Parcelable {
/** Key code constant: Step backward media key.
* Steps media backward, one frame at a time. */
public static final int KEYCODE_MEDIA_STEP_BACKWARD = 275;
+ /** Key code constant: put device to sleep unless a wakelock is held.
+ * @hide */
+ public static final int KEYCODE_SOFT_SLEEP = 276;
- private static final int LAST_KEYCODE = KEYCODE_MEDIA_STEP_BACKWARD;
+ private static final int LAST_KEYCODE = KEYCODE_SOFT_SLEEP;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
@@ -1828,8 +1844,17 @@ public class KeyEvent extends InputEvent implements Parcelable {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_MENU:
+ case KeyEvent.KEYCODE_HOME:
case KeyEvent.KEYCODE_WAKEUP:
case KeyEvent.KEYCODE_PAIRING:
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ case KeyEvent.KEYCODE_CAMERA:
+ case KeyEvent.KEYCODE_FOCUS:
+ 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/MotionEvent.java b/core/java/android/view/MotionEvent.java
index a8d0b90..e0c9d59 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -977,6 +977,22 @@ public final class MotionEvent extends InputEvent implements Parcelable {
public static final int AXIS_TILT = 25;
/**
+ * Axis constant: Generic scroll axis of a motion event.
+ * <p>
+ * <ul>
+ * <li>Reports the relative movement of the generic scrolling device.
+ * </ul>
+ * </p><p>
+ * This axis should be used for scroll events that are neither strictly vertical nor horizontal.
+ * A good example would be the rotation of a rotary encoder input device.
+ * </p>
+ *
+ * @see #getAxisValue(int, int)
+ * {@hide}
+ */
+ public static final int AXIS_SCROLL = 26;
+
+ /**
* Axis constant: Generic 1 axis of a motion event.
* The interpretation of a generic axis is device-specific.
*
@@ -1186,6 +1202,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
names.append(AXIS_BRAKE, "AXIS_BRAKE");
names.append(AXIS_DISTANCE, "AXIS_DISTANCE");
names.append(AXIS_TILT, "AXIS_TILT");
+ names.append(AXIS_SCROLL, "AXIS_SCROLL");
names.append(AXIS_GENERIC_1, "AXIS_GENERIC_1");
names.append(AXIS_GENERIC_2, "AXIS_GENERIC_2");
names.append(AXIS_GENERIC_3, "AXIS_GENERIC_3");
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index bcf9b2c..e839468 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -58,6 +58,11 @@ public class SurfaceControl {
private static native void nativeSetWindowCrop(long nativeObject, int l, int t, int r, int b);
private static native void nativeSetLayerStack(long nativeObject, int layerStack);
+ private static native void nativeSetBlur(long nativeObject, float blur);
+ private static native void nativeSetBlurMaskSurface(long nativeObject, long maskLayerNativeObject);
+ private static native void nativeSetBlurMaskSampling(long nativeObject, int blurMaskSampling);
+ private static native void nativeSetBlurMaskAlphaThreshold(long nativeObject, float alpha);
+
private static native boolean nativeClearContentFrameStats(long nativeObject);
private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats);
private static native boolean nativeClearAnimationFrameStats();
@@ -170,6 +175,11 @@ public class SurfaceControl {
public static final int FX_SURFACE_NORMAL = 0x00000000;
/**
+ * Surface creation flag: Creates a blur surface.
+ */
+ public static final int FX_SURFACE_BLUR = 0x00010000;
+
+ /**
* Surface creation flag: Creates a Dim surface.
* Everything behind this surface is dimmed by the amount specified
* in {@link #setAlpha}. It is an error to lock a Dim surface, since it
@@ -215,6 +225,12 @@ public class SurfaceControl {
*/
public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
+ /**
+ * Built-in physical display id: Attached HDMI display.
+ * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
+ */
+ public static final int BUILT_IN_DISPLAY_ID_TERTIARY = 2;
+
/* Display power modes * /
/**
@@ -378,6 +394,29 @@ public class SurfaceControl {
nativeSetSize(mNativeObject, w, h);
}
+ public void setBlur(float blur) {
+ checkNotReleased();
+ nativeSetBlur(mNativeObject, blur);
+ }
+
+ public void setBlurMaskSurface(SurfaceControl maskSurface) {
+ checkNotReleased();
+ if (maskSurface != null) {
+ maskSurface.checkNotReleased();
+ }
+ nativeSetBlurMaskSurface(mNativeObject, maskSurface == null ? 0:maskSurface.mNativeObject);
+ }
+
+ public void setBlurMaskSampling(int blurMaskSampling) {
+ checkNotReleased();
+ nativeSetBlurMaskSampling(mNativeObject, blurMaskSampling);
+ }
+
+ public void setBlurMaskAlphaThreshold(float alpha) {
+ checkNotReleased();
+ nativeSetBlurMaskAlphaThreshold(mNativeObject, alpha);
+ }
+
public void hide() {
checkNotReleased();
nativeSetFlags(mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index f6119e2..db147ab 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -145,9 +145,10 @@ public class ThreadedRenderer extends HardwareRenderer {
@Override
boolean initialize(Surface surface) throws OutOfResourcesException {
+ boolean status = !mInitialized;
mInitialized = true;
updateEnabledState(surface);
- boolean status = nInitialize(mNativeProxy, surface);
+ nInitialize(mNativeProxy, surface);
return status;
}
@@ -503,7 +504,7 @@ public class ThreadedRenderer extends HardwareRenderer {
private static native boolean nLoadSystemProperties(long nativeProxy);
private static native void nSetName(long nativeProxy, String name);
- private static native boolean nInitialize(long nativeProxy, Surface window);
+ private static native void nInitialize(long nativeProxy, Surface window);
private static native void nUpdateSurface(long nativeProxy, Surface window);
private static native boolean nPauseSurface(long nativeProxy, Surface window);
private static native void nSetup(long nativeProxy, int width, int height,
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index dea004e..4b56352 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9284,6 +9284,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
final int actionMasked = event.getActionMasked();
if (actionMasked == MotionEvent.ACTION_DOWN) {
+ android.util.SeempLog.record(3);
// Defensive cleanup for new gesture
stopNestedScroll();
}
@@ -9828,6 +9829,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param event The KeyEvent object that defines the button action.
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
+ android.util.SeempLog.record(4);
boolean result = false;
if (KeyEvent.isConfirmKey(keyCode)) {
@@ -9872,6 +9874,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param event The KeyEvent object that defines the button action.
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
+ android.util.SeempLog.record(5);
if (KeyEvent.isConfirmKey(keyCode)) {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
@@ -10269,6 +10272,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return True if the event was handled, false otherwise.
*/
public boolean onTouchEvent(MotionEvent event) {
+ android.util.SeempLog.record(3);
final float x = event.getX();
final float y = event.getY();
final int viewFlags = mViewFlags;
@@ -15940,8 +15944,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
RenderNode renderNode = null;
Bitmap cache = null;
int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local
- if (layerType == LAYER_TYPE_SOFTWARE
- || (!drawingWithRenderNode && layerType != LAYER_TYPE_NONE)) {
+ if (!drawingWithRenderNode && layerType != LAYER_TYPE_NONE) {
// If not drawing with RenderNode, treat HW layers as SW
layerType = LAYER_TYPE_SOFTWARE;
buildDrawingCache(true);
@@ -16937,8 +16940,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@CallSuper
protected boolean verifyDrawable(Drawable who) {
- return who == mBackground || (mScrollCache != null && mScrollCache.scrollBar == who)
- || (mForegroundInfo != null && mForegroundInfo.mDrawable == who);
+ // Avoid verifying the scroll bar drawable so that we don't end up in
+ // an invalidation loop. This effectively prevents the scroll bar
+ // drawable from triggering invalidations and scheduling runnables.
+ return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who);
}
/**
@@ -21717,7 +21722,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Last global system UI visibility reported by the window manager.
*/
- int mGlobalSystemUiVisibility;
+ int mGlobalSystemUiVisibility = -1;
/**
* True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 4d584a3..93f5779 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -317,7 +317,7 @@ public class ViewConfiguration {
case HAS_PERMANENT_MENU_KEY_AUTODETECT: {
IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
try {
- sHasPermanentMenuKey = !wm.hasNavigationBar();
+ sHasPermanentMenuKey = wm.hasPermanentMenuKey();
sHasPermanentMenuKeySet = true;
} catch (RemoteException ex) {
sHasPermanentMenuKey = false;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 42402eb..9569422 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -174,6 +174,10 @@ public final class ViewRootImpl implements ViewParent,
// so the window should no longer be active.
boolean mStopped = false;
+ // Set to true if the owner of this window is in ambient mode,
+ // which means it won't receive input events.
+ boolean mIsAmbientMode = false;
+
// Set to true to stop input during an Activity Transition.
boolean mPausedForTransition = false;
@@ -990,6 +994,10 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ public void setIsAmbientMode(boolean ambient) {
+ mIsAmbientMode = ambient;
+ }
+
void setWindowStopped(boolean stopped) {
if (mStopped != stopped) {
mStopped = stopped;
@@ -3704,7 +3712,7 @@ public final class ViewRootImpl implements ViewParent,
return true;
} else if ((!mAttachInfo.mHasWindowFocus
&& !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
- || (mPausedForTransition && !isBack(q.mEvent))) {
+ || mIsAmbientMode || (mPausedForTransition && !isBack(q.mEvent))) {
// This is a focus event and the window doesn't currently have input focus or
// has stopped. This could be an event that came back from the previous stage
// but the window has lost focus or stopped in the meantime.
@@ -5514,6 +5522,8 @@ public final class ViewRootImpl implements ViewParent,
writer.println(mProcessInputEventsScheduled);
writer.print(innerPrefix); writer.print("mTraversalScheduled=");
writer.print(mTraversalScheduled);
+ writer.print(innerPrefix); writer.print("mIsAmbientMode=");
+ writer.print(mIsAmbientMode);
if (mTraversalScheduled) {
writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
} else {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index c222a82..65577f0 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -199,6 +199,7 @@ public abstract class Window {
private boolean mHaveWindowFormat = false;
private boolean mHaveDimAmount = false;
+ private boolean mHaveBlurAmount = false;
private int mDefaultWindowFormat = PixelFormat.OPAQUE;
private boolean mHasSoftInputMode = false;
@@ -818,6 +819,13 @@ public abstract class Window {
setPrivateFlags(flags, flags);
}
+ /** @hide */
+ public void setBlurMaskAlphaThreshold(float alpha) {
+ final WindowManager.LayoutParams attrs = getAttributes();
+ attrs.blurMaskAlphaThreshold = alpha;
+ dispatchWindowAttributesChanged(attrs);
+ }
+
/**
* Convenience function to clear the flag bits as specified in flags, as
* per {@link #setFlags}.
@@ -829,6 +837,11 @@ public abstract class Window {
setFlags(0, flags);
}
+ /** @hide */
+ public void clearPrivateFlags(int flags) {
+ setPrivateFlags(0, flags);
+ }
+
/**
* Set the flags of the window, as per the
* {@link WindowManager.LayoutParams WindowManager.LayoutParams}
@@ -856,6 +869,13 @@ public abstract class Window {
}
private void setPrivateFlags(int flags, int mask) {
+ int preventFlags = WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_POWER_KEY |
+ WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_SYSTEM_KEYS;
+
+ if ((flags & mask & preventFlags) != 0) {
+ mContext.enforceCallingOrSelfPermission("android.permission.PREVENT_SYSTEM_KEYS",
+ "No permission to prevent system key");
+ }
final WindowManager.LayoutParams attrs = getAttributes();
attrs.privateFlags = (attrs.privateFlags & ~mask) | (flags & mask);
dispatchWindowAttributesChanged(attrs);
@@ -895,6 +915,19 @@ public abstract class Window {
}
/**
+ * Set the amount of blur behind the window when using
+ * {@link WindowManager.LayoutParams#FLAG_BLUR_BEHIND}.
+ * This feature may not be supported by all devices.
+ * {@hide}
+ */
+ public void setBlurAmount(float amount) {
+ final WindowManager.LayoutParams attrs = getAttributes();
+ attrs.blurAmount = amount;
+ mHaveBlurAmount = true;
+ dispatchWindowAttributesChanged(attrs);
+ }
+
+ /**
* Specify custom window attributes. <strong>PLEASE NOTE:</strong> the
* layout params you give here should generally be from values previously
* retrieved with {@link #getAttributes()}; you probably do not want to
@@ -1404,6 +1437,11 @@ public abstract class Window {
return mHaveDimAmount;
}
+ /** @hide */
+ protected boolean haveBlurAmount() {
+ return mHaveBlurAmount;
+ }
+
public abstract void setChildDrawable(int featureId, Drawable drawable);
public abstract void setChildInt(int featureId, int value);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 45bc1df..36f593e 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -186,6 +186,7 @@ public interface WindowManager extends ViewManager {
* @see #TYPE_SYSTEM_ERROR
* @see #TYPE_INPUT_METHOD
* @see #TYPE_INPUT_METHOD_DIALOG
+ * @see #TYPE_KEYGUARD_PANEL
*/
@ViewDebug.ExportedProperty(mapping = {
@ViewDebug.IntToString(from = TYPE_BASE_APPLICATION, to = "TYPE_BASE_APPLICATION"),
@@ -226,6 +227,7 @@ public interface WindowManager extends ViewManager {
@ViewDebug.IntToString(from = TYPE_PRIVATE_PRESENTATION, to = "TYPE_PRIVATE_PRESENTATION"),
@ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION, to = "TYPE_VOICE_INTERACTION"),
@ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING, to = "TYPE_VOICE_INTERACTION_STARTING"),
+ @ViewDebug.IntToString(from = TYPE_KEYGUARD_PANEL, to = "TYPE_KEYGUARD_PANEL"),
})
public int type;
@@ -565,6 +567,13 @@ public interface WindowManager extends ViewManager {
public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33;
/**
+ * Window type: Windows that are layered within the keyguard
+ * This type is LAST_SYSTEM_WINDOW-1 to avoid future conflicts with AOSP
+ * @hide
+ */
+ public static final int TYPE_KEYGUARD_PANEL = FIRST_SYSTEM_WINDOW+998;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
@@ -1128,6 +1137,48 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT = 0x00001000;
/**
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_STATUS_HIDE_FORCED = 0x00800000;
+
+ /**
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_NAV_HIDE_FORCED = 0x01000000;
+
+ /**
+ * The window had not set FULLSCREEN flag so don't handle it as fullscreen in layoutWindowLw
+ *
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_WAS_NOT_FULLSCREEN = 0x02000000;
+
+ /**
+ * Window flag: Overrides default system key behavior.
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_PREVENT_SYSTEM_KEYS = 0x10000000;
+
+ /**
+ * Window flag: Overrides default system key behavior.
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_PREVENT_POWER_KEY = 0x20000000;
+
+ /**
+ * Window flag: adding additional blur layer and set this as masking layer
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_BLUR_WITH_MASKING = 0x40000000;
+
+ /**
+ * Window flag: adding additional blur layer and set this as masking layer.
+ * This is faster and ugglier than non-scaled version.
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_BLUR_WITH_MASKING_SCALED = 0x80000000;
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
@@ -1389,6 +1440,15 @@ public interface WindowManager extends ViewManager {
public float dimAmount = 1.0f;
/**
+ * When {@link #FLAG_BLUR_BEHIND} is set, this is the amount of blur
+ * to apply. Range is from 1.0 for maximum to 0.0 for no
+ * blur.
+ * @hide
+ */
+ public float blurAmount = 1.0f;
+
+
+ /**
* Default value for {@link #screenBrightness} and {@link #buttonBrightness}
* indicating that the brightness value is not overridden for this window
* and normal brightness policy should be used.
@@ -1581,6 +1641,14 @@ public interface WindowManager extends ViewManager {
*/
public long userActivityTimeout = -1;
+ /**
+ * Threshold value that blur masking layer uses to determine whether
+ * to use or discard the blurred color.
+ * Value should be between 0.0 and 1.0
+ * @hide
+ */
+ public float blurMaskAlphaThreshold = 0.0f;
+
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
@@ -1667,6 +1735,7 @@ public interface WindowManager extends ViewManager {
out.writeInt(windowAnimations);
out.writeFloat(alpha);
out.writeFloat(dimAmount);
+ out.writeFloat(blurAmount);
out.writeFloat(screenBrightness);
out.writeFloat(buttonBrightness);
out.writeInt(rotationAnimation);
@@ -1687,6 +1756,7 @@ public interface WindowManager extends ViewManager {
out.writeInt(surfaceInsets.bottom);
out.writeInt(hasManualSurfaceInsets ? 1 : 0);
out.writeInt(needsMenuKey);
+ out.writeFloat(blurMaskAlphaThreshold);
}
public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1717,6 +1787,7 @@ public interface WindowManager extends ViewManager {
windowAnimations = in.readInt();
alpha = in.readFloat();
dimAmount = in.readFloat();
+ blurAmount = in.readFloat();
screenBrightness = in.readFloat();
buttonBrightness = in.readFloat();
rotationAnimation = in.readInt();
@@ -1737,6 +1808,7 @@ public interface WindowManager extends ViewManager {
surfaceInsets.bottom = in.readInt();
hasManualSurfaceInsets = in.readInt() != 0;
needsMenuKey = in.readInt();
+ blurMaskAlphaThreshold = in.readFloat();
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -1776,6 +1848,10 @@ public interface WindowManager extends ViewManager {
/** {@hide} */
public static final int PREFERRED_DISPLAY_MODE_ID = 1 << 23;
/** {@hide} */
+ public static final int BLUR_AMOUNT_CHANGED = 1 << 29;
+ /** {@hide} */
+ public static final int BLUR_MASK_ALPHA_THRESHOLD_CHANGED = 1 << 30;
+ /** {@hide} */
public static final int EVERYTHING_CHANGED = 0xffffffff;
// internal buffer to backup/restore parameters under compatibility mode.
@@ -1870,6 +1946,10 @@ public interface WindowManager extends ViewManager {
dimAmount = o.dimAmount;
changes |= DIM_AMOUNT_CHANGED;
}
+ if (blurAmount != o.blurAmount) {
+ blurAmount = o.blurAmount;
+ changes |= BLUR_AMOUNT_CHANGED;
+ }
if (screenBrightness != o.screenBrightness) {
screenBrightness = o.screenBrightness;
changes |= SCREEN_BRIGHTNESS_CHANGED;
@@ -1935,6 +2015,11 @@ public interface WindowManager extends ViewManager {
changes |= NEEDS_MENU_KEY_CHANGED;
}
+ if (blurMaskAlphaThreshold != o.blurMaskAlphaThreshold) {
+ blurMaskAlphaThreshold = o.blurMaskAlphaThreshold;
+ changes |= BLUR_MASK_ALPHA_THRESHOLD_CHANGED;
+ }
+
return changes;
}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 98e9f54..95e291c 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -81,12 +81,14 @@ public final class WindowManagerImpl implements WindowManager {
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
+ android.util.SeempLog.record_vg_layout(383,params);
applyDefaultToken(params);
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
+ android.util.SeempLog.record_vg_layout(384,params);
applyDefaultToken(params);
mGlobal.updateViewLayout(view, params);
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index aaf6052..d19096b 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -453,6 +453,8 @@ public interface WindowManagerPolicy {
/** Unregister a system listener for touch events */
void unregisterPointerEventListener(PointerEventListener listener);
+
+ void addSystemUIVisibilityFlag(int flags);
}
public interface PointerEventListener {
@@ -663,6 +665,11 @@ public interface WindowManagerPolicy {
public WindowState getWinShowWhenLockedLw();
/**
+ * Returns the current keyguard panel, if such a thing exists.
+ */
+ public WindowState getWinKeyguardPanelLw();
+
+ /**
* Called when the system would like to show a UI to indicate that an
* application is starting. You can use this to add a
* APPLICATION_STARTING_TYPE window with the given appToken to the window
@@ -778,7 +785,8 @@ public interface WindowManagerPolicy {
* Create and return an animation to let the wallpaper disappear after being shown on a force
* hiding window.
*/
- public Animation createForceHideWallpaperExitAnimation(boolean goingToNotificationShade);
+ public Animation createForceHideWallpaperExitAnimation(boolean goingToNotificationShade,
+ boolean keyguardShowingMedia);
/**
* Called from the input reader thread before a key is enqueued.
@@ -1237,6 +1245,12 @@ public interface WindowManagerPolicy {
* Specifies whether there is an on-screen navigation bar separate from the status bar.
*/
public boolean hasNavigationBar();
+ public boolean hasPermanentMenuKey();
+
+ /**
+ * Specifies whether the device needs a navigation bar (because it has no hardware buttons)
+ */
+ public boolean needsNavigationBar();
/**
* Lock the device now.
@@ -1311,4 +1325,6 @@ public interface WindowManagerPolicy {
* @param fadeoutDuration the duration of the exit animation, in milliseconds
*/
public void startKeyguardExitAnimation(long startTime, long fadeoutDuration);
+
+ public void setLiveLockscreenEdgeDetector(boolean enable);
}
diff --git a/core/java/android/view/WindowManagerPolicyControl.java b/core/java/android/view/WindowManagerPolicyControl.java
new file mode 100644
index 0000000..cdba239
--- /dev/null
+++ b/core/java/android/view/WindowManagerPolicyControl.java
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 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.view;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerPolicy.WindowState;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Iterator;
+
+/**
+ * Runtime adjustments applied to the global window policy.
+ *
+ * This includes forcing immersive mode behavior for one or both system bars (based on a package
+ * list) and permanently disabling immersive mode confirmations for specific packages.
+ *
+ * Control by setting {@link Settings.Global.POLICY_CONTROL} to one or more name-value pairs.
+ * e.g.
+ * to force immersive mode everywhere:
+ * "immersive.full=*"
+ * to force transient status for all apps except a specific package:
+ * "immersive.status=apps,-com.package"
+ * to disable the immersive mode confirmations for specific packages:
+ * "immersive.preconfirms=com.package.one,com.package.two"
+ *
+ * Separate multiple name-value pairs with ':'
+ * e.g. "immersive.status=apps:immersive.preconfirms=*"
+ *
+ * @hide
+ */
+public class WindowManagerPolicyControl {
+ private static String TAG = "PolicyControl";
+ private static boolean DEBUG = false;
+
+ private static final String NAME_IMMERSIVE_FULL = "immersive.full";
+ private static final String NAME_IMMERSIVE_STATUS = "immersive.status";
+ private static final String NAME_IMMERSIVE_NAVIGATION = "immersive.navigation";
+ private static final String NAME_IMMERSIVE_PRECONFIRMATIONS = "immersive.preconfirms";
+
+ private static int sDefaultImmersiveStyle;
+ private static String sSettingValue;
+ private static Filter sImmersivePreconfirmationsFilter;
+ private static Filter sImmersiveStatusFilter;
+ private static Filter sImmersiveNavigationFilter;
+
+ /**
+ * Accessible constants for Settings
+ */
+ public final static class ImmersiveDefaultStyles {
+ public final static int IMMERSIVE_FULL = 0;
+ public final static int IMMERSIVE_STATUS = 1;
+ public final static int IMMERSIVE_NAVIGATION = 2;
+ }
+
+ public static int getSystemUiVisibility(WindowState win, LayoutParams attrs) {
+ attrs = attrs != null ? attrs : win.getAttrs();
+ int vis = win != null ? win.getSystemUiVisibility() : attrs.systemUiVisibility;
+ if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)
+ && (sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_FULL ||
+ sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_STATUS)) {
+ vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.STATUS_BAR_TRANSLUCENT);
+ }
+ if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)
+ && (sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_FULL ||
+ sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_NAVIGATION)) {
+ vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+ vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.NAVIGATION_BAR_TRANSLUCENT);
+ }
+ return vis;
+ }
+
+ public static int getWindowFlags(WindowState win, LayoutParams attrs) {
+ attrs = attrs != null ? attrs : win.getAttrs();
+ int flags = attrs.flags;
+
+ if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)
+ && (sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_FULL ||
+ sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_STATUS)) {
+ flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
+ flags &= ~(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+ | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+ }
+ if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)
+ && (sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_FULL ||
+ sDefaultImmersiveStyle == ImmersiveDefaultStyles.IMMERSIVE_NAVIGATION)) {
+ flags &= ~WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+ }
+ return flags;
+ }
+
+ public static int getPrivateWindowFlags(WindowState win, LayoutParams attrs) {
+ attrs = attrs != null ? attrs : win.getAttrs();
+ int privateFlags = attrs.privateFlags;
+
+ if (sImmersiveStatusFilter != null && sImmersiveNavigationFilter != null &&
+ sImmersiveStatusFilter.isEnabledForAll()
+ && sImmersiveNavigationFilter.isEnabledForAll()) {
+
+ if ((attrs.flags & LayoutParams.FLAG_FULLSCREEN) == 0) {
+ privateFlags |= LayoutParams.PRIVATE_FLAG_WAS_NOT_FULLSCREEN;
+ }
+
+ switch (sDefaultImmersiveStyle) {
+ case ImmersiveDefaultStyles.IMMERSIVE_FULL:
+ privateFlags |= LayoutParams.PRIVATE_FLAG_NAV_HIDE_FORCED;
+ privateFlags |= LayoutParams.PRIVATE_FLAG_STATUS_HIDE_FORCED;
+ return privateFlags;
+ case ImmersiveDefaultStyles.IMMERSIVE_STATUS:
+ privateFlags |= LayoutParams.PRIVATE_FLAG_STATUS_HIDE_FORCED;
+ return privateFlags;
+ case ImmersiveDefaultStyles.IMMERSIVE_NAVIGATION:
+ privateFlags |= LayoutParams.PRIVATE_FLAG_NAV_HIDE_FORCED;
+ return privateFlags;
+ }
+ }
+
+ if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
+ if ((attrs.flags & LayoutParams.FLAG_FULLSCREEN) == 0) {
+ privateFlags |= LayoutParams.PRIVATE_FLAG_WAS_NOT_FULLSCREEN;
+ }
+ privateFlags |= LayoutParams.PRIVATE_FLAG_STATUS_HIDE_FORCED;
+ }
+
+ if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
+ privateFlags |= LayoutParams.PRIVATE_FLAG_NAV_HIDE_FORCED;
+ }
+
+ return privateFlags;
+ }
+
+ public static boolean immersiveStatusFilterMatches(String packageName) {
+ return sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(packageName);
+ }
+
+ public static boolean immersiveNavigationFilterMatches(String packageName) {
+ return sImmersiveNavigationFilter != null
+ && sImmersiveNavigationFilter.matches(packageName);
+ }
+
+ public static int adjustClearableFlags(WindowState win, int clearableFlags) {
+ final LayoutParams attrs = win != null ? win.getAttrs() : null;
+ if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
+ clearableFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
+ }
+ return clearableFlags;
+ }
+
+ public static boolean disableImmersiveConfirmation(String pkg) {
+ return (sImmersivePreconfirmationsFilter != null
+ && sImmersivePreconfirmationsFilter.matches(pkg))
+ || ActivityManager.isRunningInTestHarness();
+ }
+
+ public static void reloadFromSetting(Context context) {
+ reloadStyleFromSetting(context, Settings.Global.POLICY_CONTROL_STYLE);
+ reloadFromSetting(context, Settings.Global.POLICY_CONTROL);
+ }
+
+ public static void reloadFromSetting(Context context, String key) {
+ if (DEBUG) Slog.d(TAG, "reloadFromSetting()");
+ String value = null;
+ try {
+ value = Settings.Global.getStringForUser(context.getContentResolver(),
+ key,
+ UserHandle.USER_CURRENT);
+ if (sSettingValue != null && sSettingValue.equals(value)) return;
+ setFilters(value);
+ sSettingValue = value;
+ } catch (Throwable t) {
+ Slog.w(TAG, "Error loading policy control, value=" + value, t);
+ }
+ }
+
+ public static void reloadStyleFromSetting(Context context, String key) {
+ sDefaultImmersiveStyle = Settings.Global.getInt(context.getContentResolver(),
+ key, WindowManagerPolicyControl.ImmersiveDefaultStyles.IMMERSIVE_FULL);
+ if (DEBUG) Slog.d(TAG, "reloadStyleFromSetting " + sDefaultImmersiveStyle);
+ }
+
+ public static void saveToSettings(Context context) {
+ saveToSettings(context, Settings.Global.POLICY_CONTROL);
+ }
+
+ public static void saveToSettings(Context context, String key) {
+ StringBuilder value = new StringBuilder();
+ boolean needSemicolon = false;
+ if (sImmersiveStatusFilter != null) {
+ writeFilter(NAME_IMMERSIVE_STATUS, sImmersiveStatusFilter, value);
+ needSemicolon = true;
+ }
+ if (sImmersiveNavigationFilter != null) {
+ if (needSemicolon) {
+ value.append(":");
+ }
+ writeFilter(NAME_IMMERSIVE_NAVIGATION, sImmersiveNavigationFilter, value);
+ }
+
+ Settings.Global.putString(context.getContentResolver(), key, value.toString());
+ }
+
+ public static void saveStyleToSettings(Context context, int value) {
+ Settings.Global.putInt(context.getContentResolver(),
+ Settings.Global.POLICY_CONTROL_STYLE, value);
+ sDefaultImmersiveStyle = value;
+ }
+
+ public static void addToStatusWhiteList(String packageName) {
+ if (sImmersiveStatusFilter == null) {
+ sImmersiveStatusFilter = new Filter(new ArraySet<String>(), new ArraySet<String>());
+ }
+
+ if (!sImmersiveStatusFilter.mWhitelist.contains(packageName)) {
+ sImmersiveStatusFilter.mWhitelist.add(packageName);
+ }
+ }
+
+ public static void addToNavigationWhiteList(String packageName) {
+ if (sImmersiveNavigationFilter == null) {
+ sImmersiveNavigationFilter = new Filter(new ArraySet<String>(), new ArraySet<String>());
+ }
+
+ if (!sImmersiveNavigationFilter.mWhitelist.contains(packageName)) {
+ sImmersiveNavigationFilter.mWhitelist.add(packageName);
+ }
+ }
+
+ public static void removeFromWhiteLists(String packageName) {
+ if (sImmersiveStatusFilter != null) {
+ sImmersiveStatusFilter.mWhitelist.remove(packageName);
+ }
+ if (sImmersiveNavigationFilter != null) {
+ sImmersiveNavigationFilter.mWhitelist.remove(packageName);
+ }
+ }
+
+ public static ArraySet<String> getWhiteLists() {
+ ArraySet<String> result = new ArraySet<>();
+
+ if (sImmersiveStatusFilter != null) {
+ result.addAll(sImmersiveStatusFilter.mWhitelist);
+ }
+ if (sImmersiveNavigationFilter != null
+ && sImmersiveNavigationFilter != sImmersiveStatusFilter) {
+ result.addAll(sImmersiveNavigationFilter.mWhitelist);
+ }
+
+ return result;
+ }
+
+ private static void writeFilter(String name, Filter filter, StringBuilder stringBuilder) {
+ if (filter.mWhitelist.isEmpty() && filter.mBlacklist.isEmpty()) {
+ return;
+ }
+ stringBuilder.append(name);
+ stringBuilder.append("=");
+
+ boolean needComma = false;
+ if (!filter.mWhitelist.isEmpty()) {
+ writePackages(filter.mWhitelist, stringBuilder, false);
+ needComma = true;
+ }
+ if (!filter.mBlacklist.isEmpty()) {
+ if (needComma) {
+ stringBuilder.append(",");
+ }
+ writePackages(filter.mBlacklist, stringBuilder, true);
+ }
+ }
+
+ private static void writePackages(ArraySet<String> set, StringBuilder stringBuilder,
+ boolean isBlackList) {
+ Iterator<String> iterator = set.iterator();
+ while (iterator.hasNext()) {
+ if (isBlackList) {
+ stringBuilder.append("-");
+ }
+ String name = iterator.next();
+ stringBuilder.append(name);
+ if (iterator.hasNext()) {
+ stringBuilder.append(",");
+ }
+ }
+ }
+
+ public static boolean isImmersiveFiltersActive() {
+ return sImmersiveStatusFilter != null || sImmersiveNavigationFilter != null;
+ }
+
+ public static void dump(String prefix, PrintWriter pw) {
+ dump("sImmersiveStatusFilter", sImmersiveStatusFilter, prefix, pw);
+ dump("sImmersiveNavigationFilter", sImmersiveNavigationFilter, prefix, pw);
+ dump("sImmersivePreconfirmationsFilter", sImmersivePreconfirmationsFilter, prefix, pw);
+ }
+
+ private static void dump(String name, Filter filter, String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("PolicyControl."); pw.print(name); pw.print('=');
+ if (filter == null) {
+ pw.println("null");
+ } else {
+ filter.dump(pw); pw.println();
+ }
+ }
+
+ private static void setFilters(String value) {
+ if (DEBUG) Slog.d(TAG, "setFilters: " + value);
+ sImmersiveStatusFilter = null;
+ sImmersiveNavigationFilter = null;
+ sImmersivePreconfirmationsFilter = null;
+ if (value != null) {
+ String[] nvps = value.split(":");
+ for (String nvp : nvps) {
+ int i = nvp.indexOf('=');
+ if (i == -1) continue;
+ String n = nvp.substring(0, i);
+ String v = nvp.substring(i + 1);
+ if (n.equals(NAME_IMMERSIVE_FULL)) {
+ Filter f = Filter.parse(v);
+ sImmersiveStatusFilter = sImmersiveNavigationFilter = f;
+ if (sImmersivePreconfirmationsFilter == null) {
+ sImmersivePreconfirmationsFilter = f;
+ }
+ } else if (n.equals(NAME_IMMERSIVE_STATUS)) {
+ Filter f = Filter.parse(v);
+ sImmersiveStatusFilter = f;
+ } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) {
+ Filter f = Filter.parse(v);
+ sImmersiveNavigationFilter = f;
+ if (sImmersivePreconfirmationsFilter == null) {
+ sImmersivePreconfirmationsFilter = f;
+ }
+ } else if (n.equals(NAME_IMMERSIVE_PRECONFIRMATIONS)) {
+ Filter f = Filter.parse(v);
+ sImmersivePreconfirmationsFilter = f;
+ }
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "immersiveStatusFilter: " + sImmersiveStatusFilter);
+ Slog.d(TAG, "immersiveNavigationFilter: " + sImmersiveNavigationFilter);
+ Slog.d(TAG, "immersivePreconfirmationsFilter: " + sImmersivePreconfirmationsFilter);
+ }
+ }
+
+ private static class Filter {
+ private static final String ALL = "*";
+ private static final String APPS = "apps";
+
+ private final ArraySet<String> mWhitelist;
+ private final ArraySet<String> mBlacklist;
+
+ private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
+ mWhitelist = whitelist;
+ mBlacklist = blacklist;
+ }
+
+ boolean matches(LayoutParams attrs) {
+ if (attrs == null) return false;
+ boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+ && attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+ if (isApp && mBlacklist.contains(APPS)) return false;
+ if (onBlacklist(attrs.packageName)) return false;
+ if (isApp && mWhitelist.contains(APPS)) return true;
+ return onWhitelist(attrs.packageName);
+ }
+
+ boolean matches(String packageName) {
+ return !onBlacklist(packageName) && onWhitelist(packageName);
+ }
+
+ public boolean isEnabledForAll() {
+ return mWhitelist.contains(ALL);
+ }
+
+ private boolean onBlacklist(String packageName) {
+ return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
+ }
+
+ private boolean onWhitelist(String packageName) {
+ return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
+ }
+
+ void dump(PrintWriter pw) {
+ pw.print("Filter[");
+ dump("whitelist", mWhitelist, pw); pw.print(',');
+ dump("blacklist", mBlacklist, pw); pw.print(']');
+ }
+
+ private void dump(String name, ArraySet<String> set, PrintWriter pw) {
+ pw.print(name); pw.print("=(");
+ final int n = set.size();
+ for (int i = 0; i < n; i++) {
+ if (i > 0) pw.print(',');
+ pw.print(set.valueAt(i));
+ }
+ pw.print(')');
+ }
+
+ @Override
+ public String toString() {
+ StringWriter sw = new StringWriter();
+ dump(new PrintWriter(sw, true));
+ return sw.toString();
+ }
+
+ // value = comma-delimited list of tokens, where token = (package name|apps|*)
+ // e.g. "com.package1", or "apps, com.android.keyguard" or "*"
+ static Filter parse(String value) {
+ if (value == null) return null;
+ ArraySet<String> whitelist = new ArraySet<String>();
+ ArraySet<String> blacklist = new ArraySet<String>();
+ for (String token : value.split(",")) {
+ token = token.trim();
+ if (token.startsWith("-") && token.length() > 1) {
+ token = token.substring(1);
+ blacklist.add(token);
+ } else {
+ whitelist.add(token);
+ }
+ }
+ return new Filter(whitelist, blacklist);
+ }
+ }
+}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 4737e9b..01fcc1a 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -290,7 +290,9 @@ public class WebChromeClient {
* origin.
*/
public void onGeolocationPermissionsShowPrompt(String origin,
- GeolocationPermissions.Callback callback) {}
+ GeolocationPermissions.Callback callback) {
+ android.util.SeempLog.record(54);
+ }
/**
* Notify the host application that a request for Geolocation permissions,
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 584deff..93b1e56 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -97,7 +97,14 @@ public final class WebViewFactory {
}
public static String getWebViewPackageName() {
- return AppGlobals.getInitialApplication().getString(
+ Application initialApp = AppGlobals.getInitialApplication();
+ String pkg = initialApp.getString(
+ com.android.internal.R.string.config_alternateWebViewPackageName);
+ /* Attempt to use alternate WebView package first */
+ if (isPackageInstalled(initialApp, pkg)) {
+ return pkg;
+ }
+ return initialApp.getString(
com.android.internal.R.string.config_webViewPackageName);
}
@@ -529,6 +536,14 @@ public final class WebViewFactory {
return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
}
+ private static boolean isPackageInstalled(Context context, String packageName) {
+ try {
+ return context.getPackageManager().getPackageInfo(packageName, 0) != null;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
private static native boolean nativeCreateRelroFile(String lib32, String lib64,
String relro32, String relro64);
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index a4c8d1c..31bc536 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -663,7 +663,14 @@ public abstract class AbsSeekBar extends ProgressBar {
progress += scale * max;
setHotspot(x, (int) event.getY());
- setProgress((int) progress, true);
+ setProgress(updateTouchProgress(getProgress(), (int) progress), true);
+ }
+
+ /**
+ * @hide
+ */
+ protected int updateTouchProgress(int lastProgress, int newProgress) {
+ return newProgress;
}
/**
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index c40289e..559181b 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -383,6 +383,7 @@ class FastScroller {
break;
}
}
+ ta.recycle();
updateAppearance();
}
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index b5e08ca..df3d850 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -348,7 +348,6 @@ public class LinearLayout extends ViewGroup {
final int count = getVirtualChildCount();
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
-
if (child != null && child.getVisibility() != GONE) {
if (hasDividerBeforeChildAt(i)) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
@@ -377,7 +376,7 @@ public class LinearLayout extends ViewGroup {
*/
private View getLastNonGoneChild() {
for (int i = getVirtualChildCount() - 1; i >= 0; i--) {
- View child = getVirtualChildAt(i);
+ final View child = getVirtualChildAt(i);
if (child != null && child.getVisibility() != GONE) {
return child;
}
@@ -390,7 +389,6 @@ public class LinearLayout extends ViewGroup {
final boolean isLayoutRtl = isLayoutRtl();
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
-
if (child != null && child.getVisibility() != GONE) {
if (hasDividerBeforeChildAt(i)) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
@@ -577,8 +575,9 @@ public class LinearLayout extends ViewGroup {
* for an example.</p>
*
* @param index the child's index
- * @return the child at the specified index
+ * @return the child at the specified index, may be {@code null}
*/
+ @Nullable
View getVirtualChildAt(int index) {
return getChildAt(index);
}
@@ -659,7 +658,7 @@ public class LinearLayout extends ViewGroup {
*/
private boolean allViewsAreGoneBefore(int childIndex) {
for (int i = childIndex - 1; i >= 0; i--) {
- View child = getVirtualChildAt(i);
+ final View child = getVirtualChildAt(i);
if (child != null && child.getVisibility() != GONE) {
return false;
}
@@ -703,7 +702,6 @@ public class LinearLayout extends ViewGroup {
// See how tall everyone is. Also remember max width.
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
-
if (child == null) {
mTotalLength += measureNullChild(i);
continue;
@@ -822,7 +820,6 @@ public class LinearLayout extends ViewGroup {
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
-
if (child == null) {
mTotalLength += measureNullChild(i);
continue;
@@ -938,7 +935,6 @@ public class LinearLayout extends ViewGroup {
if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
-
if (child == null || child.getVisibility() == View.GONE) {
continue;
}
@@ -981,7 +977,7 @@ public class LinearLayout extends ViewGroup {
MeasureSpec.EXACTLY);
for (int i = 0; i< count; ++i) {
final View child = getVirtualChildAt(i);
- if (child.getVisibility() != GONE) {
+ if (child != null && child.getVisibility() != GONE) {
LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams());
if (lp.width == LayoutParams.MATCH_PARENT) {
@@ -1047,7 +1043,6 @@ public class LinearLayout extends ViewGroup {
// See how wide everyone is. Also remember max height.
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
-
if (child == null) {
mTotalLength += measureNullChild(i);
continue;
@@ -1203,7 +1198,6 @@ public class LinearLayout extends ViewGroup {
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
-
if (child == null) {
mTotalLength += measureNullChild(i);
continue;
@@ -1361,7 +1355,6 @@ public class LinearLayout extends ViewGroup {
if (useLargestChild && widthMode != MeasureSpec.EXACTLY) {
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
-
if (child == null || child.getVisibility() == View.GONE) {
continue;
}
@@ -1406,7 +1399,7 @@ public class LinearLayout extends ViewGroup {
MeasureSpec.EXACTLY);
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
- if (child.getVisibility() != GONE) {
+ if (child != null && child.getVisibility() != GONE) {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
if (lp.height == LayoutParams.MATCH_PARENT) {
@@ -1666,9 +1659,8 @@ public class LinearLayout extends ViewGroup {
}
for (int i = 0; i < count; i++) {
- int childIndex = start + dir * i;
+ final int childIndex = start + dir * i;
final View child = getVirtualChildAt(childIndex);
-
if (child == null) {
childLeft += measureNullChild(childIndex);
} else if (child.getVisibility() != GONE) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 7ca3339..6a272e5 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -31,6 +31,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.graphics.Rect;
@@ -55,6 +56,8 @@ import android.view.ViewGroup;
import android.widget.AdapterView.OnItemClickListener;
import libcore.util.Objects;
+import com.android.internal.R;
+
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -206,14 +209,22 @@ public class RemoteViews implements Parcelable, Filter {
/** @hide */
public static class OnClickHandler {
+
+ private int mEnterAnimationId;
+
public boolean onClickHandler(View view, PendingIntent pendingIntent,
Intent fillInIntent) {
try {
// TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
Context context = view.getContext();
- ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view,
- 0, 0,
- view.getMeasuredWidth(), view.getMeasuredHeight());
+ ActivityOptions opts;
+ if (mEnterAnimationId != 0) {
+ opts = ActivityOptions.makeCustomAnimation(context, mEnterAnimationId, 0);
+ } else {
+ opts = ActivityOptions.makeScaleUpAnimation(view,
+ 0, 0,
+ view.getMeasuredWidth(), view.getMeasuredHeight());
+ }
context.startIntentSender(
pendingIntent.getIntentSender(), fillInIntent,
Intent.FLAG_ACTIVITY_NEW_TASK,
@@ -228,6 +239,10 @@ public class RemoteViews implements Parcelable, Filter {
}
return true;
}
+
+ public void setEnterAnimationId(int enterAnimationId) {
+ mEnterAnimationId = enterAnimationId;
+ }
}
/**
@@ -2729,6 +2744,12 @@ public class RemoteViews implements Parcelable, Filter {
/** @hide */
public View apply(Context context, ViewGroup parent, OnClickHandler handler) {
+ return apply(context, parent, handler, null);
+ }
+
+ /** @hide */
+ public View apply(Context context, ViewGroup parent, OnClickHandler handler,
+ String themePackageName) {
RemoteViews rvToApply = getRemoteViewsToApply(context);
View result;
@@ -2736,7 +2757,7 @@ public class RemoteViews implements Parcelable, Filter {
// user. So build a context that loads resources from that user but
// still returns the current users userId so settings like data / time formats
// are loaded without requiring cross user persmissions.
- final Context contextForResources = getContextForResources(context);
+ final Context contextForResources = getContextForResources(context, themePackageName);
Context inflationContext = new ContextWrapper(context) {
@Override
public Resources getResources() {
@@ -2761,11 +2782,31 @@ public class RemoteViews implements Parcelable, Filter {
inflater.setFilter(this);
result = inflater.inflate(rvToApply.getLayoutId(), parent, false);
+ loadTransitionOverride(context, handler);
+
rvToApply.performApply(result, parent, handler);
return result;
}
+ private static void loadTransitionOverride(Context context,
+ RemoteViews.OnClickHandler handler) {
+ if (handler != null && context.getResources().getBoolean(
+ com.android.internal.R.bool.config_overrideRemoteViewsActivityTransition)) {
+ TypedArray windowStyle = context.getTheme().obtainStyledAttributes(
+ com.android.internal.R.styleable.Window);
+ int windowAnimations = windowStyle.getResourceId(
+ com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
+ TypedArray windowAnimationStyle = context.obtainStyledAttributes(
+ windowAnimations, com.android.internal.R.styleable.WindowAnimation);
+ handler.setEnterAnimationId(windowAnimationStyle.getResourceId(
+ com.android.internal.R.styleable.
+ WindowAnimation_activityOpenRemoteViewsEnterAnimation, 0));
+ windowStyle.recycle();
+ windowAnimationStyle.recycle();
+ }
+ }
+
/**
* Applies all of the actions to the provided view.
*
@@ -2806,14 +2847,15 @@ public class RemoteViews implements Parcelable, Filter {
}
}
- private Context getContextForResources(Context context) {
+ private Context getContextForResources(Context context, String themePackageName) {
if (mApplication != null) {
if (context.getUserId() == UserHandle.getUserId(mApplication.uid)
- && context.getPackageName().equals(mApplication.packageName)) {
+ && context.getPackageName().equals(mApplication.packageName)
+ && themePackageName == null) {
return context;
}
try {
- return context.createApplicationContext(mApplication,
+ return context.createApplicationContext(mApplication, themePackageName,
Context.CONTEXT_RESTRICTED);
} catch (NameNotFoundException e) {
Log.e(LOG_TAG, "Package name " + mApplication.packageName + " not found");
diff --git a/core/java/android/widget/TableRow.java b/core/java/android/widget/TableRow.java
index f7f9c91..22931fc 100644
--- a/core/java/android/widget/TableRow.java
+++ b/core/java/android/widget/TableRow.java
@@ -98,7 +98,7 @@ public class TableRow extends LinearLayout {
* {@hide}
*/
void setColumnCollapsed(int columnIndex, boolean collapsed) {
- View child = getVirtualChildAt(columnIndex);
+ final View child = getVirtualChildAt(columnIndex);
if (child != null) {
child.setVisibility(collapsed ? GONE : VISIBLE);
}
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index bcde315..d5a3f16 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -548,6 +548,7 @@ public class TextClock extends TextView {
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ filter.addAction(Intent.ACTION_DOZE_PULSE_STARTING);
getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
}
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 207f675..e8dccab 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -18,12 +18,15 @@ package android.widget;
import android.annotation.IntDef;
import android.annotation.StringRes;
+import android.app.ActivityManager;
import android.app.INotificationManager;
import android.app.ITransientNotification;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -400,6 +403,22 @@ public class Toast {
if (context == null) {
context = mView.getContext();
}
+
+ ImageView appIcon = (ImageView) mView.findViewById(android.R.id.icon);
+ if (appIcon != null) {
+ ActivityManager am =
+ (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ if (!am.isPackageInForeground(packageName)) {
+ PackageManager pm = context.getPackageManager();
+ Drawable icon = null;
+ try {
+ icon = pm.getApplicationIcon(packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ // nothing to do
+ }
+ appIcon.setImageDrawable(icon);
+ }
+ }
mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
// We can resolve the Gravity here by using the Locale for getting
// the layout direction
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 9fa2c23..aa1c265 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -46,4 +46,12 @@ interface IAppOpsService {
void setUserRestrictions(in Bundle restrictions, int userHandle);
void removeUser(int userHandle);
+ boolean isControlAllowed(int code, String packageName);
+
+ // Privacy guard methods
+ boolean getPrivacyGuardSettingForPackage(int uid, String packageName);
+ void setPrivacyGuardSettingForPackage(int uid, String packageName, boolean state);
+
+ // AppOps accounting
+ void resetCounters();
}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 3cddbf6..ba92f48 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2016 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -121,4 +122,18 @@ interface IBatteryStats {
void setBatteryState(int status, int health, int plugType, int level, int temp, int volt);
long getAwakeTimeBattery();
long getAwakeTimePlugged();
+
+
+ /** @hide */
+ byte[] getDockStatistics();
+ /** @hide */
+ ParcelFileDescriptor getDockStatisticsStream();
+ /** @hide **/
+ void resetStatistics();
+ /** @hide **/
+ void setDockBatteryState(int status, int health, int plugType, int level, int temp, int volt);
+ /** @hide **/
+ long getAwakeTimeDockBattery();
+ /** @hide **/
+ long getAwakeTimeDockPlugged();
}
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 4efefa9..83160cd 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -41,6 +44,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.ArrayList;
+import java.util.Arrays;
public class LocalePicker extends ListFragment {
private static final String TAG = "LocalePicker";
@@ -83,12 +87,23 @@ public class LocalePicker extends ListFragment {
}
}
+ public static ArrayList<String> getLocaleArray(String[] locales, Resources resources) {
+ String locale_codes = resources.getString(R.string.locale_codes);
+ String[] localeCodesArray = null;
+ if (locale_codes != null && !"".equals(locale_codes.trim())) {
+ localeCodesArray = locale_codes.split(",");
+ }
+ ArrayList<String> localeList = new ArrayList<String>(
+ Arrays.asList((localeCodesArray == null || localeCodesArray.length == 0) ? locales
+ : localeCodesArray));
+ return localeList;
+ }
+
public static List<LocaleInfo> getAllAssetLocales(Context context, boolean isInDeveloperMode) {
final Resources resources = context.getResources();
- final String[] locales = Resources.getSystem().getAssets().getLocales();
- List<String> localeList = new ArrayList<String>(locales.length);
- Collections.addAll(localeList, locales);
+ String[] locales = Resources.getSystem().getAssets().getLocales();
+ ArrayList<String> localeList = getLocaleArray(locales, resources);
// Don't show the pseudolocales unless we're in developer mode. http://b/17190407.
if (!isInDeveloperMode) {
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 2595fe0..efe88ff 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2014-2015 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -57,10 +58,13 @@ public class PlatLogoActivity extends Activity {
int mKeyCount;
PathInterpolator mInterpolator = new PathInterpolator(0f, 0f, 0.5f, 1f);
+ private boolean mIsCM;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mIsCM = getIntent().hasExtra("is_cm");
mLayout = new FrameLayout(this);
setContentView(mLayout);
}
@@ -153,6 +157,7 @@ public class PlatLogoActivity extends Activity {
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ .putExtra("is_cm", mIsCM)
.addCategory("com.android.internal.category.PLATLOGO"));
} catch (ActivityNotFoundException ex) {
Log.e("PlatLogoActivity", "No more eggs.");
@@ -202,7 +207,9 @@ public class PlatLogoActivity extends Activity {
}
public void showMarshmallow(View im) {
- final Drawable fg = getDrawable(com.android.internal.R.drawable.platlogo);
+ final Drawable fg = getDrawable(mIsCM
+ ? com.android.internal.R.drawable.platlogo_cm
+ : com.android.internal.R.drawable.platlogo);
fg.setBounds(0, 0, im.getWidth(), im.getHeight());
fg.setAlpha(0);
im.getOverlay().add(fg);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 4ba678c..4c3cc4d 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -91,8 +91,9 @@ public class ResolverActivity extends Activity {
private ResolveListAdapter mAdapter;
private PackageManager mPm;
private boolean mSafeForwardingMode;
- private boolean mAlwaysUseOption;
+ /*package*/ boolean mAlwaysUseOption;
private AbsListView mAdapterView;
+ private ViewGroup mFilteredItemContainer;
private Button mAlwaysButton;
private Button mOnceButton;
private View mProfileView;
@@ -305,6 +306,21 @@ public class ResolverActivity extends Activity {
}
if (mAdapter.hasFilteredItem()) {
+ mFilteredItemContainer = (ViewGroup) findViewById(R.id.filtered_item_container);
+ mFilteredItemContainer.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ DisplayResolveInfo filteredItem = mAdapter.getFilteredItem();
+
+ if (filteredItem == null) {
+ return false;
+ }
+
+ showAppDetails(filteredItem.getResolveInfo());
+ return true;
+ }
+ });
+
setAlwaysButtonEnabled(true, mAdapter.getFilteredPosition(), false);
mOnceButton.setEnabled(true);
}
@@ -1555,7 +1571,7 @@ public class ResolverActivity extends Activity {
return mDisplayList.get(index);
}
- public final View getView(int position, View convertView, ViewGroup parent) {
+ public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
view = createView(parent);
diff --git a/core/java/com/android/internal/app/ResolverProxy.java b/core/java/com/android/internal/app/ResolverProxy.java
new file mode 100644
index 0000000..f59fd11
--- /dev/null
+++ b/core/java/com/android/internal/app/ResolverProxy.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import java.util.List;
+import android.content.pm.ResolveInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.widget.AbsListView;
+import android.app.VoiceInteractor.PickOptionRequest.Option;
+import com.android.internal.app.ResolverActivity.TargetInfo;
+
+/** Relax access modifiers on key ResolverActivity extension methods to allow
+ them to be overridden from a different package/classloader.
+ Used by CMResolver */
+public class ResolverProxy extends ResolverActivity {
+ private static final String TAG = "ResolverProxy";
+
+ /** If the superclass may set up adapter entries after onCreate completes,
+ This method should be overridden to do nothing, and
+ sendVoiceChoicesIfNeeded should be called once the adapter setup is
+ complete. */
+ @Override
+ protected void onSetupVoiceInteraction() {
+ super.onSetupVoiceInteraction();
+ }
+
+ /** see onSetupVoiceInteraction */
+ @Override
+ protected void sendVoiceChoicesIfNeeded() {
+ super.sendVoiceChoicesIfNeeded();
+ }
+
+ @Override
+ protected int getLayoutResource() {
+ return super.getLayoutResource();
+ }
+
+ @Override
+ protected void bindProfileView() {
+ super.bindProfileView();
+ }
+
+ @Override
+ protected Option optionForChooserTarget(TargetInfo target, int index) {
+ return super.optionForChooserTarget(target, index);
+ }
+
+ @Override
+ protected boolean shouldGetActivityMetadata() {
+ return super.shouldGetActivityMetadata();
+ }
+
+ @Override
+ protected boolean shouldAutoLaunchSingleChoice(TargetInfo target) {
+ return super.shouldAutoLaunchSingleChoice(target);
+ }
+
+ @Override
+ protected void showAppDetails(ResolveInfo ri) {
+ super.showAppDetails(ri);
+ }
+
+ @Override
+ void startSelected(int which, boolean always, boolean filtered) {
+ super.startSelected(which, always, filtered);
+ }
+
+ @Override
+ protected void onActivityStarted(TargetInfo cti) {
+ super.onActivityStarted(cti);
+ }
+
+ @Override
+ protected boolean configureContentView(
+ List<Intent> payloadIntents, Intent[] initialIntents,
+ List<ResolveInfo> rList, boolean alwaysUseOption) {
+ return super.configureContentView(
+ payloadIntents, initialIntents, rList, alwaysUseOption);
+ }
+
+ @Override
+ protected void onPrepareAdapterView(
+ AbsListView adapterView, ResolveListAdapter adapter, boolean alwaysUseOption) {
+ super.onPrepareAdapterView(adapterView, adapter, alwaysUseOption);
+ }
+
+ /** subclasses cannot override this because ResolveListAdapter is an inaccessible
+ type. Override createProxyAdapter(...) instead */
+ @Override
+ ResolveListAdapter createAdapter(Context context, List<Intent> payloadIntents,
+ Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
+ boolean filterLastUsed) {
+ ProxyListAdapter adapter = createProxyAdapter(
+ context, payloadIntents, initialIntents, rList, launchedFromUid, filterLastUsed);
+ return (adapter != null)
+ ? adapter
+ : super.createAdapter(context, payloadIntents, initialIntents,
+ rList, launchedFromUid, filterLastUsed);
+ }
+
+ /** Subclasses should override this instead of createAdapter to avoid issues
+ with ResolveListAdapter being an inaccessible type */
+ protected ProxyListAdapter createProxyAdapter(Context context, List<Intent> payloadIntents,
+ Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
+ boolean filterLastUsed) {
+ return null;
+ }
+
+ protected void setAlwaysUseOption(boolean alwaysUse) {
+ mAlwaysUseOption = alwaysUse;
+ }
+
+ /** Provides a visible type for exending ResolveListAdapter - fortunately the key
+ methods one would need to override in ResolveListAdapter are all public or protected */
+ public class ProxyListAdapter extends ResolveListAdapter {
+ public ProxyListAdapter(
+ Context context, List<Intent> payloadIntents, Intent[] initialIntents,
+ List<ResolveInfo> rList, int launchedFromUid, boolean filterLastUsed) {
+ super(context, payloadIntents, initialIntents, rList, launchedFromUid, filterLastUsed);
+ }
+
+ /** complements getDisplayInfoCount and getDisplayInfoAt */
+ public TargetInfo removeDisplayInfoAt(int index) {
+ if (index >= 0 && index < mDisplayList.size()) {
+ return mDisplayList.remove(index);
+ } else {
+ return null;
+ }
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index f178c8c..54a4e86 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -21,6 +21,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.SensorManager;
import android.net.ConnectivityManager;
+import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryStats.Uid;
import android.os.Bundle;
@@ -61,15 +62,18 @@ public final class BatteryStatsHelper {
private static final String TAG = BatteryStatsHelper.class.getSimpleName();
private static BatteryStats sStatsXfer;
+ private static BatteryStats sDockStatsXfer;
private static Intent sBatteryBroadcastXfer;
private static ArrayMap<File, BatteryStats> sFileXfer = new ArrayMap<>();
final private Context mContext;
+ final private BatteryManager mBatteryService;
final private boolean mCollectBatteryBroadcast;
final private boolean mWifiOnly;
private IBatteryStats mBatteryInfo;
private BatteryStats mStats;
+ private BatteryStats mDockStats;
private Intent mBatteryBroadcast;
private PowerProfile mPowerProfile;
@@ -160,19 +164,28 @@ public final class BatteryStatsHelper {
public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast, boolean wifiOnly) {
mContext = context;
+ mBatteryService = ((BatteryManager) context.getSystemService(Context.BATTERY_SERVICE));
mCollectBatteryBroadcast = collectBatteryBroadcast;
mWifiOnly = wifiOnly;
}
public void storeStatsHistoryInFile(String fname) {
+ internalStoreStatsHistoryInFile(getStats(), fname);
+ }
+
+ public void storeDockStatsHistoryInFile(String fname) {
+ internalStoreStatsHistoryInFile(getDockStats(), fname);
+ }
+
+ public void internalStoreStatsHistoryInFile(BatteryStats stats, String fname) {
synchronized (sFileXfer) {
File path = makeFilePath(mContext, fname);
- sFileXfer.put(path, this.getStats());
+ sFileXfer.put(path, stats);
FileOutputStream fout = null;
try {
fout = new FileOutputStream(path);
Parcel hist = Parcel.obtain();
- getStats().writeToParcelWithoutUids(hist, 0);
+ stats.writeToParcelWithoutUids(hist, 0);
byte[] histData = hist.marshall();
fout.write(histData);
} catch (IOException e) {
@@ -229,18 +242,38 @@ public final class BatteryStatsHelper {
/** Clears the current stats and forces recreating for future use. */
public void clearStats() {
mStats = null;
+ mDockStats = null;
+ }
+
+ private void clearAllStats() {
+ clearStats();
+ sStatsXfer = null;
+ sDockStatsXfer = null;
+ sBatteryBroadcastXfer = null;
+ for (File f : sFileXfer.keySet()) {
+ f.delete();
+ }
+ sFileXfer.clear();
}
public BatteryStats getStats() {
if (mStats == null) {
- load();
+ loadStats();
}
return mStats;
}
+ public BatteryStats getDockStats() {
+ if (mDockStats == null) {
+ loadDockStats();
+ }
+ return mDockStats;
+ }
+
public Intent getBatteryBroadcast() {
if (mBatteryBroadcast == null && mCollectBatteryBroadcast) {
- load();
+ loadStats();
+ loadDockStats();
}
return mBatteryBroadcast;
}
@@ -257,6 +290,7 @@ public final class BatteryStatsHelper {
public void create(Bundle icicle) {
if (icicle != null) {
mStats = sStatsXfer;
+ mDockStats = sDockStatsXfer;
mBatteryBroadcast = sBatteryBroadcastXfer;
}
mBatteryInfo = IBatteryStats.Stub.asInterface(
@@ -266,6 +300,7 @@ public final class BatteryStatsHelper {
public void storeState() {
sStatsXfer = mStats;
+ sDockStatsXfer = mDockStats;
sBatteryBroadcastXfer = mBatteryBroadcast;
}
@@ -321,6 +356,7 @@ public final class BatteryStatsHelper {
long rawUptimeUs) {
// Initialize mStats if necessary.
getStats();
+ getDockStats();
mMaxPower = 0;
mMaxRealPower = 0;
@@ -739,7 +775,7 @@ public final class BatteryStatsHelper {
}
}
- private void load() {
+ private void loadStats() {
if (mBatteryInfo == null) {
return;
}
@@ -750,6 +786,26 @@ public final class BatteryStatsHelper {
}
}
+ private void loadDockStats() {
+ if (mBatteryInfo == null) {
+ return;
+ }
+ if (mBatteryService.isDockBatterySupported()) {
+ mDockStats = getDockStats(mBatteryInfo);
+ } else {
+ mDockStats = null;
+ }
+ }
+
+ public void resetStatistics() {
+ try {
+ clearAllStats();
+ mBatteryInfo.resetStatistics();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException:", e);
+ }
+ }
+
private static BatteryStatsImpl getStats(IBatteryStats service) {
try {
ParcelFileDescriptor pfd = service.getStatisticsStream();
@@ -772,4 +828,27 @@ public final class BatteryStatsHelper {
}
return new BatteryStatsImpl();
}
+
+ private static BatteryStatsImpl getDockStats(IBatteryStats service) {
+ try {
+ ParcelFileDescriptor pfd = service.getDockStatisticsStream();
+ if (pfd != null) {
+ FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ try {
+ byte[] data = readFully(fis, MemoryFile.getSize(pfd.getFileDescriptor()));
+ Parcel parcel = Parcel.obtain();
+ parcel.unmarshall(data, 0, data.length);
+ parcel.setDataPosition(0);
+ BatteryStatsImpl stats = com.android.internal.os.DockBatteryStatsImpl.CREATOR
+ .createFromParcel(parcel);
+ return stats;
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to read statistics stream", e);
+ }
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException:", e);
+ }
+ return new BatteryStatsImpl();
+ }
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 64b7768..d0a169e 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006-2007 The Android Open Source Project
+ * Copyright (C) 2016 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -91,7 +92,7 @@ import java.util.concurrent.locks.ReentrantLock;
* battery life. All times are represented in microseconds except where indicated
* otherwise.
*/
-public final class BatteryStatsImpl extends BatteryStats {
+public class BatteryStatsImpl extends BatteryStats {
private static final String TAG = "BatteryStatsImpl";
private static final boolean DEBUG = false;
public static final boolean DEBUG_ENERGY = false;
@@ -105,7 +106,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 132 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 133 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -1968,8 +1969,14 @@ public final class BatteryStatsImpl extends BatteryStats {
private int buildBatteryLevelInt(HistoryItem h) {
return ((((int)h.batteryLevel)<<25)&0xfe000000)
- | ((((int)h.batteryTemperature)<<14)&0x01ff8000)
- | ((((int)h.batteryVoltage)<<1)&0x00007fff);
+ | ((((int)h.batteryTemperature)<<15)&0x01ff8000)
+ | ((((int)h.batteryVoltage)<<1)&0x00007ffe);
+ }
+
+ private void readBatteryLevelInt(int batteryLevelInt, HistoryItem out) {
+ out.batteryLevel = (byte)((batteryLevelInt & 0xfe000000) >>> 25);
+ out.batteryTemperature = (short)((batteryLevelInt & 0x01ff8000) >>> 15);
+ out.batteryVoltage = (char)((batteryLevelInt & 0x00007ffe) >>> 1);
}
private int buildStateInt(HistoryItem h) {
@@ -2110,9 +2117,7 @@ public final class BatteryStatsImpl extends BatteryStats {
final int batteryLevelInt;
if ((firstToken&DELTA_BATTERY_LEVEL_FLAG) != 0) {
batteryLevelInt = src.readInt();
- cur.batteryLevel = (byte)((batteryLevelInt>>25)&0x7f);
- cur.batteryTemperature = (short)((batteryLevelInt<<7)>>21);
- cur.batteryVoltage = (char)(batteryLevelInt&0x3fff);
+ readBatteryLevelInt(batteryLevelInt, cur);
cur.numReadInts += 1;
if (DEBUG) Slog.i(TAG, "READ DELTA: batteryToken=0x"
+ Integer.toHexString(batteryLevelInt)
@@ -6839,13 +6844,13 @@ public final class BatteryStatsImpl extends BatteryStats {
public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) {
if (systemDir != null) {
- mFile = new JournaledFile(new File(systemDir, "batterystats.bin"),
- new File(systemDir, "batterystats.bin.tmp"));
+ mFile = new JournaledFile(new File(systemDir, getStatsName() + ".bin"),
+ new File(systemDir, getStatsName() + ".bin.tmp"));
} else {
mFile = null;
}
- mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
- mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml"));
+ mCheckinFile = new AtomicFile(new File(systemDir, getStatsName() + "-checkin.bin"));
+ mDailyFile = new AtomicFile(new File(systemDir, getStatsName () + "-daily.xml"));
mExternalSync = externalSync;
mHandler = new MyHandler(handler.getLooper());
mStartCount++;
@@ -6921,6 +6926,16 @@ public final class BatteryStatsImpl extends BatteryStats {
readFromParcel(p);
}
+ /** @hide */
+ protected String getStatsName() {
+ return "batterystats";
+ }
+
+ /** @hide */
+ protected String getLogName() {
+ return "BatteryStats";
+ }
+
public void setPowerProfile(PowerProfile profile) {
synchronized (this) {
mPowerProfile = profile;
@@ -7699,26 +7714,35 @@ public final class BatteryStatsImpl extends BatteryStats {
}
final Uid u = getUidStatsLocked(mapUid(entry.uid));
- u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
- entry.rxPackets);
- u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes,
- entry.txPackets);
- rxPackets.put(u.getUid(), entry.rxPackets);
- txPackets.put(u.getUid(), entry.txPackets);
+ if (entry.rxBytes != 0) {
+ u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
+ entry.rxPackets);
+ mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
+ entry.rxBytes);
+ mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
+ entry.rxPackets);
- // Sum the total number of packets so that the Rx Power and Tx Power can
- // be evenly distributed amongst the apps.
- totalRxPackets += entry.rxPackets;
- totalTxPackets += entry.txPackets;
+ rxPackets.put(u.getUid(), entry.rxPackets);
- mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
- entry.rxBytes);
- mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
- entry.txBytes);
- mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
- entry.rxPackets);
- mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
- entry.txPackets);
+ // Sum the total number of packets so that the Rx Power can
+ // be evenly distributed amongst the apps.
+ totalRxPackets += entry.rxPackets;
+ }
+
+ if (entry.txBytes != 0) {
+ u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes,
+ entry.txPackets);
+ mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
+ entry.txBytes);
+ mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
+ entry.txPackets);
+
+ txPackets.put(u.getUid(), entry.txPackets);
+
+ // Sum the total number of packets so that the Tx Power can
+ // be evenly distributed amongst the apps.
+ totalTxPackets += entry.txPackets;
+ }
}
}
@@ -8434,7 +8458,13 @@ public final class BatteryStatsImpl extends BatteryStats {
public void setBatteryStateLocked(int status, int health, int plugType, int level,
int temp, int volt) {
- final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
+ // We need to add a extra check over the status because of dock batteries
+ // PlugType doesn't means that the dock battery is charging (some devices
+ // doesn't charge under dock usb)
+ boolean onBattery = plugType == BATTERY_PLUGGED_NONE &&
+ (status != BatteryManager.BATTERY_STATUS_CHARGING ||
+ status != BatteryManager.BATTERY_STATUS_FULL);
+
final long uptime = SystemClock.uptimeMillis();
final long elapsedRealtime = SystemClock.elapsedRealtime();
if (!mHaveBatteryLevel) {
diff --git a/core/java/com/android/internal/os/DeviceKeyHandler.java b/core/java/com/android/internal/os/DeviceKeyHandler.java
new file mode 100644
index 0000000..e7d103d
--- /dev/null
+++ b/core/java/com/android/internal/os/DeviceKeyHandler.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
+ * or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language
+ * governing permissions and limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.view.KeyEvent;
+
+public interface DeviceKeyHandler {
+
+ /**
+ * Invoked when an unknown key was detected by the system, letting the device handle
+ * this special keys prior to pass the key to the active app.
+ *
+ * @param event The key event to be handled
+ * @return If the event is consume
+ */
+ public boolean handleKeyEvent(KeyEvent event);
+}
diff --git a/core/java/com/android/internal/os/DockBatteryStatsImpl.java b/core/java/com/android/internal/os/DockBatteryStatsImpl.java
new file mode 100644
index 0000000..6099ad2
--- /dev/null
+++ b/core/java/com/android/internal/os/DockBatteryStatsImpl.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.File;
+
+public final class DockBatteryStatsImpl extends BatteryStatsImpl {
+ public DockBatteryStatsImpl() {
+ super();
+ }
+
+ public DockBatteryStatsImpl(Parcel p) {
+ super(p);
+ }
+
+ public DockBatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) {
+ super(systemDir, handler, externalSync);
+ }
+
+ protected String getStatsName() {
+ return "dockbatterystats";
+ }
+
+ protected String getLogName() {
+ return "DockBatteryStats";
+ }
+
+ public static final Parcelable.Creator<DockBatteryStatsImpl> CREATOR =
+ new Parcelable.Creator<DockBatteryStatsImpl>() {
+ public DockBatteryStatsImpl createFromParcel(Parcel in) {
+ return new DockBatteryStatsImpl(in);
+ }
+
+ public DockBatteryStatsImpl[] newArray(int size) {
+ return new DockBatteryStatsImpl[size];
+ }
+ };
+}
diff --git a/core/java/com/android/internal/os/KernelCpuSpeedReader.java b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
index 5b776ac..3f6ebb9 100644
--- a/core/java/com/android/internal/os/KernelCpuSpeedReader.java
+++ b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
@@ -16,8 +16,11 @@
package com.android.internal.os;
import android.text.TextUtils;
+import android.system.OsConstants;
import android.util.Slog;
+import libcore.io.Libcore;
+
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
@@ -29,7 +32,7 @@ import java.util.Arrays;
*
* freq time
*
- * where time is measured in 1/100 seconds.
+ * where time is measured in jiffies.
*/
public class KernelCpuSpeedReader {
private static final String TAG = "KernelCpuSpeedReader";
@@ -38,6 +41,9 @@ public class KernelCpuSpeedReader {
private final long[] mLastSpeedTimes;
private final long[] mDeltaSpeedTimes;
+ // How long a CPU jiffy is in milliseconds.
+ private final long mJiffyMillis;
+
/**
* @param cpuNumber The cpu (cpu0, cpu1, etc) whose state to read.
*/
@@ -46,6 +52,8 @@ public class KernelCpuSpeedReader {
cpuNumber);
mLastSpeedTimes = new long[numSpeedSteps];
mDeltaSpeedTimes = new long[numSpeedSteps];
+ long jiffyHz = Libcore.os.sysconf(OsConstants._SC_CLK_TCK);
+ mJiffyMillis = 1000/jiffyHz;
}
/**
@@ -62,8 +70,7 @@ public class KernelCpuSpeedReader {
splitter.setString(line);
Long.parseLong(splitter.next());
- // The proc file reports time in 1/100 sec, so convert to milliseconds.
- long time = Long.parseLong(splitter.next()) * 10;
+ long time = Long.parseLong(splitter.next()) * mJiffyMillis;
if (time < mLastSpeedTimes[speedIndex]) {
// The stats reset when the cpu hotplugged. That means that the time
// we read is offset from 0, so the time is the delta.
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index bf97f1f..d831902 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -67,10 +67,10 @@ public class ProcessCpuTracker {
static final int PROCESS_STAT_UTIME = 2;
static final int PROCESS_STAT_STIME = 3;
- /** Stores user time and system time in 100ths of a second. */
+ /** Stores user time and system time in jiffies. */
private final long[] mProcessStatsData = new long[4];
- /** Stores user time and system time in 100ths of a second. Used for
+ /** Stores user time and system time in jiffies. Used for
* public API to retrieve CPU use for a process. Must lock while in use. */
private final long[] mSinglePidStatsData = new long[4];
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index f81658e..3377189 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -19,6 +19,7 @@ package com.android.internal.os;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.ApplicationErrorReport;
+import android.content.res.ThemeConfig;
import android.os.Build;
import android.os.Debug;
import android.os.IBinder;
@@ -83,6 +84,10 @@ public class RuntimeInit {
message.append("Process: ").append(processName).append(", ");
}
message.append("PID: ").append(Process.myPid());
+ final ThemeConfig themeConfig =
+ ActivityManagerNative.getDefault().getConfiguration().themeConfig;
+ message.append("\nTheme: ").append(themeConfig == null ?
+ ThemeConfig.SYSTEM_DEFAULT : themeConfig);
Clog_e(TAG, message.toString(), e);
}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 3e86fac..6c3cb3e 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -22,6 +22,7 @@ import static android.system.OsConstants.STDERR_FILENO;
import static android.system.OsConstants.STDIN_FILENO;
import static android.system.OsConstants.STDOUT_FILENO;
+import android.graphics.Typeface;
import android.net.Credentials;
import android.net.LocalSocket;
import android.os.Process;
@@ -194,6 +195,10 @@ class ZygoteConnection {
Os.fcntlInt(childPipeFd, F_SETFD, 0);
}
+ if (parsedArgs.refreshTheme) {
+ Typeface.recreateDefaults();
+ }
+
/**
* In order to avoid leaking descriptors to the Zygote child,
* the native code must close the two Zygote socket descriptors
@@ -373,6 +378,9 @@ class ZygoteConnection {
*/
String appDataDir;
+ /** from --refresh_theme */
+ boolean refreshTheme;
+
/**
* Constructs instance and parses args
* @param args zygote command-line args
@@ -529,6 +537,8 @@ class ZygoteConnection {
instructionSet = arg.substring(arg.indexOf('=') + 1);
} else if (arg.startsWith("--app-data-dir=")) {
appDataDir = arg.substring(arg.indexOf('=') + 1);
+ } else if (arg.equals("--refresh_theme")) {
+ refreshTheme = true;
} else {
break;
}
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index e330de2..6f47f70 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -94,4 +94,5 @@ oneway interface IKeyguardService {
* to start the keyguard dismiss sequence.
*/
void onActivityDrawn();
+ void showKeyguard();
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 8e8d352..fe0bc65 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -76,12 +76,19 @@ import com.android.internal.widget.SwipeDismissLayout;
import android.app.ActivityManager;
import android.app.KeyguardManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
+import android.content.ActivityNotFoundException;
+import android.database.ContentObserver;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
@@ -93,10 +100,14 @@ import android.media.session.MediaSessionLegacyHelper;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.provider.Settings;
import android.transition.Scene;
import android.transition.Transition;
import android.transition.TransitionInflater;
@@ -108,6 +119,8 @@ import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
+import android.view.GestureDetector;
+import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Animation;
@@ -118,10 +131,14 @@ import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.ProgressBar;
import android.widget.TextView;
+import android.widget.Toast;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.R;
+
/**
* Android-specific Window.
* <p>
@@ -249,7 +266,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private int mTitleColor = 0;
private boolean mAlwaysReadCloseOnTouchAttr = false;
+ private boolean mEnableGestures;
+ private Context mContext;
private ContextMenuBuilder mContextMenu;
private MenuDialogHelper mContextMenuHelper;
private boolean mClosingActionMenu;
@@ -260,6 +279,36 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private AudioManager mAudioManager;
private KeyguardManager mKeyguardManager;
+ private final class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.System
+ .getUriFor(Settings.System.ENABLE_STYLUS_GESTURES), false,
+ this);
+ checkGestures();
+ }
+
+ void unobserve() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ checkGestures();
+ }
+
+ void checkGestures() {
+ mEnableGestures = Settings.System.getInt(
+ mContext.getContentResolver(),
+ Settings.System.ENABLE_STYLUS_GESTURES, 0) == 1;
+ }
+ }
+
private int mUiOptions = 0;
private boolean mInvalidatePanelMenuPosted;
@@ -303,6 +352,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
public PhoneWindow(Context context) {
super(context);
+ mContext = context;
mLayoutInflater = LayoutInflater.from(context);
}
@@ -2224,6 +2274,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private View mStatusGuard;
// View added at runtime to draw under the navigation bar area
private View mNavigationGuard;
+ private SettingsObserver mSettingsObserver;
private final ColorViewState mStatusColorViewState = new ColorViewState(
SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
@@ -2267,6 +2318,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mBarEnterExitDuration = context.getResources().getInteger(
R.integer.dock_enter_exit_duration);
+
+ mSettingsObserver = new SettingsObserver(new Handler());
}
public void setBackgroundFallback(int resId) {
@@ -2358,8 +2411,211 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
return false;
}
+ private final StylusGestureFilter mStylusFilter = new StylusGestureFilter();
+
+ private class StylusGestureFilter extends SimpleOnGestureListener {
+
+ private final static int SWIPE_UP = 1;
+ private final static int SWIPE_DOWN = 2;
+ private final static int SWIPE_LEFT = 3;
+ private final static int SWIPE_RIGHT = 4;
+ private final static int PRESS_LONG = 5;
+ private final static int TAP_DOUBLE = 6;
+ private final static double SWIPE_MIN_DISTANCE = 25.0;
+ private final static double SWIPE_MIN_VELOCITY = 50.0;
+ private final static int KEY_NO_ACTION = 1000;
+ private final static int KEY_HOME = 1001;
+ private final static int KEY_BACK = 1002;
+ private final static int KEY_MENU = 1003;
+ private final static int KEY_SEARCH = 1004;
+ private final static int KEY_RECENT = 1005;
+ private final static int KEY_APP = 1006;
+ private GestureDetector mDetector;
+ private final static String TAG = "StylusGestureFilter";
+
+ public StylusGestureFilter() {
+ mDetector = new GestureDetector(this);
+ }
+
+ public boolean onTouchEvent(MotionEvent event) {
+ return mDetector.onTouchEvent(event);
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2,
+ float velocityX, float velocityY) {
+
+ final float xDistance = Math.abs(e1.getX() - e2.getX());
+ final float yDistance = Math.abs(e1.getY() - e2.getY());
+
+ velocityX = Math.abs(velocityX);
+ velocityY = Math.abs(velocityY);
+ boolean result = false;
+
+ if (velocityX > (SWIPE_MIN_VELOCITY * getResources().getDisplayMetrics().density)
+ && xDistance > (SWIPE_MIN_DISTANCE * getResources().getDisplayMetrics().density)
+ && xDistance > yDistance) {
+ if (e1.getX() > e2.getX()) { // right to left
+ // Swipe Left
+ dispatchStylusAction(SWIPE_LEFT);
+ } else {
+ // Swipe Right
+ dispatchStylusAction(SWIPE_RIGHT);
+ }
+ result = true;
+ } else if (velocityY > (SWIPE_MIN_VELOCITY * getResources().getDisplayMetrics().density)
+ && yDistance > (SWIPE_MIN_DISTANCE * getResources().getDisplayMetrics().density)
+ && yDistance > xDistance) {
+ if (e1.getY() > e2.getY()) { // bottom to up
+ // Swipe Up
+ dispatchStylusAction(SWIPE_UP);
+ } else {
+ // Swipe Down
+ dispatchStylusAction(SWIPE_DOWN);
+ }
+ result = true;
+ }
+ return result;
+ }
+
+ @Override
+ public boolean onDoubleTap(MotionEvent arg0) {
+ dispatchStylusAction(TAP_DOUBLE);
+ return true;
+ }
+
+ public void onLongPress(MotionEvent e) {
+ dispatchStylusAction(PRESS_LONG);
+ }
+
+ }
+
+ private void menuAction() {
+ dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_MENU));
+ dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_MENU));
+
+ }
+
+ private void backAction() {
+ dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_BACK));
+ dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_BACK));
+ }
+
+ private void dispatchStylusAction(int gestureAction) {
+ final ContentResolver resolver = mContext.getContentResolver();
+ boolean isSystemUI = mContext.getPackageName().equals("com.android.systemui");
+ String setting = null;
+ int dispatchAction = -1;
+ switch (gestureAction) {
+ case StylusGestureFilter.SWIPE_LEFT:
+ setting = Settings.System.getString(resolver,
+ Settings.System.GESTURES_LEFT_SWIPE);
+ break;
+ case StylusGestureFilter.SWIPE_RIGHT:
+ setting = Settings.System.getString(resolver,
+ Settings.System.GESTURES_RIGHT_SWIPE);
+ break;
+ case StylusGestureFilter.SWIPE_UP:
+ setting = Settings.System.getString(resolver,
+ Settings.System.GESTURES_UP_SWIPE);
+ break;
+ case StylusGestureFilter.SWIPE_DOWN:
+ setting = Settings.System.getString(resolver,
+ Settings.System.GESTURES_DOWN_SWIPE);
+ break;
+ case StylusGestureFilter.TAP_DOUBLE:
+ setting = Settings.System.getString(resolver,
+ Settings.System.GESTURES_DOUBLE_TAP);
+ break;
+ case StylusGestureFilter.PRESS_LONG:
+ setting = Settings.System.getString(resolver,
+ Settings.System.GESTURES_LONG_PRESS);
+ break;
+ default:
+ return;
+ }
+
+ try {
+ int value = Integer.valueOf(setting);
+ if (value == StylusGestureFilter.KEY_NO_ACTION) {
+ return;
+ }
+ dispatchAction = value;
+ } catch (NumberFormatException e) {
+ dispatchAction = StylusGestureFilter.KEY_APP;
+ }
+
+ // Dispatching action
+ switch (dispatchAction) {
+ case StylusGestureFilter.KEY_HOME:
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(homeIntent);
+ break;
+ case StylusGestureFilter.KEY_BACK:
+ backAction();
+ break;
+ case StylusGestureFilter.KEY_MENU:
+ // Menu action on notificationbar / systemui will be converted
+ // to back action
+ if (isSystemUI) {
+ backAction();
+ break;
+ }
+ menuAction();
+ break;
+ case StylusGestureFilter.KEY_SEARCH:
+ // Search action on notificationbar / systemui will be converted
+ // to back action
+ if (isSystemUI) {
+ backAction();
+ break;
+ }
+ launchDefaultSearch(new KeyEvent(KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_SEARCH));
+ break;
+ case StylusGestureFilter.KEY_RECENT:
+ IStatusBarService mStatusBarService = IStatusBarService.Stub
+ .asInterface(ServiceManager.getService("statusbar"));
+ try {
+ mStatusBarService.toggleRecentApps();
+ } catch (RemoteException e) {
+ }
+ break;
+ case StylusGestureFilter.KEY_APP:
+ // Launching app on notificationbar / systemui will be preceded
+ // with a back Action
+ if (isSystemUI) {
+ backAction();
+ }
+ try {
+ final PackageManager pm = mContext.getPackageManager();
+ Intent launchIntent = pm.getLaunchIntentForPackage(setting);
+ if (launchIntent != null) {
+ mContext.startActivity(launchIntent);
+ }
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(mContext, mContext.getString(R.string.stylus_app_not_installed, setting),
+ Toast.LENGTH_LONG).show();
+ }
+ break;
+ }
+ }
+
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
+ // Stylus events with side button pressed are filtered and other
+ // events are processed normally.
+ if (mEnableGestures
+ && MotionEvent.BUTTON_SECONDARY == ev.getButtonState()) {
+ mStylusFilter.onTouchEvent(ev);
+ return false;
+ }
final Callback cb = getCallback();
return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)
: super.dispatchTouchEvent(ev);
@@ -3255,6 +3511,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
+ mSettingsObserver.observe();
+
updateWindowResizeState();
final Callback cb = getCallback();
@@ -3278,6 +3536,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
+ mSettingsObserver.unobserve();
+
final Callback cb = getCallback();
if (cb != null && mFeatureId < 0) {
cb.onDetachedFromWindow();
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 447292c..be78a12 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -1879,6 +1879,33 @@ public class StateMachine {
}
/**
+ * Check if there are any pending messages with code 'what' in deferred messages queue.
+ */
+ protected final boolean hasDeferredMessages(int what) {
+ SmHandler smh = mSmHandler;
+ if (smh == null) return false;
+
+ Iterator<Message> iterator = smh.mDeferredMessages.iterator();
+ while (iterator.hasNext()) {
+ Message msg = iterator.next();
+ if (msg.what == what) return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if there are any pending posts of messages with code 'what' in
+ * the message queue. This does NOT check messages in deferred message queue.
+ */
+ protected final boolean hasMessages(int what) {
+ SmHandler smh = mSmHandler;
+ if (smh == null) return false;
+
+ return smh.hasMessages(what);
+ }
+
+ /**
* Validate that the message was sent by
* {@link StateMachine#quit} or {@link StateMachine#quitNow}.
* */
diff --git a/core/java/com/android/internal/util/cm/ActionUtils.java b/core/java/com/android/internal/util/cm/ActionUtils.java
new file mode 100644
index 0000000..7e86cd3
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/ActionUtils.java
@@ -0,0 +1,149 @@
+package com.android.internal.util.cm;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
+import android.app.IActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import android.view.HapticFeedbackConstants;
+import android.widget.Toast;
+import com.android.internal.R;
+
+import java.util.List;
+
+public class ActionUtils {
+ private static final boolean DEBUG = false;
+ private static final String TAG = ActionUtils.class.getSimpleName();
+ private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
+
+ /**
+ * Kills the top most / most recent user application, but leaves out the launcher.
+ * This is function governed by {@link CMSettings.Secure.KILL_APP_LONGPRESS_BACK}.
+ *
+ * @param context the current context, used to retrieve the package manager.
+ * @param userId the ID of the currently active user
+ * @return {@code true} when a user application was found and closed.
+ */
+ public static boolean killForegroundApp(Context context, int userId) {
+ try {
+ return killForegroundAppInternal(context, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not kill foreground app");
+ }
+ return false;
+ }
+
+ private static boolean killForegroundAppInternal(Context context, int userId)
+ throws RemoteException {
+ try {
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ String defaultHomePackage = "com.android.launcher";
+ intent.addCategory(Intent.CATEGORY_HOME);
+ final ResolveInfo res = context.getPackageManager().resolveActivity(intent, 0);
+
+ if (res.activityInfo != null && !res.activityInfo.packageName.equals("android")) {
+ defaultHomePackage = res.activityInfo.packageName;
+ }
+
+ IActivityManager am = ActivityManagerNative.getDefault();
+ List<ActivityManager.RunningAppProcessInfo> apps = am.getRunningAppProcesses();
+ for (ActivityManager.RunningAppProcessInfo appInfo : apps) {
+ int uid = appInfo.uid;
+ // Make sure it's a foreground user application (not system,
+ // root, phone, etc.)
+ if (uid >= Process.FIRST_APPLICATION_UID && uid <= Process.LAST_APPLICATION_UID
+ && appInfo.importance ==
+ ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+ if (appInfo.pkgList != null && (appInfo.pkgList.length > 0)) {
+ for (String pkg : appInfo.pkgList) {
+ if (!pkg.equals("com.android.systemui")
+ && !pkg.equals(defaultHomePackage)) {
+ am.forceStopPackage(pkg, UserHandle.USER_CURRENT);
+ return true;
+ }
+ }
+ } else {
+ Process.killProcess(appInfo.pid);
+ return true;
+ }
+ }
+ }
+ } catch (RemoteException remoteException) {
+ // Do nothing; just let it go.
+ }
+ return false;
+ }
+
+ /**
+ * Attempt to bring up the last activity in the stack before the current active one.
+ *
+ * @param context
+ * @return whether an activity was found to switch to
+ */
+ public static boolean switchToLastApp(Context context, int userId) {
+ try {
+ return switchToLastAppInternal(context, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not switch to last app");
+ }
+ return false;
+ }
+
+ private static boolean switchToLastAppInternal(Context context, int userId)
+ throws RemoteException {
+ ActivityManager.RecentTaskInfo lastTask = getLastTask(context, userId);
+
+ if (lastTask == null || lastTask.id < 0) {
+ return false;
+ }
+
+ final String packageName = lastTask.baseIntent.getComponent().getPackageName();
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ final ActivityOptions opts = ActivityOptions.makeCustomAnimation(context,
+ com.android.internal.R.anim.last_app_in,
+ com.android.internal.R.anim.last_app_out);
+
+ if (DEBUG) Log.d(TAG, "switching to " + packageName);
+ am.moveTaskToFront(lastTask.id, ActivityManager.MOVE_TASK_NO_USER_ACTION, opts.toBundle());
+
+ return true;
+ }
+
+ private static ActivityManager.RecentTaskInfo getLastTask(Context context, int userId)
+ throws RemoteException {
+ final String defaultHomePackage = resolveCurrentLauncherPackage(context, userId);
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ final List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasks(5,
+ ActivityManager.RECENT_IGNORE_UNAVAILABLE, userId);
+
+ for (int i = 1; i < tasks.size(); i++) {
+ ActivityManager.RecentTaskInfo task = tasks.get(i);
+ if (task.origActivity != null) {
+ task.baseIntent.setComponent(task.origActivity);
+ }
+ String packageName = task.baseIntent.getComponent().getPackageName();
+ if (!packageName.equals(defaultHomePackage)
+ && !packageName.equals(SYSTEMUI_PACKAGE)) {
+ return tasks.get(i);
+ }
+ }
+
+ return null;
+ }
+
+ private static String resolveCurrentLauncherPackage(Context context, int userId) {
+ final Intent launcherIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME);
+ final PackageManager pm = context.getPackageManager();
+ final ResolveInfo launcherInfo = pm.resolveActivityAsUser(launcherIntent, 0, userId);
+ return launcherInfo.activityInfo.packageName;
+ }
+}
diff --git a/core/java/com/android/internal/util/cm/PowerMenuConstants.java b/core/java/com/android/internal/util/cm/PowerMenuConstants.java
new file mode 100644
index 0000000..3debd09
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/PowerMenuConstants.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.cm;
+
+/* Master list of all actions for the power menu */
+public class PowerMenuConstants {
+ public static final String GLOBAL_ACTION_KEY_POWER = "power";
+ public static final String GLOBAL_ACTION_KEY_REBOOT = "reboot";
+ public static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
+ public static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
+ public static final String GLOBAL_ACTION_KEY_USERS = "users";
+ public static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
+ public static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
+ public static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
+ public static final String GLOBAL_ACTION_KEY_SILENT = "silent";
+ public static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
+ public static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
+
+ private static String[] ALL_ACTIONS = {
+ GLOBAL_ACTION_KEY_POWER,
+ GLOBAL_ACTION_KEY_REBOOT,
+ GLOBAL_ACTION_KEY_SCREENSHOT,
+ GLOBAL_ACTION_KEY_AIRPLANE,
+ GLOBAL_ACTION_KEY_USERS,
+ GLOBAL_ACTION_KEY_SETTINGS,
+ GLOBAL_ACTION_KEY_LOCKDOWN,
+ GLOBAL_ACTION_KEY_BUGREPORT,
+ GLOBAL_ACTION_KEY_SILENT,
+ GLOBAL_ACTION_KEY_VOICEASSIST,
+ GLOBAL_ACTION_KEY_ASSIST
+ };
+
+ public static String[] getAllActions() {
+ return ALL_ACTIONS;
+ }
+}
diff --git a/core/java/com/android/internal/util/cm/SpamFilter.java b/core/java/com/android/internal/util/cm/SpamFilter.java
new file mode 100644
index 0000000..c261009
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/SpamFilter.java
@@ -0,0 +1,82 @@
+package com.android.internal.util.cm;
+
+import android.app.Notification;
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+public class SpamFilter {
+
+ public static final String AUTHORITY = "com.cyanogenmod.spam";
+ public static final String MESSAGE_PATH = "message";
+ public static final Uri NOTIFICATION_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(AUTHORITY)
+ .appendEncodedPath(MESSAGE_PATH)
+ .build();
+
+ public static final class SpamContract {
+
+ public static final class PackageTable {
+ public static final String TABLE_NAME = "packages";
+ public static final String ID = "_id";
+ public static final String PACKAGE_NAME = "package_name";
+ }
+
+ public static final class NotificationTable {
+ public static final String TABLE_NAME = "notifications";
+ public static final String ID = "_id";
+ public static final String PACKAGE_ID = "package_id";
+ public static final String MESSAGE_TEXT = "message_text";
+ public static final String COUNT = "count";
+ public static final String LAST_BLOCKED = "last_blocked";
+ public static final String NORMALIZED_TEXT = "normalized_text";
+ }
+
+ }
+
+ public static String getNormalizedContent(String msg) {
+ return msg.toLowerCase().replaceAll("[^\\p{L}\\p{Nd}]+", "");
+ }
+
+ public static String getNormalizedNotificationContent(Notification notification) {
+ String content = getNotificationContent(notification);
+ return getNormalizedContent(content);
+ }
+
+ public static String getNotificationContent(Notification notification) {
+ CharSequence notificationTitle = getNotificationTitle(notification);
+ CharSequence notificationMessage = getNotificationMessage(notification);
+ return notificationTitle + "\n" + notificationMessage;
+ }
+
+ private static CharSequence getNotificationTitle(Notification notification) {
+ Bundle extras = notification.extras;
+ String titleExtra = extras.containsKey(Notification.EXTRA_TITLE_BIG)
+ ? Notification.EXTRA_TITLE_BIG : Notification.EXTRA_TITLE;
+ CharSequence notificationTitle = extras.getCharSequence(titleExtra);
+ return notificationTitle;
+ }
+
+ private static CharSequence getNotificationMessage(Notification notification) {
+ Bundle extras = notification.extras;
+ CharSequence notificationMessage = extras.getCharSequence(Notification.EXTRA_TEXT);
+
+ if (TextUtils.isEmpty(notificationMessage)) {
+ CharSequence[] inboxLines = extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES);
+ if (inboxLines == null || inboxLines.length == 0) {
+ notificationMessage = "";
+ } else {
+ notificationMessage = TextUtils.join("\n", inboxLines);
+ }
+ }
+ return notificationMessage;
+ }
+
+ public static boolean hasFilterableContent(Notification notification) {
+ CharSequence notificationTitle = getNotificationTitle(notification);
+ CharSequence notificationMessage = getNotificationMessage(notification);
+ return !(TextUtils.isEmpty(notificationTitle) && TextUtils.isEmpty(notificationMessage));
+ }
+}
diff --git a/core/java/com/android/internal/util/cm/palette/ColorCutQuantizer.java b/core/java/com/android/internal/util/cm/palette/ColorCutQuantizer.java
new file mode 100644
index 0000000..a24dff8
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/palette/ColorCutQuantizer.java
@@ -0,0 +1,516 @@
+/*
+ * 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 com.android.internal.util.cm.palette;
+
+import android.graphics.Color;
+import com.android.internal.util.cm.palette.Palette.Swatch;
+import android.util.TimingLogger;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.PriorityQueue;
+
+/**
+ * An color quantizer based on the Median-cut algorithm, but optimized for picking out distinct
+ * colors rather than representation colors.
+ *
+ * The color space is represented as a 3-dimensional cube with each dimension being an RGB
+ * component. The cube is then repeatedly divided until we have reduced the color space to the
+ * requested number of colors. An average color is then generated from each cube.
+ *
+ * What makes this different to median-cut is that median-cut divided cubes so that all of the cubes
+ * have roughly the same population, where this quantizer divides boxes based on their color volume.
+ * This means that the color space is divided into distinct colors, rather than representative
+ * colors.
+ *
+ * @hide
+ */
+final class ColorCutQuantizer {
+
+ private static final String LOG_TAG = "ColorCutQuantizer";
+ private static final boolean LOG_TIMINGS = false;
+
+ private static final int COMPONENT_RED = -3;
+ private static final int COMPONENT_GREEN = -2;
+ private static final int COMPONENT_BLUE = -1;
+
+ private static final int QUANTIZE_WORD_WIDTH = 5;
+ private static final int QUANTIZE_WORD_MASK = (1 << QUANTIZE_WORD_WIDTH) - 1;
+
+ final int[] mColors;
+ final int[] mHistogram;
+ final List<Swatch> mQuantizedColors;
+ final TimingLogger mTimingLogger;
+ final Palette.Filter[] mFilters;
+
+ private final float[] mTempHsl = new float[3];
+
+ /**
+ * Constructor.
+ *
+ * @param pixels histogram representing an image's pixel data
+ * @param maxColors The maximum number of colors that should be in the result palette.
+ * @param filters Set of filters to use in the quantization stage
+ */
+ ColorCutQuantizer(final int[] pixels, final int maxColors, final Palette.Filter[] filters) {
+ mTimingLogger = LOG_TIMINGS ? new TimingLogger(LOG_TAG, "Creation") : null;
+ mFilters = filters;
+
+ final int[] hist = mHistogram = new int[1 << (QUANTIZE_WORD_WIDTH * 3)];
+ for (int i = 0; i < pixels.length; i++) {
+ final int quantizedColor = quantizeFromRgb888(pixels[i]);
+ // Now update the pixel value to the quantized value
+ pixels[i] = quantizedColor;
+ // And update the histogram
+ hist[quantizedColor]++;
+ }
+
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("Histogram created");
+ }
+
+ // Now let's count the number of distinct colors
+ int distinctColorCount = 0;
+ for (int color = 0; color < hist.length; color++) {
+ if (hist[color] > 0 && shouldIgnoreColor(color)) {
+ // If we should ignore the color, set the population to 0
+ hist[color] = 0;
+ }
+ if (hist[color] > 0) {
+ // If the color has population, increase the distinct color count
+ distinctColorCount++;
+ }
+ }
+
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("Filtered colors and distinct colors counted");
+ }
+
+ // Now lets go through create an array consisting of only distinct colors
+ final int[] colors = mColors = new int[distinctColorCount];
+ int distinctColorIndex = 0;
+ for (int color = 0; color < hist.length; color++) {
+ if (hist[color] > 0) {
+ colors[distinctColorIndex++] = color;
+ }
+ }
+
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("Distinct colors copied into array");
+ }
+
+ if (distinctColorCount <= maxColors) {
+ // The image has fewer colors than the maximum requested, so just return the colors
+ mQuantizedColors = new ArrayList<>();
+ for (int color : colors) {
+ mQuantizedColors.add(new Swatch(approximateToRgb888(color), hist[color]));
+ }
+
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("Too few colors present. Copied to Swatches");
+ mTimingLogger.dumpToLog();
+ }
+ } else {
+ // We need use quantization to reduce the number of colors
+ mQuantizedColors = quantizePixels(maxColors);
+
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("Quantized colors computed");
+ mTimingLogger.dumpToLog();
+ }
+ }
+ }
+
+ /**
+ * @return the list of quantized colors
+ */
+ List<Swatch> getQuantizedColors() {
+ return mQuantizedColors;
+ }
+
+ private List<Swatch> quantizePixels(int maxColors) {
+ // Create the priority queue which is sorted by volume descending. This means we always
+ // split the largest box in the queue
+ final PriorityQueue<Vbox> pq = new PriorityQueue<>(maxColors, VBOX_COMPARATOR_VOLUME);
+
+ // To start, offer a box which contains all of the colors
+ pq.offer(new Vbox(0, mColors.length - 1));
+
+ // Now go through the boxes, splitting them until we have reached maxColors or there are no
+ // more boxes to split
+ splitBoxes(pq, maxColors);
+
+ // Finally, return the average colors of the color boxes
+ return generateAverageColors(pq);
+ }
+
+ /**
+ * Iterate through the {@link java.util.Queue}, popping
+ * {@link ColorCutQuantizer.Vbox} objects from the queue
+ * and splitting them. Once split, the new box and the remaining box are offered back to the
+ * queue.
+ *
+ * @param queue {@link java.util.PriorityQueue} to poll for boxes
+ * @param maxSize Maximum amount of boxes to split
+ */
+ private void splitBoxes(final PriorityQueue<Vbox> queue, final int maxSize) {
+ while (queue.size() < maxSize) {
+ final Vbox vbox = queue.poll();
+
+ if (vbox != null && vbox.canSplit()) {
+ // First split the box, and offer the result
+ queue.offer(vbox.splitBox());
+
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("Box split");
+ }
+ // Then offer the box back
+ queue.offer(vbox);
+ } else {
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("All boxes split");
+ }
+ // If we get here then there are no more boxes to split, so return
+ return;
+ }
+ }
+ }
+
+ private List<Swatch> generateAverageColors(Collection<Vbox> vboxes) {
+ ArrayList<Swatch> colors = new ArrayList<>(vboxes.size());
+ for (Vbox vbox : vboxes) {
+ Swatch swatch = vbox.getAverageColor();
+ if (!shouldIgnoreColor(swatch)) {
+ // As we're averaging a color box, we can still get colors which we do not want, so
+ // we check again here
+ colors.add(swatch);
+ }
+ }
+ return colors;
+ }
+
+ /**
+ * Represents a tightly fitting box around a color space.
+ */
+ private class Vbox {
+ // lower and upper index are inclusive
+ private int mLowerIndex;
+ private int mUpperIndex;
+ // Population of colors within this box
+ private int mPopulation;
+
+ private int mMinRed, mMaxRed;
+ private int mMinGreen, mMaxGreen;
+ private int mMinBlue, mMaxBlue;
+
+ Vbox(int lowerIndex, int upperIndex) {
+ mLowerIndex = lowerIndex;
+ mUpperIndex = upperIndex;
+ fitBox();
+ }
+
+ final int getVolume() {
+ return (mMaxRed - mMinRed + 1) * (mMaxGreen - mMinGreen + 1) *
+ (mMaxBlue - mMinBlue + 1);
+ }
+
+ final boolean canSplit() {
+ return getColorCount() > 1;
+ }
+
+ final int getColorCount() {
+ return 1 + mUpperIndex - mLowerIndex;
+ }
+
+ /**
+ * Recomputes the boundaries of this box to tightly fit the colors within the box.
+ */
+ final void fitBox() {
+ final int[] colors = mColors;
+ final int[] hist = mHistogram;
+
+ // Reset the min and max to opposite values
+ int minRed, minGreen, minBlue;
+ minRed = minGreen = minBlue = Integer.MAX_VALUE;
+ int maxRed, maxGreen, maxBlue;
+ maxRed = maxGreen = maxBlue = Integer.MIN_VALUE;
+ int count = 0;
+
+ for (int i = mLowerIndex; i <= mUpperIndex; i++) {
+ final int color = colors[i];
+ count += hist[color];
+
+ final int r = quantizedRed(color);
+ final int g = quantizedGreen(color);
+ final int b = quantizedBlue(color);
+ if (r > maxRed) {
+ maxRed = r;
+ }
+ if (r < minRed) {
+ minRed = r;
+ }
+ if (g > maxGreen) {
+ maxGreen = g;
+ }
+ if (g < minGreen) {
+ minGreen = g;
+ }
+ if (b > maxBlue) {
+ maxBlue = b;
+ }
+ if (b < minBlue) {
+ minBlue = b;
+ }
+ }
+
+ mMinRed = minRed;
+ mMaxRed = maxRed;
+ mMinGreen = minGreen;
+ mMaxGreen = maxGreen;
+ mMinBlue = minBlue;
+ mMaxBlue = maxBlue;
+ mPopulation = count;
+ }
+
+ /**
+ * Split this color box at the mid-point along it's longest dimension
+ *
+ * @return the new ColorBox
+ */
+ final Vbox splitBox() {
+ if (!canSplit()) {
+ throw new IllegalStateException("Can not split a box with only 1 color");
+ }
+
+ // find median along the longest dimension
+ final int splitPoint = findSplitPoint();
+
+ Vbox newBox = new Vbox(splitPoint + 1, mUpperIndex);
+
+ // Now change this box's upperIndex and recompute the color boundaries
+ mUpperIndex = splitPoint;
+ fitBox();
+
+ return newBox;
+ }
+
+ /**
+ * @return the dimension which this box is largest in
+ */
+ final int getLongestColorDimension() {
+ final int redLength = mMaxRed - mMinRed;
+ final int greenLength = mMaxGreen - mMinGreen;
+ final int blueLength = mMaxBlue - mMinBlue;
+
+ if (redLength >= greenLength && redLength >= blueLength) {
+ return COMPONENT_RED;
+ } else if (greenLength >= redLength && greenLength >= blueLength) {
+ return COMPONENT_GREEN;
+ } else {
+ return COMPONENT_BLUE;
+ }
+ }
+
+ /**
+ * Finds the point within this box's lowerIndex and upperIndex index of where to split.
+ *
+ * This is calculated by finding the longest color dimension, and then sorting the
+ * sub-array based on that dimension value in each color. The colors are then iterated over
+ * until a color is found with at least the midpoint of the whole box's dimension midpoint.
+ *
+ * @return the index of the colors array to split from
+ */
+ final int findSplitPoint() {
+ final int longestDimension = getLongestColorDimension();
+ final int[] colors = mColors;
+ final int[] hist = mHistogram;
+
+ // We need to sort the colors in this box based on the longest color dimension.
+ // As we can't use a Comparator to define the sort logic, we modify each color so that
+ // it's most significant is the desired dimension
+ modifySignificantOctet(colors, longestDimension, mLowerIndex, mUpperIndex);
+
+ // Now sort... Arrays.sort uses a exclusive toIndex so we need to add 1
+ Arrays.sort(colors, mLowerIndex, mUpperIndex + 1);
+
+ // Now revert all of the colors so that they are packed as RGB again
+ modifySignificantOctet(colors, longestDimension, mLowerIndex, mUpperIndex);
+
+ final int midPoint = mPopulation / 2;
+ for (int i = mLowerIndex, count = 0; i <= mUpperIndex; i++) {
+ count += hist[colors[i]];
+ if (count >= midPoint) {
+ return i;
+ }
+ }
+
+ return mLowerIndex;
+ }
+
+ /**
+ * @return the average color of this box.
+ */
+ final Swatch getAverageColor() {
+ final int[] colors = mColors;
+ final int[] hist = mHistogram;
+ int redSum = 0;
+ int greenSum = 0;
+ int blueSum = 0;
+ int totalPopulation = 0;
+
+ for (int i = mLowerIndex; i <= mUpperIndex; i++) {
+ final int color = colors[i];
+ final int colorPopulation = hist[color];
+
+ totalPopulation += colorPopulation;
+ redSum += colorPopulation * quantizedRed(color);
+ greenSum += colorPopulation * quantizedGreen(color);
+ blueSum += colorPopulation * quantizedBlue(color);
+ }
+
+ final int redMean = Math.round(redSum / (float) totalPopulation);
+ final int greenMean = Math.round(greenSum / (float) totalPopulation);
+ final int blueMean = Math.round(blueSum / (float) totalPopulation);
+
+ return new Swatch(approximateToRgb888(redMean, greenMean, blueMean), totalPopulation);
+ }
+ }
+
+ /**
+ * Modify the significant octet in a packed color int. Allows sorting based on the value of a
+ * single color component. This relies on all components being the same word size.
+ *
+ * @see Vbox#findSplitPoint()
+ */
+ private static void modifySignificantOctet(final int[] a, final int dimension,
+ final int lower, final int upper) {
+ switch (dimension) {
+ case COMPONENT_RED:
+ // Already in RGB, no need to do anything
+ break;
+ case COMPONENT_GREEN:
+ // We need to do a RGB to GRB swap, or vice-versa
+ for (int i = lower; i <= upper; i++) {
+ final int color = a[i];
+ a[i] = quantizedGreen(color) << (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH)
+ | quantizedRed(color) << QUANTIZE_WORD_WIDTH
+ | quantizedBlue(color);
+ }
+ break;
+ case COMPONENT_BLUE:
+ // We need to do a RGB to BGR swap, or vice-versa
+ for (int i = lower; i <= upper; i++) {
+ final int color = a[i];
+ a[i] = quantizedBlue(color) << (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH)
+ | quantizedGreen(color) << QUANTIZE_WORD_WIDTH
+ | quantizedRed(color);
+ }
+ break;
+ }
+ }
+
+ private boolean shouldIgnoreColor(int color565) {
+ final int rgb = approximateToRgb888(color565);
+ ColorUtils.colorToHSL(rgb, mTempHsl);
+ return shouldIgnoreColor(rgb, mTempHsl);
+ }
+
+ private boolean shouldIgnoreColor(Swatch color) {
+ return shouldIgnoreColor(color.getRgb(), color.getHsl());
+ }
+
+ private boolean shouldIgnoreColor(int rgb, float[] hsl) {
+ if (mFilters != null && mFilters.length > 0) {
+ for (int i = 0, count = mFilters.length; i < count; i++) {
+ if (!mFilters[i].isAllowed(rgb, hsl)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Comparator which sorts {@link Vbox} instances based on their volume, in descending order
+ */
+ private static final Comparator<Vbox> VBOX_COMPARATOR_VOLUME = new Comparator<Vbox>() {
+ @Override
+ public int compare(Vbox lhs, Vbox rhs) {
+ return rhs.getVolume() - lhs.getVolume();
+ }
+ };
+
+ /**
+ * Quantized a RGB888 value to have a word width of {@value #QUANTIZE_WORD_WIDTH}.
+ */
+ private static int quantizeFromRgb888(int color) {
+ int r = modifyWordWidth(Color.red(color), 8, QUANTIZE_WORD_WIDTH);
+ int g = modifyWordWidth(Color.green(color), 8, QUANTIZE_WORD_WIDTH);
+ int b = modifyWordWidth(Color.blue(color), 8, QUANTIZE_WORD_WIDTH);
+ return r << (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH) | g << QUANTIZE_WORD_WIDTH | b;
+ }
+
+ /**
+ * Quantized RGB888 values to have a word width of {@value #QUANTIZE_WORD_WIDTH}.
+ */
+ private static int approximateToRgb888(int r, int g, int b) {
+ return Color.rgb(modifyWordWidth(r, QUANTIZE_WORD_WIDTH, 8),
+ modifyWordWidth(g, QUANTIZE_WORD_WIDTH, 8),
+ modifyWordWidth(b, QUANTIZE_WORD_WIDTH, 8));
+ }
+
+ private static int approximateToRgb888(int color) {
+ return approximateToRgb888(quantizedRed(color), quantizedGreen(color), quantizedBlue(color));
+ }
+
+ /**
+ * @return red component of the quantized color
+ */
+ private static int quantizedRed(int color) {
+ return (color >> (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH)) & QUANTIZE_WORD_MASK;
+ }
+
+ /**
+ * @return green component of a quantized color
+ */
+ private static int quantizedGreen(int color) {
+ return (color >> QUANTIZE_WORD_WIDTH) & QUANTIZE_WORD_MASK;
+ }
+
+ /**
+ * @return blue component of a quantized color
+ */
+ private static int quantizedBlue(int color) {
+ return color & QUANTIZE_WORD_MASK;
+ }
+
+ private static int modifyWordWidth(int value, int currentWidth, int targetWidth) {
+ final int newValue;
+ if (targetWidth > currentWidth) {
+ // If we're approximating up in word width, we'll shift up
+ newValue = value << (targetWidth - currentWidth);
+ } else {
+ // Else, we will just shift and keep the MSB
+ newValue = value >> (currentWidth - targetWidth);
+ }
+ return newValue & ((1 << targetWidth) - 1);
+ }
+
+}
diff --git a/core/java/com/android/internal/util/cm/palette/ColorUtils.java b/core/java/com/android/internal/util/cm/palette/ColorUtils.java
new file mode 100644
index 0000000..8dcf750
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/palette/ColorUtils.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright 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.util.cm.palette;
+
+import android.graphics.Color;
+
+/**
+ * A set of color-related utility methods, building upon those available in {@code Color}.
+ *
+ * @hide
+ */
+public class ColorUtils {
+
+ private static final int MIN_ALPHA_SEARCH_MAX_ITERATIONS = 10;
+ private static final int MIN_ALPHA_SEARCH_PRECISION = 10;
+
+ private ColorUtils() {}
+
+ /**
+ * Composite two potentially translucent colors over each other and returns the result.
+ */
+ public static int compositeColors(int foreground, int background) {
+ int bgAlpha = Color.alpha(background);
+ int fgAlpha = Color.alpha(foreground);
+ int a = compositeAlpha(fgAlpha, bgAlpha);
+
+ int r = compositeComponent(Color.red(foreground), fgAlpha,
+ Color.red(background), bgAlpha, a);
+ int g = compositeComponent(Color.green(foreground), fgAlpha,
+ Color.green(background), bgAlpha, a);
+ int b = compositeComponent(Color.blue(foreground), fgAlpha,
+ Color.blue(background), bgAlpha, a);
+
+ return Color.argb(a, r, g, b);
+ }
+
+ private static int compositeAlpha(int foregroundAlpha, int backgroundAlpha) {
+ return 0xFF - (((0xFF - backgroundAlpha) * (0xFF - foregroundAlpha)) / 0xFF);
+ }
+
+ private static int compositeComponent(int fgC, int fgA, int bgC, int bgA, int a) {
+ if (a == 0) return 0;
+ return ((0xFF * fgC * fgA) + (bgC * bgA * (0xFF - fgA))) / (a * 0xFF);
+ }
+
+ /**
+ * Returns the luminance of a color.
+ *
+ * Formula defined here: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
+ */
+ public static double calculateLuminance(int color) {
+ double red = Color.red(color) / 255d;
+ red = red < 0.03928 ? red / 12.92 : Math.pow((red + 0.055) / 1.055, 2.4);
+
+ double green = Color.green(color) / 255d;
+ green = green < 0.03928 ? green / 12.92 : Math.pow((green + 0.055) / 1.055, 2.4);
+
+ double blue = Color.blue(color) / 255d;
+ blue = blue < 0.03928 ? blue / 12.92 : Math.pow((blue + 0.055) / 1.055, 2.4);
+
+ return (0.2126 * red) + (0.7152 * green) + (0.0722 * blue);
+ }
+
+ /**
+ * Returns the contrast ratio between {@code foreground} and {@code background}.
+ * {@code background} must be opaque.
+ * <p>
+ * Formula defined
+ * <a href="http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef">here</a>.
+ */
+ public static double calculateContrast(int foreground, int background) {
+ if (Color.alpha(background) != 255) {
+ throw new IllegalArgumentException("background can not be translucent");
+ }
+ if (Color.alpha(foreground) < 255) {
+ // If the foreground is translucent, composite the foreground over the background
+ foreground = compositeColors(foreground, background);
+ }
+
+ final double luminance1 = calculateLuminance(foreground) + 0.05;
+ final double luminance2 = calculateLuminance(background) + 0.05;
+
+ // Now return the lighter luminance divided by the darker luminance
+ return Math.max(luminance1, luminance2) / Math.min(luminance1, luminance2);
+ }
+
+ /**
+ * Calculates the minimum alpha value which can be applied to {@code foreground} so that would
+ * have a contrast value of at least {@code minContrastRatio} when compared to
+ * {@code background}.
+ *
+ * @param foreground the foreground color.
+ * @param background the background color. Should be opaque.
+ * @param minContrastRatio the minimum contrast ratio.
+ * @return the alpha value in the range 0-255, or -1 if no value could be calculated.
+ */
+ public static int calculateMinimumAlpha(int foreground, int background,
+ float minContrastRatio) {
+ if (Color.alpha(background) != 255) {
+ throw new IllegalArgumentException("background can not be translucent");
+ }
+
+ // First lets check that a fully opaque foreground has sufficient contrast
+ int testForeground = setAlphaComponent(foreground, 255);
+ double testRatio = calculateContrast(testForeground, background);
+ if (testRatio < minContrastRatio) {
+ // Fully opaque foreground does not have sufficient contrast, return error
+ return -1;
+ }
+
+ // Binary search to find a value with the minimum value which provides sufficient contrast
+ int numIterations = 0;
+ int minAlpha = 0;
+ int maxAlpha = 255;
+
+ while (numIterations <= MIN_ALPHA_SEARCH_MAX_ITERATIONS &&
+ (maxAlpha - minAlpha) > MIN_ALPHA_SEARCH_PRECISION) {
+ final int testAlpha = (minAlpha + maxAlpha) / 2;
+
+ testForeground = setAlphaComponent(foreground, testAlpha);
+ testRatio = calculateContrast(testForeground, background);
+
+ if (testRatio < minContrastRatio) {
+ minAlpha = testAlpha;
+ } else {
+ maxAlpha = testAlpha;
+ }
+
+ numIterations++;
+ }
+
+ // Conservatively return the max of the range of possible alphas, which is known to pass.
+ return maxAlpha;
+ }
+
+ /**
+ * Convert RGB components to HSL (hue-saturation-lightness).
+ * <ul>
+ * <li>hsl[0] is Hue [0 .. 360)</li>
+ * <li>hsl[1] is Saturation [0...1]</li>
+ * <li>hsl[2] is Lightness [0...1]</li>
+ * </ul>
+ *
+ * @param r red component value [0..255]
+ * @param g green component value [0..255]
+ * @param b blue component value [0..255]
+ * @param hsl 3 element array which holds the resulting HSL components.
+ */
+ public static void RGBToHSL(int r, int g, int b, float[] hsl) {
+ final float rf = r / 255f;
+ final float gf = g / 255f;
+ final float bf = b / 255f;
+
+ final float max = Math.max(rf, Math.max(gf, bf));
+ final float min = Math.min(rf, Math.min(gf, bf));
+ final float deltaMaxMin = max - min;
+
+ float h, s;
+ float l = (max + min) / 2f;
+
+ if (max == min) {
+ // Monochromatic
+ h = s = 0f;
+ } else {
+ if (max == rf) {
+ h = ((gf - bf) / deltaMaxMin) % 6f;
+ } else if (max == gf) {
+ h = ((bf - rf) / deltaMaxMin) + 2f;
+ } else {
+ h = ((rf - gf) / deltaMaxMin) + 4f;
+ }
+
+ s = deltaMaxMin / (1f - Math.abs(2f * l - 1f));
+ }
+
+ h = (h * 60f) % 360f;
+ if (h < 0) {
+ h += 360f;
+ }
+
+ hsl[0] = constrain(h, 0f, 360f);
+ hsl[1] = constrain(s, 0f, 1f);
+ hsl[2] = constrain(l, 0f, 1f);
+ }
+
+ /**
+ * Convert the ARGB color to its HSL (hue-saturation-lightness) components.
+ * <ul>
+ * <li>hsl[0] is Hue [0 .. 360)</li>
+ * <li>hsl[1] is Saturation [0...1]</li>
+ * <li>hsl[2] is Lightness [0...1]</li>
+ * </ul>
+ *
+ * @param color the ARGB color to convert. The alpha component is ignored.
+ * @param hsl 3 element array which holds the resulting HSL components.
+ */
+ public static void colorToHSL(int color, float[] hsl) {
+ RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), hsl);
+ }
+
+ /**
+ * Convert HSL (hue-saturation-lightness) components to a RGB color.
+ * <ul>
+ * <li>hsl[0] is Hue [0 .. 360)</li>
+ * <li>hsl[1] is Saturation [0...1]</li>
+ * <li>hsl[2] is Lightness [0...1]</li>
+ * </ul>
+ * If hsv values are out of range, they are pinned.
+ *
+ * @param hsl 3 element array which holds the input HSL components.
+ * @return the resulting RGB color
+ */
+ public static int HSLToColor(float[] hsl) {
+ final float h = hsl[0];
+ final float s = hsl[1];
+ final float l = hsl[2];
+
+ final float c = (1f - Math.abs(2 * l - 1f)) * s;
+ final float m = l - 0.5f * c;
+ final float x = c * (1f - Math.abs((h / 60f % 2f) - 1f));
+
+ final int hueSegment = (int) h / 60;
+
+ int r = 0, g = 0, b = 0;
+
+ switch (hueSegment) {
+ case 0:
+ r = Math.round(255 * (c + m));
+ g = Math.round(255 * (x + m));
+ b = Math.round(255 * m);
+ break;
+ case 1:
+ r = Math.round(255 * (x + m));
+ g = Math.round(255 * (c + m));
+ b = Math.round(255 * m);
+ break;
+ case 2:
+ r = Math.round(255 * m);
+ g = Math.round(255 * (c + m));
+ b = Math.round(255 * (x + m));
+ break;
+ case 3:
+ r = Math.round(255 * m);
+ g = Math.round(255 * (x + m));
+ b = Math.round(255 * (c + m));
+ break;
+ case 4:
+ r = Math.round(255 * (x + m));
+ g = Math.round(255 * m);
+ b = Math.round(255 * (c + m));
+ break;
+ case 5:
+ case 6:
+ r = Math.round(255 * (c + m));
+ g = Math.round(255 * m);
+ b = Math.round(255 * (x + m));
+ break;
+ }
+
+ r = constrain(r, 0, 255);
+ g = constrain(g, 0, 255);
+ b = constrain(b, 0, 255);
+
+ return Color.rgb(r, g, b);
+ }
+
+ /**
+ * Set the alpha component of {@code color} to be {@code alpha}.
+ */
+ public static int setAlphaComponent(int color, int alpha) {
+ if (alpha < 0 || alpha > 255) {
+ throw new IllegalArgumentException("alpha must be between 0 and 255.");
+ }
+ return (color & 0x00ffffff) | (alpha << 24);
+ }
+
+ private static float constrain(float amount, float low, float high) {
+ return amount < low ? low : (amount > high ? high : amount);
+ }
+
+ private static int constrain(int amount, int low, int high) {
+ return amount < low ? low : (amount > high ? high : amount);
+ }
+
+}
diff --git a/core/java/com/android/internal/util/cm/palette/DefaultGenerator.java b/core/java/com/android/internal/util/cm/palette/DefaultGenerator.java
new file mode 100644
index 0000000..407f01d
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/palette/DefaultGenerator.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 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.util.cm.palette;
+
+import com.android.internal.util.cm.palette.Palette.Swatch;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+class DefaultGenerator extends Palette.Generator {
+
+ private static final float TARGET_DARK_LUMA = 0.26f;
+ private static final float MAX_DARK_LUMA = 0.45f;
+
+ private static final float MIN_LIGHT_LUMA = 0.55f;
+ private static final float TARGET_LIGHT_LUMA = 0.74f;
+
+ private static final float MIN_NORMAL_LUMA = 0.3f;
+ private static final float TARGET_NORMAL_LUMA = 0.5f;
+ private static final float MAX_NORMAL_LUMA = 0.7f;
+
+ private static final float TARGET_MUTED_SATURATION = 0.3f;
+ private static final float MAX_MUTED_SATURATION = 0.4f;
+
+ private static final float TARGET_VIBRANT_SATURATION = 1f;
+ private static final float MIN_VIBRANT_SATURATION = 0.35f;
+
+ private static final float WEIGHT_SATURATION = 3f;
+ private static final float WEIGHT_LUMA = 6f;
+ private static final float WEIGHT_POPULATION = 1f;
+
+ private List<Swatch> mSwatches;
+
+ private int mHighestPopulation;
+
+ private Swatch mVibrantSwatch;
+ private Swatch mMutedSwatch;
+ private Swatch mDarkVibrantSwatch;
+ private Swatch mDarkMutedSwatch;
+ private Swatch mLightVibrantSwatch;
+ private Swatch mLightMutedSwatch;
+
+ @Override
+ public void generate(final List<Swatch> swatches) {
+ mSwatches = swatches;
+
+ mHighestPopulation = findMaxPopulation();
+
+ generateVariationColors();
+
+ // Now try and generate any missing colors
+ generateEmptySwatches();
+ }
+
+ @Override
+ public Swatch getVibrantSwatch() {
+ return mVibrantSwatch;
+ }
+
+ @Override
+ public Swatch getLightVibrantSwatch() {
+ return mLightVibrantSwatch;
+ }
+
+ @Override
+ public Swatch getDarkVibrantSwatch() {
+ return mDarkVibrantSwatch;
+ }
+
+ @Override
+ public Swatch getMutedSwatch() {
+ return mMutedSwatch;
+ }
+
+ @Override
+ public Swatch getLightMutedSwatch() {
+ return mLightMutedSwatch;
+ }
+
+ @Override
+ public Swatch getDarkMutedSwatch() {
+ return mDarkMutedSwatch;
+ }
+
+ private void generateVariationColors() {
+ mVibrantSwatch = findColorVariation(TARGET_NORMAL_LUMA, MIN_NORMAL_LUMA, MAX_NORMAL_LUMA,
+ TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
+
+ mLightVibrantSwatch = findColorVariation(TARGET_LIGHT_LUMA, MIN_LIGHT_LUMA, 1f,
+ TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
+
+ mDarkVibrantSwatch = findColorVariation(TARGET_DARK_LUMA, 0f, MAX_DARK_LUMA,
+ TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
+
+ mMutedSwatch = findColorVariation(TARGET_NORMAL_LUMA, MIN_NORMAL_LUMA, MAX_NORMAL_LUMA,
+ TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
+
+ mLightMutedSwatch = findColorVariation(TARGET_LIGHT_LUMA, MIN_LIGHT_LUMA, 1f,
+ TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
+
+ mDarkMutedSwatch = findColorVariation(TARGET_DARK_LUMA, 0f, MAX_DARK_LUMA,
+ TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
+ }
+
+ /**
+ * Try and generate any missing swatches from the swatches we did find.
+ */
+ private void generateEmptySwatches() {
+ if (mVibrantSwatch == null) {
+ // If we do not have a vibrant color...
+ if (mDarkVibrantSwatch != null) {
+ // ...but we do have a dark vibrant, generate the value by modifying the luma
+ final float[] newHsl = copyHslValues(mDarkVibrantSwatch);
+ newHsl[2] = TARGET_NORMAL_LUMA;
+ mVibrantSwatch = new Swatch(ColorUtils.HSLToColor(newHsl), 0);
+ }
+ }
+
+ if (mDarkVibrantSwatch == null) {
+ // If we do not have a dark vibrant color...
+ if (mVibrantSwatch != null) {
+ // ...but we do have a vibrant, generate the value by modifying the luma
+ final float[] newHsl = copyHslValues(mVibrantSwatch);
+ newHsl[2] = TARGET_DARK_LUMA;
+ mDarkVibrantSwatch = new Swatch(ColorUtils.HSLToColor(newHsl), 0);
+ }
+ }
+ }
+
+ /**
+ * Find the {@link Palette.Swatch} with the highest population value and return the population.
+ */
+ private int findMaxPopulation() {
+ int population = 0;
+ for (Swatch swatch : mSwatches) {
+ population = Math.max(population, swatch.getPopulation());
+ }
+ return population;
+ }
+
+ private Swatch findColorVariation(float targetLuma, float minLuma, float maxLuma,
+ float targetSaturation, float minSaturation, float maxSaturation) {
+ Swatch max = null;
+ float maxValue = 0f;
+
+ for (Swatch swatch : mSwatches) {
+ final float sat = swatch.getHsl()[1];
+ final float luma = swatch.getHsl()[2];
+
+ if (sat >= minSaturation && sat <= maxSaturation &&
+ luma >= minLuma && luma <= maxLuma &&
+ !isAlreadySelected(swatch)) {
+ float value = createComparisonValue(sat, targetSaturation, luma, targetLuma,
+ swatch.getPopulation(), mHighestPopulation);
+ if (max == null || value > maxValue) {
+ max = swatch;
+ maxValue = value;
+ }
+ }
+ }
+
+ return max;
+ }
+
+ /**
+ * @return true if we have already selected {@code swatch}
+ */
+ private boolean isAlreadySelected(Swatch swatch) {
+ return mVibrantSwatch == swatch || mDarkVibrantSwatch == swatch ||
+ mLightVibrantSwatch == swatch || mMutedSwatch == swatch ||
+ mDarkMutedSwatch == swatch || mLightMutedSwatch == swatch;
+ }
+
+ private static float createComparisonValue(float saturation, float targetSaturation,
+ float luma, float targetLuma,
+ int population, int maxPopulation) {
+ return createComparisonValue(saturation, targetSaturation, WEIGHT_SATURATION,
+ luma, targetLuma, WEIGHT_LUMA,
+ population, maxPopulation, WEIGHT_POPULATION);
+ }
+
+ private static float createComparisonValue(
+ float saturation, float targetSaturation, float saturationWeight,
+ float luma, float targetLuma, float lumaWeight,
+ int population, int maxPopulation, float populationWeight) {
+ return weightedMean(
+ invertDiff(saturation, targetSaturation), saturationWeight,
+ invertDiff(luma, targetLuma), lumaWeight,
+ population / (float) maxPopulation, populationWeight
+ );
+ }
+
+ /**
+ * Copy a {@link Swatch}'s HSL values into a new float[].
+ */
+ private static float[] copyHslValues(Swatch color) {
+ final float[] newHsl = new float[3];
+ System.arraycopy(color.getHsl(), 0, newHsl, 0, 3);
+ return newHsl;
+ }
+
+ /**
+ * Returns a value in the range 0-1. 1 is returned when {@code value} equals the
+ * {@code targetValue} and then decreases as the absolute difference between {@code value} and
+ * {@code targetValue} increases.
+ *
+ * @param value the item's value
+ * @param targetValue the value which we desire
+ */
+ private static float invertDiff(float value, float targetValue) {
+ return 1f - Math.abs(value - targetValue);
+ }
+
+ private static float weightedMean(float... values) {
+ float sum = 0f;
+ float sumWeight = 0f;
+
+ for (int i = 0; i < values.length; i += 2) {
+ float value = values[i];
+ float weight = values[i + 1];
+
+ sum += (value * weight);
+ sumWeight += weight;
+ }
+
+ return sum / sumWeight;
+ }
+}
diff --git a/core/java/com/android/internal/util/cm/palette/Palette.java b/core/java/com/android/internal/util/cm/palette/Palette.java
new file mode 100644
index 0000000..2cbd2b8
--- /dev/null
+++ b/core/java/com/android/internal/util/cm/palette/Palette.java
@@ -0,0 +1,740 @@
+/*
+ * 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 com.android.internal.util.cm.palette;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.os.AsyncTask;
+import android.annotation.ColorInt;
+import android.annotation.Nullable;
+import android.util.TimingLogger;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A helper class to extract prominent colors from an image.
+ * <p>
+ * A number of colors with different profiles are extracted from the image:
+ * <ul>
+ * <li>Vibrant</li>
+ * <li>Vibrant Dark</li>
+ * <li>Vibrant Light</li>
+ * <li>Muted</li>
+ * <li>Muted Dark</li>
+ * <li>Muted Light</li>
+ * </ul>
+ * These can be retrieved from the appropriate getter method.
+ *
+ * <p>
+ * Instances are created with a {@link Builder} which supports several options to tweak the
+ * generated Palette. See that class' documentation for more information.
+ * <p>
+ * Generation should always be completed on a background thread, ideally the one in
+ * which you load your image on. {@link Builder} supports both synchronous and asynchronous
+ * generation:
+ *
+ * <pre>
+ * // Synchronous
+ * Palette p = Palette.from(bitmap).generate();
+ *
+ * // Asynchronous
+ * Palette.from(bitmap).generate(new PaletteAsyncListener() {
+ * public void onGenerated(Palette p) {
+ * // Use generated instance
+ * }
+ * });
+ * </pre>
+ *
+ * @hide
+ */
+public final class Palette {
+
+ /**
+ * Listener to be used with {@link #generateAsync(Bitmap, PaletteAsyncListener)} or
+ * {@link #generateAsync(Bitmap, int, PaletteAsyncListener)}
+ */
+ public interface PaletteAsyncListener {
+
+ /**
+ * Called when the {@link Palette} has been generated.
+ */
+ void onGenerated(Palette palette);
+ }
+
+ private static final int DEFAULT_RESIZE_BITMAP_MAX_DIMENSION = 192;
+ private static final int DEFAULT_CALCULATE_NUMBER_COLORS = 16;
+
+ private static final float MIN_CONTRAST_TITLE_TEXT = 3.0f;
+ private static final float MIN_CONTRAST_BODY_TEXT = 4.5f;
+
+ private static final String LOG_TAG = "Palette";
+ private static final boolean LOG_TIMINGS = false;
+
+ /**
+ * Start generating a {@link Palette} with the returned {@link Builder} instance.
+ */
+ public static Builder from(Bitmap bitmap) {
+ return new Builder(bitmap);
+ }
+
+ /**
+ * Generate a {@link Palette} from the pre-generated list of {@link Palette.Swatch} swatches.
+ * This is useful for testing, or if you want to resurrect a {@link Palette} instance from a
+ * list of swatches. Will return null if the {@code swatches} is null.
+ */
+ public static Palette from(List<Swatch> swatches) {
+ return new Builder(swatches).generate();
+ }
+
+ /**
+ * @deprecated Use {@link Builder} to generate the Palette.
+ */
+ @Deprecated
+ public static Palette generate(Bitmap bitmap) {
+ return from(bitmap).generate();
+ }
+
+ /**
+ * @deprecated Use {@link Builder} to generate the Palette.
+ */
+ @Deprecated
+ public static Palette generate(Bitmap bitmap, int numColors) {
+ return from(bitmap).maximumColorCount(numColors).generate();
+ }
+
+ /**
+ * @deprecated Use {@link Builder} to generate the Palette.
+ */
+ @Deprecated
+ public static AsyncTask<Bitmap, Void, Palette> generateAsync(
+ Bitmap bitmap, PaletteAsyncListener listener) {
+ return from(bitmap).generate(listener);
+ }
+
+ /**
+ * @deprecated Use {@link Builder} to generate the Palette.
+ */
+ @Deprecated
+ public static AsyncTask<Bitmap, Void, Palette> generateAsync(
+ final Bitmap bitmap, final int numColors, final PaletteAsyncListener listener) {
+ return from(bitmap).maximumColorCount(numColors).generate(listener);
+ }
+
+ private final List<Swatch> mSwatches;
+ private final Generator mGenerator;
+
+ private Palette(List<Swatch> swatches, Generator generator) {
+ mSwatches = swatches;
+ mGenerator = generator;
+ }
+
+ /**
+ * Returns all of the swatches which make up the palette.
+ */
+ public List<Swatch> getSwatches() {
+ return Collections.unmodifiableList(mSwatches);
+ }
+
+ /**
+ * Returns the most vibrant swatch in the palette. Might be null.
+ */
+ @Nullable
+ public Swatch getVibrantSwatch() {
+ return mGenerator.getVibrantSwatch();
+ }
+
+ /**
+ * Returns a light and vibrant swatch from the palette. Might be null.
+ */
+ @Nullable
+ public Swatch getLightVibrantSwatch() {
+ return mGenerator.getLightVibrantSwatch();
+ }
+
+ /**
+ * Returns a dark and vibrant swatch from the palette. Might be null.
+ */
+ @Nullable
+ public Swatch getDarkVibrantSwatch() {
+ return mGenerator.getDarkVibrantSwatch();
+ }
+
+ /**
+ * Returns a muted swatch from the palette. Might be null.
+ */
+ @Nullable
+ public Swatch getMutedSwatch() {
+ return mGenerator.getMutedSwatch();
+ }
+
+ /**
+ * Returns a muted and light swatch from the palette. Might be null.
+ */
+ @Nullable
+ public Swatch getLightMutedSwatch() {
+ return mGenerator.getLightMutedSwatch();
+ }
+
+ /**
+ * Returns a muted and dark swatch from the palette. Might be null.
+ */
+ @Nullable
+ public Swatch getDarkMutedSwatch() {
+ return mGenerator.getDarkMutedSwatch();
+ }
+
+ /**
+ * Returns the most vibrant color in the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ @ColorInt
+ public int getVibrantColor(@ColorInt int defaultColor) {
+ Swatch swatch = getVibrantSwatch();
+ return swatch != null ? swatch.getRgb() : defaultColor;
+ }
+
+ /**
+ * Returns a light and vibrant color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ @ColorInt
+ public int getLightVibrantColor(@ColorInt int defaultColor) {
+ Swatch swatch = getLightVibrantSwatch();
+ return swatch != null ? swatch.getRgb() : defaultColor;
+ }
+
+ /**
+ * Returns a dark and vibrant color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ @ColorInt
+ public int getDarkVibrantColor(@ColorInt int defaultColor) {
+ Swatch swatch = getDarkVibrantSwatch();
+ return swatch != null ? swatch.getRgb() : defaultColor;
+ }
+
+ /**
+ * Returns a muted color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ @ColorInt
+ public int getMutedColor(@ColorInt int defaultColor) {
+ Swatch swatch = getMutedSwatch();
+ return swatch != null ? swatch.getRgb() : defaultColor;
+ }
+
+ /**
+ * Returns a muted and light color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ @ColorInt
+ public int getLightMutedColor(@ColorInt int defaultColor) {
+ Swatch swatch = getLightMutedSwatch();
+ return swatch != null ? swatch.getRgb() : defaultColor;
+ }
+
+ /**
+ * Returns a muted and dark color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ @ColorInt
+ public int getDarkMutedColor(@ColorInt int defaultColor) {
+ Swatch swatch = getDarkMutedSwatch();
+ return swatch != null ? swatch.getRgb() : defaultColor;
+ }
+
+ /**
+ * Scale the bitmap down so that it's largest dimension is {@code targetMaxDimension}.
+ * If {@code bitmap} is smaller than this, then it is returned.
+ */
+ private static Bitmap scaleBitmapDown(Bitmap bitmap, final int targetMaxDimension) {
+ final int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight());
+
+ if (maxDimension <= targetMaxDimension) {
+ // If the bitmap is small enough already, just return it
+ return bitmap;
+ }
+
+ final float scaleRatio = targetMaxDimension / (float) maxDimension;
+ return Bitmap.createScaledBitmap(bitmap,
+ Math.round(bitmap.getWidth() * scaleRatio),
+ Math.round(bitmap.getHeight() * scaleRatio),
+ false);
+ }
+
+ /**
+ * Represents a color swatch generated from an image's palette. The RGB color can be retrieved
+ * by calling {@link #getRgb()}.
+ */
+ public static final class Swatch {
+ private final int mRed, mGreen, mBlue;
+ private final int mRgb;
+ private final int mPopulation;
+
+ private boolean mGeneratedTextColors;
+ private int mTitleTextColor;
+ private int mBodyTextColor;
+
+ private float[] mHsl;
+
+ public Swatch(@ColorInt int color, int population) {
+ mRed = Color.red(color);
+ mGreen = Color.green(color);
+ mBlue = Color.blue(color);
+ mRgb = color;
+ mPopulation = population;
+ }
+
+ Swatch(int red, int green, int blue, int population) {
+ mRed = red;
+ mGreen = green;
+ mBlue = blue;
+ mRgb = Color.rgb(red, green, blue);
+ mPopulation = population;
+ }
+
+ /**
+ * @return this swatch's RGB color value
+ */
+ @ColorInt
+ public int getRgb() {
+ return mRgb;
+ }
+
+ /**
+ * Return this swatch's HSL values.
+ * hsv[0] is Hue [0 .. 360)
+ * hsv[1] is Saturation [0...1]
+ * hsv[2] is Lightness [0...1]
+ */
+ public float[] getHsl() {
+ if (mHsl == null) {
+ mHsl = new float[3];
+ ColorUtils.RGBToHSL(mRed, mGreen, mBlue, mHsl);
+ }
+ return mHsl;
+ }
+
+ /**
+ * @return the number of pixels represented by this swatch
+ */
+ public int getPopulation() {
+ return mPopulation;
+ }
+
+ /**
+ * Returns an appropriate color to use for any 'title' text which is displayed over this
+ * {@link Swatch}'s color. This color is guaranteed to have sufficient contrast.
+ */
+ @ColorInt
+ public int getTitleTextColor() {
+ ensureTextColorsGenerated();
+ return mTitleTextColor;
+ }
+
+ /**
+ * Returns an appropriate color to use for any 'body' text which is displayed over this
+ * {@link Swatch}'s color. This color is guaranteed to have sufficient contrast.
+ */
+ @ColorInt
+ public int getBodyTextColor() {
+ ensureTextColorsGenerated();
+ return mBodyTextColor;
+ }
+
+ private void ensureTextColorsGenerated() {
+ if (!mGeneratedTextColors) {
+ // First check white, as most colors will be dark
+ final int lightBodyAlpha = ColorUtils.calculateMinimumAlpha(
+ Color.WHITE, mRgb, MIN_CONTRAST_BODY_TEXT);
+ final int lightTitleAlpha = ColorUtils.calculateMinimumAlpha(
+ Color.WHITE, mRgb, MIN_CONTRAST_TITLE_TEXT);
+
+ if (lightBodyAlpha != -1 && lightTitleAlpha != -1) {
+ // If we found valid light values, use them and return
+ mBodyTextColor = ColorUtils.setAlphaComponent(Color.WHITE, lightBodyAlpha);
+ mTitleTextColor = ColorUtils.setAlphaComponent(Color.WHITE, lightTitleAlpha);
+ mGeneratedTextColors = true;
+ return;
+ }
+
+ final int darkBodyAlpha = ColorUtils.calculateMinimumAlpha(
+ Color.BLACK, mRgb, MIN_CONTRAST_BODY_TEXT);
+ final int darkTitleAlpha = ColorUtils.calculateMinimumAlpha(
+ Color.BLACK, mRgb, MIN_CONTRAST_TITLE_TEXT);
+
+ if (darkBodyAlpha != -1 && darkBodyAlpha != -1) {
+ // If we found valid dark values, use them and return
+ mBodyTextColor = ColorUtils.setAlphaComponent(Color.BLACK, darkBodyAlpha);
+ mTitleTextColor = ColorUtils.setAlphaComponent(Color.BLACK, darkTitleAlpha);
+ mGeneratedTextColors = true;
+ return;
+ }
+
+ // If we reach here then we can not find title and body values which use the same
+ // lightness, we need to use mismatched values
+ mBodyTextColor = lightBodyAlpha != -1
+ ? ColorUtils.setAlphaComponent(Color.WHITE, lightBodyAlpha)
+ : ColorUtils.setAlphaComponent(Color.BLACK, darkBodyAlpha);
+ mTitleTextColor = lightTitleAlpha != -1
+ ? ColorUtils.setAlphaComponent(Color.WHITE, lightTitleAlpha)
+ : ColorUtils.setAlphaComponent(Color.BLACK, darkTitleAlpha);
+ mGeneratedTextColors = true;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(getClass().getSimpleName())
+ .append(" [RGB: #").append(Integer.toHexString(getRgb())).append(']')
+ .append(" [HSL: ").append(Arrays.toString(getHsl())).append(']')
+ .append(" [Population: ").append(mPopulation).append(']')
+ .append(" [Title Text: #").append(Integer.toHexString(getTitleTextColor()))
+ .append(']')
+ .append(" [Body Text: #").append(Integer.toHexString(getBodyTextColor()))
+ .append(']').toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Swatch swatch = (Swatch) o;
+ return mPopulation == swatch.mPopulation && mRgb == swatch.mRgb;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * mRgb + mPopulation;
+ }
+ }
+
+ /**
+ * Builder class for generating {@link Palette} instances.
+ */
+ public static final class Builder {
+ private List<Swatch> mSwatches;
+ private Bitmap mBitmap;
+ private int mMaxColors = DEFAULT_CALCULATE_NUMBER_COLORS;
+ private int mResizeMaxDimension = DEFAULT_RESIZE_BITMAP_MAX_DIMENSION;
+ private final List<Filter> mFilters = new ArrayList<>();
+
+ private Generator mGenerator;
+
+ /**
+ * Construct a new {@link Builder} using a source {@link Bitmap}
+ */
+ public Builder(Bitmap bitmap) {
+ this();
+ if (bitmap == null || bitmap.isRecycled()) {
+ throw new IllegalArgumentException("Bitmap is not valid");
+ }
+ mBitmap = bitmap;
+ }
+
+ /**
+ * Construct a new {@link Builder} using a list of {@link Swatch} instances.
+ * Typically only used for testing.
+ */
+ public Builder(List<Swatch> swatches) {
+ this();
+ if (swatches == null || swatches.isEmpty()) {
+ throw new IllegalArgumentException("List of Swatches is not valid");
+ }
+ mSwatches = swatches;
+ }
+
+ private Builder() {
+ mFilters.add(DEFAULT_FILTER);
+ }
+
+ /**
+ * Set the {@link Generator} to use when generating the {@link Palette}. If this is called
+ * with {@code null} then the default generator will be used.
+ */
+ Builder generator(Generator generator) {
+ mGenerator = generator;
+ return this;
+ }
+
+ /**
+ * Set the maximum number of colors to use in the quantization step when using a
+ * {@link android.graphics.Bitmap} as the source.
+ * <p>
+ * Good values for depend on the source image type. For landscapes, good values are in
+ * the range 10-16. For images which are largely made up of people's faces then this
+ * value should be increased to ~24.
+ */
+ public Builder maximumColorCount(int colors) {
+ mMaxColors = colors;
+ return this;
+ }
+
+ /**
+ * Set the resize value when using a {@link android.graphics.Bitmap} as the source.
+ * If the bitmap's largest dimension is greater than the value specified, then the bitmap
+ * will be resized so that it's largest dimension matches {@code maxDimension}. If the
+ * bitmap is smaller or equal, the original is used as-is.
+ * <p>
+ * This value has a large effect on the processing time. The larger the resized image is,
+ * the greater time it will take to generate the palette. The smaller the image is, the
+ * more detail is lost in the resulting image and thus less precision for color selection.
+ */
+ public Builder resizeBitmapSize(int maxDimension) {
+ mResizeMaxDimension = maxDimension;
+ return this;
+ }
+
+ /**
+ * Clear all added filters. This includes any default filters added automatically by
+ * {@link Palette}.
+ */
+ public Builder clearFilters() {
+ mFilters.clear();
+ return this;
+ }
+
+ /**
+ * Add a filter to be able to have fine grained controlled over the colors which are
+ * allowed in the resulting palette.
+ *
+ * @param filter filter to add.
+ */
+ public Builder addFilter(Filter filter) {
+ if (filter != null) {
+ mFilters.add(filter);
+ }
+ return this;
+ }
+
+ /**
+ * Generate and return the {@link Palette} synchronously.
+ */
+ public Palette generate() {
+ final TimingLogger logger = LOG_TIMINGS
+ ? new TimingLogger(LOG_TAG, "Generation")
+ : null;
+
+ List<Swatch> swatches;
+
+ if (mBitmap != null) {
+ // We have a Bitmap so we need to quantization to reduce the number of colors
+
+ if (mResizeMaxDimension <= 0) {
+ throw new IllegalArgumentException(
+ "Minimum dimension size for resizing should should be >= 1");
+ }
+
+ // First we'll scale down the bitmap so it's largest dimension is as specified
+ final Bitmap scaledBitmap = scaleBitmapDown(mBitmap, mResizeMaxDimension);
+
+ if (logger != null) {
+ logger.addSplit("Processed Bitmap");
+ }
+
+ // Now generate a quantizer from the Bitmap
+ final int width = scaledBitmap.getWidth();
+ final int height = scaledBitmap.getHeight();
+ final int[] pixels = new int[width * height];
+ scaledBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
+
+ final ColorCutQuantizer quantizer = new ColorCutQuantizer(pixels, mMaxColors,
+ mFilters.isEmpty() ? null : mFilters.toArray(new Filter[mFilters.size()]));
+
+ // If created a new bitmap, recycle it
+ if (scaledBitmap != mBitmap) {
+ scaledBitmap.recycle();
+ }
+ swatches = quantizer.getQuantizedColors();
+
+ if (logger != null) {
+ logger.addSplit("Color quantization completed");
+ }
+ } else {
+ // Else we're using the provided swatches
+ swatches = mSwatches;
+ }
+
+ // If we haven't been provided with a generator, use the default
+ if (mGenerator == null) {
+ mGenerator = new DefaultGenerator();
+ }
+
+ // Now call let the Generator do it's thing
+ mGenerator.generate(swatches);
+
+ if (logger != null) {
+ logger.addSplit("Generator.generate() completed");
+ }
+
+ // Now create a Palette instance
+ Palette p = new Palette(swatches, mGenerator);
+
+ if (logger != null) {
+ logger.addSplit("Created Palette");
+ logger.dumpToLog();
+ }
+
+ return p;
+ }
+
+ /**
+ * Generate the {@link Palette} asynchronously. The provided listener's
+ * {@link PaletteAsyncListener#onGenerated} method will be called with the palette when
+ * generated.
+ */
+ public AsyncTask<Bitmap, Void, Palette> generate(final PaletteAsyncListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener can not be null");
+ }
+
+ AsyncTask<Bitmap, Void, Palette> task = new AsyncTask<Bitmap, Void, Palette>() {
+ @Override
+ protected Palette doInBackground(Bitmap... params) {
+ return generate();
+ }
+
+ @Override
+ protected void onPostExecute(Palette colorExtractor) {
+ listener.onGenerated(colorExtractor);
+ }
+ };
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mBitmap);
+ return task;
+ }
+ }
+
+ static abstract class Generator {
+
+ /**
+ * This method will be called with the {@link Palette.Swatch} that represent an image.
+ * You should process this list so that you have appropriate values when the other methods in
+ * class are called.
+ * <p>
+ * This method will probably be called on a background thread.
+ */
+ public abstract void generate(List<Palette.Swatch> swatches);
+
+ /**
+ * Return the most vibrant {@link Palette.Swatch}
+ */
+ public Palette.Swatch getVibrantSwatch() {
+ return null;
+ }
+
+ /**
+ * Return a light and vibrant {@link Palette.Swatch}
+ */
+ public Palette.Swatch getLightVibrantSwatch() {
+ return null;
+ }
+
+ /**
+ * Return a dark and vibrant {@link Palette.Swatch}
+ */
+ public Palette.Swatch getDarkVibrantSwatch() {
+ return null;
+ }
+
+ /**
+ * Return a muted {@link Palette.Swatch}
+ */
+ public Palette.Swatch getMutedSwatch() {
+ return null;
+ }
+
+ /**
+ * Return a muted and light {@link Palette.Swatch}
+ */
+ public Palette.Swatch getLightMutedSwatch() {
+ return null;
+ }
+
+ /**
+ * Return a muted and dark {@link Palette.Swatch}
+ */
+ public Palette.Swatch getDarkMutedSwatch() {
+ return null;
+ }
+ }
+
+ /**
+ * A Filter provides a mechanism for exercising fine-grained control over which colors
+ * are valid within a resulting {@link Palette}.
+ */
+ public interface Filter {
+ /**
+ * Hook to allow clients to be able filter colors from resulting palette.
+ *
+ * @param rgb the color in RGB888.
+ * @param hsl HSL representation of the color.
+ *
+ * @return true if the color is allowed, false if not.
+ *
+ * @see Builder#addFilter(Filter)
+ */
+ boolean isAllowed(int rgb, float[] hsl);
+ }
+
+ /**
+ * The default filter.
+ */
+ private static final Filter DEFAULT_FILTER = new Filter() {
+ private static final float BLACK_MAX_LIGHTNESS = 0.05f;
+ private static final float WHITE_MIN_LIGHTNESS = 0.95f;
+
+ @Override
+ public boolean isAllowed(int rgb, float[] hsl) {
+ return !isWhite(hsl) && !isBlack(hsl) && !isNearRedILine(hsl);
+ }
+
+ /**
+ * @return true if the color represents a color which is close to black.
+ */
+ private boolean isBlack(float[] hslColor) {
+ return hslColor[2] <= BLACK_MAX_LIGHTNESS;
+ }
+
+ /**
+ * @return true if the color represents a color which is close to white.
+ */
+ private boolean isWhite(float[] hslColor) {
+ return hslColor[2] >= WHITE_MIN_LIGHTNESS;
+ }
+
+ /**
+ * @return true if the color lies close to the red side of the I line.
+ */
+ private boolean isNearRedILine(float[] hslColor) {
+ return hslColor[0] >= 10f && hslColor[0] <= 37f && hslColor[1] <= 0.82f;
+ }
+ };
+}
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index b479cb1..9b4910e 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -25,6 +25,7 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
@@ -41,7 +42,8 @@ import com.android.internal.R;
public final class RotationPolicy {
private static final String TAG = "RotationPolicy";
private static final int CURRENT_ROTATION = -1;
- private static final int NATURAL_ROTATION = Surface.ROTATION_0;
+ private static final int NATURAL_ROTATION =
+ SystemProperties.getInt("persist.panel.orientation", Surface.ROTATION_0) / 90;
private RotationPolicy() {
}
@@ -72,7 +74,7 @@ public final class RotationPolicy {
* otherwise Configuration.ORIENTATION_UNDEFINED if any orientation is lockable.
*/
public static int getRotationLockOrientation(Context context) {
- if (!areAllRotationsAllowed(context)) {
+ if (!isCurrentRotationAllowed(context)) {
final Point size = new Point();
final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
try {
@@ -112,7 +114,8 @@ public final class RotationPolicy {
Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0,
UserHandle.USER_CURRENT);
- final int rotation = areAllRotationsAllowed(context) ? CURRENT_ROTATION : NATURAL_ROTATION;
+ final int rotation = isCurrentRotationAllowed(context)
+ ? CURRENT_ROTATION : NATURAL_ROTATION;
setRotationLock(enabled, rotation);
}
@@ -129,8 +132,39 @@ public final class RotationPolicy {
setRotationLock(enabled, NATURAL_ROTATION);
}
- private static boolean areAllRotationsAllowed(Context context) {
- return context.getResources().getBoolean(R.bool.config_allowAllRotations);
+ public static boolean isRotationAllowed(int rotation,
+ int userRotationAngles, boolean allowAllRotations) {
+ if (userRotationAngles < 0) {
+ // Not set by user so use these defaults
+ userRotationAngles = allowAllRotations ?
+ (1 | 2 | 4 | 8) : // All angles
+ (1 | 2 | 8); // All except 180
+ }
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ return (userRotationAngles & 1) != 0;
+ case Surface.ROTATION_90:
+ return (userRotationAngles & 2) != 0;
+ case Surface.ROTATION_180:
+ return (userRotationAngles & 4) != 0;
+ case Surface.ROTATION_270:
+ return (userRotationAngles & 8) != 0;
+ }
+ return false;
+ }
+
+ private static boolean isCurrentRotationAllowed(Context context) {
+ int userRotationAngles = Settings.System.getInt(context.getContentResolver(),
+ Settings.System.ACCELEROMETER_ROTATION_ANGLES, -1);
+ boolean allowAllRotations = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_allowAllRotations);
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ try {
+ return isRotationAllowed(wm.getRotation(), userRotationAngles, allowAllRotations);
+ } catch (RemoteException exc) {
+ Log.w(TAG, "Unable to getWindowManagerService.getRotation()");
+ }
+ return false;
}
private static void setRotationLock(final boolean enabled, final int rotation) {
@@ -194,4 +228,4 @@ public final class RotationPolicy {
public abstract void onChange();
}
-} \ No newline at end of file
+}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 4e4552d..cc951a5 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -33,10 +33,12 @@ interface ILockSettings {
void setLockPassword(in String password, in String savedPassword, int userId);
VerifyCredentialResponse checkPassword(in String password, int userId);
VerifyCredentialResponse verifyPassword(in String password, long challenge, int userId);
+ byte getLockPatternSize(int userId);
boolean checkVoldPassword(int userId);
boolean havePattern(int userId);
boolean havePassword(int userId);
void registerStrongAuthTracker(in IStrongAuthTracker tracker);
void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
void requireStrongAuth(int strongAuthReason, int userId);
+ void sanitizePassword();
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 60380fb..dc2cf1e 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -64,6 +64,11 @@ public class LockPatternUtils {
private static final boolean DEBUG = false;
/**
+ * The key to identify when the lock pattern enabled flag is being acccessed for legacy reasons.
+ */
+ public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";
+
+ /**
* The number of incorrect attempts before which we fall back on an alternative
* method of verifying the user, and resetting their lock pattern.
*/
@@ -91,6 +96,11 @@ public class LockPatternUtils {
*/
public static final int MIN_LOCK_PASSWORD_SIZE = 4;
+ /*
+ * The default size of the pattern lockscreen. Ex: 3x3
+ */
+ public static final byte PATTERN_SIZE_DEFAULT = 3;
+
/**
* The minimum number of dots the user must include in a wrong pattern
* attempt for it to be counted against the counts that affect
@@ -253,7 +263,7 @@ public class LockPatternUtils {
throws RequestThrottledException {
try {
VerifyCredentialResponse response =
- getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
+ getLockSettings().verifyPattern(patternToString(pattern, userId), challenge, userId);
if (response == null) {
// Shouldn't happen
return null;
@@ -281,7 +291,7 @@ public class LockPatternUtils {
throws RequestThrottledException {
try {
VerifyCredentialResponse response =
- getLockSettings().checkPattern(patternToString(pattern), userId);
+ getLockSettings().checkPattern(patternToString(pattern, userId), userId);
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
return true;
@@ -508,7 +518,7 @@ public class LockPatternUtils {
+ MIN_LOCK_PATTERN_SIZE + " dots long.");
}
- getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId);
+ getLockSettings().setLockPattern(patternToString(pattern, userId), savedPattern, userId);
DevicePolicyManager dpm = getDevicePolicyManager();
// Update the device encryption password.
@@ -517,7 +527,7 @@ public class LockPatternUtils {
if (!shouldEncryptWithCredentials(true)) {
clearEncryptionPassword();
} else {
- String stringPattern = patternToString(pattern);
+ String stringPattern = patternToString(pattern, userId);
updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
}
}
@@ -533,6 +543,17 @@ public class LockPatternUtils {
}
}
+ /**
+ * clears stored password.
+ */
+ public void sanitizePassword() {
+ try {
+ getLockSettings().sanitizePassword();
+ } catch (RemoteException re) {
+ Log.e(TAG, "Couldn't sanitize password" + re);
+ }
+ }
+
private void updateCryptoUserInfo(int userId) {
if (userId != UserHandle.USER_OWNER) {
return;
@@ -836,17 +857,18 @@ public class LockPatternUtils {
* @param string The pattern serialized with {@link #patternToString}
* @return The pattern.
*/
- public static List<LockPatternView.Cell> stringToPattern(String string) {
+ public static List<LockPatternView.Cell> stringToPattern(String string, byte gridSize) {
if (string == null) {
return null;
}
-
List<LockPatternView.Cell> result = Lists.newArrayList();
+ LockPatternView.Cell.updateSize(gridSize);
+
final byte[] bytes = string.getBytes();
for (int i = 0; i < bytes.length; i++) {
byte b = (byte) (bytes[i] - '1');
- result.add(LockPatternView.Cell.of(b / 3, b % 3));
+ result.add(LockPatternView.Cell.of(b / gridSize, b % gridSize, gridSize));
}
return result;
}
@@ -856,16 +878,26 @@ public class LockPatternUtils {
* @param pattern The pattern.
* @return The pattern in string form.
*/
- public static String patternToString(List<LockPatternView.Cell> pattern) {
+ public String patternToString(List<LockPatternView.Cell> pattern, int userId) {
+ return patternToString(pattern, getLockPatternSize(userId));
+ }
+
+ /**
+ * Serialize a pattern.
+ * @param pattern The pattern.
+ * @return The pattern in string form.
+ */
+ public static String patternToString(List<LockPatternView.Cell> pattern, byte gridSize) {
if (pattern == null) {
return "";
}
final int patternSize = pattern.size();
+ LockPatternView.Cell.updateSize(gridSize);
byte[] res = new byte[patternSize];
for (int i = 0; i < patternSize; i++) {
LockPatternView.Cell cell = pattern.get(i);
- res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
+ res[i] = (byte) (cell.getRow() * gridSize + cell.getColumn() + '1');
}
return new String(res);
}
@@ -875,7 +907,6 @@ public class LockPatternUtils {
return "";
}
final int patternSize = pattern.length();
-
byte[] res = new byte[patternSize];
final byte[] bytes = pattern.getBytes();
for (int i = 0; i < patternSize; i++) {
@@ -891,7 +922,7 @@ public class LockPatternUtils {
* @param pattern the gesture pattern.
* @return the hash of the pattern in a byte array.
*/
- public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
+ public static byte[] patternToHash(List<LockPatternView.Cell> pattern, byte gridSize) {
if (pattern == null) {
return null;
}
@@ -900,7 +931,7 @@ public class LockPatternUtils {
byte[] res = new byte[patternSize];
for (int i = 0; i < patternSize; i++) {
LockPatternView.Cell cell = pattern.get(i);
- res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
+ res[i] = (byte) (cell.getRow() * gridSize + cell.getColumn());
}
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
@@ -985,6 +1016,19 @@ public class LockPatternUtils {
return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
}
+ @Deprecated
+ public boolean isLegacyLockPatternEnabled(int userId) {
+ // Note: this value should default to {@code true} to avoid any reset that might result.
+ // We must use a special key to read this value, since it will by default return the value
+ // based on the new logic.
+ return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
+ }
+
+ @Deprecated
+ public void setLegacyLockPatternEnabled(int userId) {
+ setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
+ }
+
private boolean isLockPatternEnabled(int mode, int userId) {
return mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
&& savedPatternExists(userId);
@@ -1054,6 +1098,40 @@ public class LockPatternUtils {
}
/**
+ * @return the pattern lockscreen size
+ */
+ public byte getLockPatternSize(int userId) {
+ long size = getLong(Settings.Secure.LOCK_PATTERN_SIZE, -1, userId);
+ if (size > 0 && size < 128) {
+ return (byte) size;
+ }
+ return LockPatternUtils.PATTERN_SIZE_DEFAULT;
+ }
+
+ /**
+ * Set the pattern lockscreen size
+ */
+ public void setLockPatternSize(long size, int userId) {
+ setLong(Settings.Secure.LOCK_PATTERN_SIZE, size, userId);
+ }
+
+ public void setVisibleDotsEnabled(boolean enabled, int userId) {
+ setBoolean(Settings.Secure.LOCK_DOTS_VISIBLE, enabled, userId);
+ }
+
+ public boolean isVisibleDotsEnabled(int userId) {
+ return getBoolean(Settings.Secure.LOCK_DOTS_VISIBLE, true, userId);
+ }
+
+ public void setShowErrorPath(boolean enabled, int userId) {
+ setBoolean(Settings.Secure.LOCK_SHOW_ERROR_PATH, enabled, userId);
+ }
+
+ public boolean isShowErrorPath(int userId) {
+ return getBoolean(Settings.Secure.LOCK_SHOW_ERROR_PATH, true, userId);
+ }
+
+ /**
* Set and store the lockout deadline, meaning the user can't attempt his/her unlock
* pattern until the deadline has passed.
* @return the chosen deadline.
@@ -1090,7 +1168,7 @@ public class LockPatternUtils {
return deadline;
}
- private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
+ protected boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
try {
return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
} catch (RemoteException re) {
@@ -1098,7 +1176,7 @@ public class LockPatternUtils {
}
}
- private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
+ protected void setBoolean(String secureSettingKey, boolean enabled, int userId) {
try {
getLockSettings().setBoolean(secureSettingKey, enabled, userId);
} catch (RemoteException re) {
@@ -1107,7 +1185,7 @@ public class LockPatternUtils {
}
}
- private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
+ protected long getLong(String secureSettingKey, long defaultValue, int userHandle) {
try {
return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
} catch (RemoteException re) {
@@ -1115,7 +1193,7 @@ public class LockPatternUtils {
}
}
- private void setLong(String secureSettingKey, long value, int userHandle) {
+ protected void setLong(String secureSettingKey, long value, int userHandle) {
try {
getLockSettings().setLong(secureSettingKey, value, userHandle);
} catch (RemoteException re) {
@@ -1124,7 +1202,7 @@ public class LockPatternUtils {
}
}
- private String getString(String secureSettingKey, int userHandle) {
+ protected String getString(String secureSettingKey, int userHandle) {
try {
return getLockSettings().getString(secureSettingKey, null, userHandle);
} catch (RemoteException re) {
@@ -1132,7 +1210,7 @@ public class LockPatternUtils {
}
}
- private void setString(String secureSettingKey, String value, int userHandle) {
+ protected void setString(String secureSettingKey, String value, int userHandle) {
try {
getLockSettings().setString(secureSettingKey, value, userHandle);
} catch (RemoteException re) {
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 9211eaa..baa228f 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -51,6 +51,7 @@ import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import com.android.internal.R;
+import com.android.internal.widget.LockPatternUtils;
import java.util.ArrayList;
import java.util.HashMap;
@@ -58,7 +59,7 @@ import java.util.List;
/**
* Displays and detects the user's unlock attempt, which is a drag of a finger
- * across 9 regions of the screen.
+ * across regions of the screen.
*
* Is also capable of displaying a static pattern in "in progress", "wrong" or
* "correct" states.
@@ -70,7 +71,7 @@ public class LockPatternView extends View {
private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h)
private static final boolean PROFILE_DRAWING = false;
- private final CellState[][] mCellStates;
+ private CellState[][] mCellStates;
private final int mDotSize;
private final int mDotSizeActivated;
@@ -88,6 +89,8 @@ public class LockPatternView extends View {
*/
private static final int MILLIS_PER_CIRCLE_ANIMATING = 700;
+ private byte mPatternSize = LockPatternUtils.PATTERN_SIZE_DEFAULT;
+
/**
* This can be used to avoid updating the display for very small motions or noisy panels.
* It didn't seem to have much impact on the devices tested, so currently set to 0.
@@ -98,7 +101,7 @@ public class LockPatternView extends View {
private static final String TAG = "LockPatternView";
private OnPatternListener mOnPatternListener;
- private final ArrayList<Cell> mPattern = new ArrayList<Cell>(9);
+ private ArrayList<Cell> mPattern = new ArrayList<Cell>(mPatternSize * mPatternSize);
/**
* Lookup table for the circles of the pattern we are currently drawing.
@@ -106,7 +109,7 @@ public class LockPatternView extends View {
* in which case we use this to hold the cells we are drawing for the in
* progress animation.
*/
- private final boolean[][] mPatternDrawLookup = new boolean[3][3];
+ private boolean[][] mPatternDrawLookup = new boolean[mPatternSize][mPatternSize];
/**
* the in progress point:
@@ -123,6 +126,8 @@ public class LockPatternView extends View {
private boolean mInStealthMode = false;
private boolean mEnableHapticFeedback = true;
private boolean mPatternInProgress = false;
+ private boolean mVisibleDots = true;
+ private boolean mShowErrorPath = true;
private float mHitFactor = 0.6f;
@@ -143,32 +148,26 @@ public class LockPatternView extends View {
private PatternExploreByTouchHelper mExploreByTouchHelper;
private AudioManager mAudioManager;
+ private LockPatternUtils mLockPatternUtils;
+
/**
- * Represents a cell in the 3 X 3 matrix of the unlock pattern view.
+ * Represents a cell in the matrix of the unlock pattern view.
*/
public static final class Cell {
final int row;
final int column;
- // keep # objects limited to 9
- private static final Cell[][] sCells = createCells();
-
- private static Cell[][] createCells() {
- Cell[][] res = new Cell[3][3];
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- res[i][j] = new Cell(i, j);
- }
- }
- return res;
+ static Cell[][] sCells;
+ static {
+ updateSize(LockPatternUtils.PATTERN_SIZE_DEFAULT);
}
/**
* @param row The row of the cell.
* @param column The column of the cell.
*/
- private Cell(int row, int column) {
- checkRange(row, column);
+ private Cell(int row, int column, byte size) {
+ checkRange(row, column, size);
this.row = row;
this.column = column;
}
@@ -181,17 +180,30 @@ public class LockPatternView extends View {
return column;
}
- public static Cell of(int row, int column) {
- checkRange(row, column);
+ /**
+ * @param row The row of the cell.
+ * @param column The column of the cell.
+ */
+ public static synchronized Cell of(int row, int column, byte size) {
+ checkRange(row, column, size);
return sCells[row][column];
}
- private static void checkRange(int row, int column) {
- if (row < 0 || row > 2) {
- throw new IllegalArgumentException("row must be in range 0-2");
+ public static void updateSize(byte size) {
+ sCells = new Cell[size][size];
+ for (int i = 0; i < size; i++) {
+ for (int j = 0; j < size; j++) {
+ sCells[i][j] = new Cell(i, j, size);
+ }
}
- if (column < 0 || column > 2) {
- throw new IllegalArgumentException("column must be in range 0-2");
+ }
+
+ private static void checkRange(int row, int column, byte size) {
+ if (row < 0 || row > size - 1) {
+ throw new IllegalArgumentException("row must be in range 0-" + (size - 1));
+ }
+ if (column < 0 || column > size - 1) {
+ throw new IllegalArgumentException("column must be in range 0-" + (size - 1));
}
}
@@ -317,9 +329,9 @@ public class LockPatternView extends View {
mPaint.setAntiAlias(true);
mPaint.setDither(true);
- mCellStates = new CellState[3][3];
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
+ mCellStates = new CellState[mPatternSize][mPatternSize];
+ for (int i = 0; i < mPatternSize; i++) {
+ for (int j = 0; j < mPatternSize; j++) {
mCellStates[i][j] = new CellState();
mCellStates[i][j].radius = mDotSize/2;
mCellStates[i][j].row = i;
@@ -355,6 +367,13 @@ public class LockPatternView extends View {
}
/**
+ * @return the current pattern lockscreen size.
+ */
+ public byte getLockPatternSize() {
+ return mPatternSize;
+ }
+
+ /**
* Set whether the view is in stealth mode. If true, there will be no
* visible feedback as the user enters the pattern.
*
@@ -364,6 +383,22 @@ public class LockPatternView extends View {
mInStealthMode = inStealthMode;
}
+ public void setVisibleDots(boolean visibleDots) {
+ mVisibleDots = visibleDots;
+ }
+
+ public boolean isVisibleDots() {
+ return mVisibleDots;
+ }
+
+ public void setShowErrorPath(boolean showErrorPath) {
+ mShowErrorPath = showErrorPath;
+ }
+
+ public boolean isShowErrorPath() {
+ return mShowErrorPath;
+ }
+
/**
* Set whether the view will use tactile feedback. If true, there will be
* tactile feedback as the user enters the pattern.
@@ -375,6 +410,35 @@ public class LockPatternView extends View {
}
/**
+ * Set the pattern size of the lockscreen
+ *
+ * @param size The pattern size.
+ */
+ public void setLockPatternSize(byte size) {
+ mPatternSize = size;
+ Cell.updateSize(size);
+ mCellStates = new CellState[mPatternSize][mPatternSize];
+ for (int i = 0; i < mPatternSize; i++) {
+ for (int j = 0; j < mPatternSize; j++) {
+ mCellStates[i][j] = new CellState();
+ mCellStates[i][j].radius = mDotSize / 2;
+ mCellStates[i][j].row = i;
+ mCellStates[i][j].col = j;
+ }
+ }
+ mPattern = new ArrayList<Cell>(size * size);
+ mPatternDrawLookup = new boolean[size][size];
+ }
+
+ /**
+ * Set the LockPatternUtil instance used to encode a pattern to a string
+ * @param utils The instance.
+ */
+ public void setLockPatternUtils(LockPatternUtils utils) {
+ mLockPatternUtils = utils;
+ }
+
+ /**
* Set the call back for pattern detection.
* @param onPatternListener The call back.
*/
@@ -589,8 +653,8 @@ public class LockPatternView extends View {
* Clear the pattern lookup table.
*/
private void clearPatternDrawLookup() {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
+ for (int i = 0; i < mPatternSize; i++) {
+ for (int j = 0; j < mPatternSize; j++) {
mPatternDrawLookup[i][j] = false;
}
}
@@ -614,11 +678,11 @@ public class LockPatternView extends View {
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
final int width = w - mPaddingLeft - mPaddingRight;
- mSquareWidth = width / 3.0f;
+ mSquareWidth = width / (float) mPatternSize;
if (DEBUG_A11Y) Log.v(TAG, "onSizeChanged(" + w + "," + h + ")");
final int height = h - mPaddingTop - mPaddingBottom;
- mSquareHeight = height / 3.0f;
+ mSquareHeight = height / (float) mPatternSize;
mExploreByTouchHelper.invalidateRoot();
}
@@ -674,7 +738,6 @@ public class LockPatternView extends View {
if (cell != null) {
// check for gaps in existing pattern
- Cell fillInGapCell = null;
final ArrayList<Cell> pattern = mPattern;
if (!pattern.isEmpty()) {
final Cell lastCell = pattern.get(pattern.size() - 1);
@@ -684,21 +747,19 @@ public class LockPatternView extends View {
int fillInRow = lastCell.row;
int fillInColumn = lastCell.column;
- if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) {
- fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1);
- }
-
- if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) {
- fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1);
+ if (dRow == 0 || dColumn == 0 || Math.abs(dRow) == Math.abs(dColumn)) {
+ while (true) {
+ fillInRow += Integer.signum(dRow);
+ fillInColumn += Integer.signum(dColumn);
+ if (fillInRow == cell.row && fillInColumn == cell.column) break;
+ Cell fillInGapCell = Cell.of(fillInRow, fillInColumn, mPatternSize);
+ if (!mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
+ addCellToPattern(fillInGapCell);
+ }
+ }
}
-
- fillInGapCell = Cell.of(fillInRow, fillInColumn);
}
- if (fillInGapCell != null &&
- !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
- addCellToPattern(fillInGapCell);
- }
addCellToPattern(cell);
if (mEnableHapticFeedback) {
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
@@ -796,7 +857,7 @@ public class LockPatternView extends View {
if (mPatternDrawLookup[rowHit][columnHit]) {
return null;
}
- return Cell.of(rowHit, columnHit);
+ return Cell.of(rowHit, columnHit, mPatternSize);
}
/**
@@ -810,7 +871,7 @@ public class LockPatternView extends View {
float hitSize = squareHeight * mHitFactor;
float offset = mPaddingTop + (squareHeight - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < mPatternSize; i++) {
final float hitTop = offset + squareHeight * i;
if (y >= hitTop && y <= hitTop + hitSize) {
@@ -830,7 +891,7 @@ public class LockPatternView extends View {
float hitSize = squareWidth * mHitFactor;
float offset = mPaddingLeft + (squareWidth - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < mPatternSize; i++) {
final float hitLeft = offset + squareWidth * i;
if (x >= hitLeft && x <= hitLeft + hitSize) {
@@ -984,8 +1045,8 @@ public class LockPatternView extends View {
}
private void cancelLineAnimations() {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
+ for (int i = 0; i < mPatternSize; i++) {
+ for (int j = 0; j < mPatternSize; j++) {
CellState state = mCellStates[i][j];
if (state.lineAnimator != null) {
state.lineAnimator.cancel();
@@ -1088,20 +1149,21 @@ public class LockPatternView extends View {
currentPath.rewind();
// draw the circles
- for (int i = 0; i < 3; i++) {
- float centerY = getCenterYForRow(i);
- for (int j = 0; j < 3; j++) {
- CellState cellState = mCellStates[i][j];
- float centerX = getCenterXForColumn(j);
- float translationY = cellState.translationY;
- if (isHardwareAccelerated() && cellState.hwAnimating) {
- DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
- displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY,
- cellState.hwRadius, cellState.hwPaint);
- } else {
- drawCircle(canvas, (int) centerX, (int) centerY + translationY,
- cellState.radius, drawLookup[i][j], cellState.alpha);
-
+ if (mVisibleDots) {
+ for (int i = 0; i < mPatternSize; i++) {
+ float centerY = getCenterYForRow(i);
+ for (int j = 0; j < mPatternSize; j++) {
+ CellState cellState = mCellStates[i][j];
+ float centerX = getCenterXForColumn(j);
+ float translationY = cellState.translationY;
+ if (isHardwareAccelerated() && cellState.hwAnimating) {
+ DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
+ displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY,
+ cellState.hwRadius, cellState.hwPaint);
+ } else {
+ drawCircle(canvas, (int) centerX, (int) centerY + translationY,
+ cellState.radius, drawLookup[i][j], cellState.alpha);
+ }
}
}
}
@@ -1109,8 +1171,8 @@ public class LockPatternView extends View {
// TODO: the path should be created and cached every time we hit-detect a cell
// only the last segment of the path should be computed here
// draw the path of the pattern (unless we are in stealth mode)
- final boolean drawPath = !mInStealthMode;
-
+ final boolean drawPath = ((!mInStealthMode && mPatternDisplayMode != DisplayMode.Wrong)
+ || (mPatternDisplayMode == DisplayMode.Wrong && mShowErrorPath));
if (drawPath) {
mPathPaint.setColor(getCurrentColor(true /* partOfPattern */));
@@ -1168,7 +1230,9 @@ public class LockPatternView extends View {
}
private int getCurrentColor(boolean partOfPattern) {
- if (!partOfPattern || mInStealthMode || mPatternInProgress) {
+ if (!partOfPattern || (mInStealthMode && mPatternDisplayMode != DisplayMode.Wrong)
+ || (mPatternDisplayMode == DisplayMode.Wrong && !mShowErrorPath)
+ || mPatternInProgress) {
// unselected circle
return mRegularColor;
} else if (mPatternDisplayMode == DisplayMode.Wrong) {
@@ -1196,9 +1260,9 @@ public class LockPatternView extends View {
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
return new SavedState(superState,
- LockPatternUtils.patternToString(mPattern),
- mPatternDisplayMode.ordinal(),
- mInputEnabled, mInStealthMode, mEnableHapticFeedback);
+ LockPatternUtils.patternToString(mPattern, mPatternSize),
+ mPatternDisplayMode.ordinal(), mPatternSize,
+ mInputEnabled, mInStealthMode, mEnableHapticFeedback, mVisibleDots, mShowErrorPath);
}
@Override
@@ -1207,11 +1271,14 @@ public class LockPatternView extends View {
super.onRestoreInstanceState(ss.getSuperState());
setPattern(
DisplayMode.Correct,
- LockPatternUtils.stringToPattern(ss.getSerializedPattern()));
+ LockPatternUtils.stringToPattern(ss.getSerializedPattern(), ss.getPatternSize()));
mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()];
+ mPatternSize = ss.getPatternSize();
mInputEnabled = ss.isInputEnabled();
mInStealthMode = ss.isInStealthMode();
mEnableHapticFeedback = ss.isTactileFeedbackEnabled();
+ mVisibleDots = ss.isVisibleDots();
+ mShowErrorPath = ss.isShowErrorPath();
}
/**
@@ -1221,21 +1288,28 @@ public class LockPatternView extends View {
private final String mSerializedPattern;
private final int mDisplayMode;
+ private final byte mPatternSize;
private final boolean mInputEnabled;
private final boolean mInStealthMode;
private final boolean mTactileFeedbackEnabled;
+ private final boolean mVisibleDots;
+ private final boolean mShowErrorPath;
/**
* Constructor called from {@link LockPatternView#onSaveInstanceState()}
*/
private SavedState(Parcelable superState, String serializedPattern, int displayMode,
- boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled) {
+ byte patternSize, boolean inputEnabled, boolean inStealthMode,
+ boolean tactileFeedbackEnabled, boolean visibleDots, boolean showErrorPath) {
super(superState);
mSerializedPattern = serializedPattern;
mDisplayMode = displayMode;
+ mPatternSize = patternSize;
mInputEnabled = inputEnabled;
mInStealthMode = inStealthMode;
mTactileFeedbackEnabled = tactileFeedbackEnabled;
+ mVisibleDots = visibleDots;
+ mShowErrorPath = showErrorPath;
}
/**
@@ -1245,9 +1319,12 @@ public class LockPatternView extends View {
super(in);
mSerializedPattern = in.readString();
mDisplayMode = in.readInt();
+ mPatternSize = (byte) in.readByte();
mInputEnabled = (Boolean) in.readValue(null);
mInStealthMode = (Boolean) in.readValue(null);
mTactileFeedbackEnabled = (Boolean) in.readValue(null);
+ mVisibleDots = (Boolean) in.readValue(null);
+ mShowErrorPath = (Boolean) in.readValue(null);
}
public String getSerializedPattern() {
@@ -1258,6 +1335,10 @@ public class LockPatternView extends View {
return mDisplayMode;
}
+ public byte getPatternSize() {
+ return mPatternSize;
+ }
+
public boolean isInputEnabled() {
return mInputEnabled;
}
@@ -1270,14 +1351,25 @@ public class LockPatternView extends View {
return mTactileFeedbackEnabled;
}
+ public boolean isVisibleDots() {
+ return mVisibleDots;
+ }
+
+ public boolean isShowErrorPath() {
+ return mShowErrorPath;
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(mSerializedPattern);
dest.writeInt(mDisplayMode);
+ dest.writeByte(mPatternSize);
dest.writeValue(mInputEnabled);
dest.writeValue(mInStealthMode);
dest.writeValue(mTactileFeedbackEnabled);
+ dest.writeValue(mVisibleDots);
+ dest.writeValue(mShowErrorPath);
}
@SuppressWarnings({ "unused", "hiding" }) // Found using reflection
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index 35ed63b..d88f479 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -89,14 +89,21 @@ public class SwipeDismissLayout extends FrameLayout {
}
};
private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
+ private Runnable mRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mDismissed) {
+ dismiss();
+ } else {
+ cancel();
+ }
+ resetMembers();
+ }
+ };
+
@Override
public void onReceive(Context context, Intent intent) {
- if (mDismissed) {
- dismiss();
- } else {
- cancel();
- }
- resetMembers();
+ post(mRunnable);
}
};
private IntentFilter mScreenOffFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index 92d5aea..6103ebc 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -97,6 +97,7 @@ public class BootReceiver extends BroadcastReceiver {
final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
final SharedPreferences prefs = ctx.getSharedPreferences("log_files", Context.MODE_PRIVATE);
final String headers = new StringBuilder(512)
+ .append("CM Version: ").append(SystemProperties.get("ro.cm.version")).append("\n")
.append("Build: ").append(Build.FINGERPRINT).append("\n")
.append("Hardware: ").append(Build.BOARD).append("\n")
.append("Revision: ")
diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java
index 3d9fb5c..c3dcd40 100644
--- a/core/java/com/android/server/net/BaseNetworkObserver.java
+++ b/core/java/com/android/server/net/BaseNetworkObserver.java
@@ -63,6 +63,11 @@ public class BaseNetworkObserver extends INetworkManagementEventObserver.Stub {
}
@Override
+ public void interfaceMessageRecevied(String message) {
+ // default no-op
+ }
+
+ @Override
public void limitReached(String limitName, String iface) {
// default no-op
}
diff --git a/core/java/org/codeaurora/camera/Android.mk b/core/java/org/codeaurora/camera/Android.mk
new file mode 100644
index 0000000..2e005f7
--- /dev/null
+++ b/core/java/org/codeaurora/camera/Android.mk
@@ -0,0 +1,30 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE:= org.codeaurora.camera
+
+# This will install the file in /system/framework
+LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)
+
+include $(BUILD_JAVA_LIBRARY)
+
+# ==== permissions ========================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := org.codeaurora.camera.xml
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_CLASS := ETC
+
+# This will install the file in /system/etc/permissions
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
diff --git a/core/java/org/codeaurora/camera/ExtendedFace.java b/core/java/org/codeaurora/camera/ExtendedFace.java
new file mode 100644
index 0000000..afda0b6
--- /dev/null
+++ b/core/java/org/codeaurora/camera/ExtendedFace.java
@@ -0,0 +1,211 @@
+/* Copyright (c) 2015, The Linux Foundataion. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+package org.codeaurora.camera;
+
+import android.hardware.Camera;
+
+import java.util.ArrayList;
+
+import android.os.Bundle;
+
+import android.os.SystemProperties;
+
+/**
+ * {@hide} Information about a face identified through Extended camera face
+ *
+ * <p>
+ * When face detection is used with a camera, the {@link FaceDetectionListener}
+ * returns a list of face objects for use in focusing and metering.
+ * </p>
+ *
+ * @see FaceDetectionListener
+ */
+public class ExtendedFace extends android.hardware.Camera.Face {
+ public ExtendedFace() {
+ super();
+ }
+
+ private int smileDegree = 0;
+ private int smileScore = 0;
+ private int blinkDetected = 0;
+ private int faceRecognized = 0;
+ private int gazeAngle = 0;
+ private int updownDir = 0;
+ private int leftrightDir = 0;
+ private int rollDir = 0;
+ private int leyeBlink = 0;
+ private int reyeBlink = 0;
+ private int leftrightGaze = 0;
+ private int topbottomGaze = 0;
+
+ private static final String STR_TRUE = "true";
+ private static final String STR_FALSE = "false";
+
+ /**
+ * The smilie degree for the detection of the face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getSmileDegree() {
+ return smileDegree;
+ }
+
+ /**
+ * The smilie score for the detection of the face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getSmileScore() {
+ return smileScore;
+ }
+
+ /**
+ * The smilie degree for the detection of the face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getBlinkDetected() {
+ return blinkDetected;
+ }
+
+ /**
+ * If face is recognized.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getFaceRecognized() {
+ return faceRecognized;
+ }
+
+ /**
+ * The gaze angle for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getGazeAngle() {
+ return gazeAngle;
+ }
+
+ /**
+ * The up down direction for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getUpDownDirection() {
+ return updownDir;
+ }
+
+ /**
+ * The left right direction for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getLeftRightDirection() {
+ return leftrightDir;
+ }
+
+ /**
+ * The roll direction for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getRollDirection() {
+ return rollDir;
+ }
+
+ /**
+ * The degree of left eye blink for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getLeftEyeBlinkDegree() {
+ return leyeBlink;
+ }
+
+ /**
+ * The degree of right eye blink for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getRightEyeBlinkDegree() {
+ return reyeBlink;
+ }
+
+ /**
+ * The gaze degree of left-right direction for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getLeftRightGazeDegree() {
+ return leftrightGaze;
+ }
+
+ /**
+ * The gaze degree of up-down direction for the detected face.
+ *
+ * @see #startFaceDetection()
+ */
+ public int getTopBottomGazeDegree() {
+ return topbottomGaze;
+ }
+
+ private static final String BUNDLE_KEY_SMILE_SCORE = "smileScore";
+ private static final String BUNDLE_KEY_SMILE_VALUE = "smileValue";
+ private static final String BUNDLE_KEY_BLINK_DETECTED = "blinkDetected";
+ private static final String BUNDLE_KEY_LEFT_EYE_CLOSED_VALUE = "leftEyeClosedValue";
+ private static final String BUNDLE_KEY_RIGHT_EYE_CLOSED_VALUE = "rightEyeClosedValue";
+ private static final String BUNDLE_KEY_FACE_PITCH_DEGREE = "facePitchDegree";
+ private static final String BUNDLE_KEY_FACE_YAW_DEGREE = "faceYawDegree";
+ private static final String BUNDLE_KEY_FACE_ROLL_DEGREE = "faceRollDegree";
+ private static final String BUNDLE_KEY_GAZE_UP_DOWN_DEGREE = "gazeUpDownDegree";
+ private static final String BUNDLE_KEY_GAZE_LEFT_RIGHT_DEGREE = "gazeLeftRightDegree";
+ private static final String BUNDLE_KEY_FACE_RECOGNIZED = "faceRecognized";
+
+ public Bundle getExtendedFaceInfo() {
+ Bundle faceInfo = new Bundle();
+ faceInfo.putInt(BUNDLE_KEY_SMILE_VALUE, this.smileDegree);
+
+ faceInfo.putInt(BUNDLE_KEY_LEFT_EYE_CLOSED_VALUE, this.leyeBlink);
+ faceInfo.putInt(BUNDLE_KEY_RIGHT_EYE_CLOSED_VALUE, this.reyeBlink);
+
+ faceInfo.putInt(BUNDLE_KEY_FACE_PITCH_DEGREE, this.updownDir);
+ faceInfo.putInt(BUNDLE_KEY_FACE_YAW_DEGREE, this.leftrightDir);
+ faceInfo.putInt(BUNDLE_KEY_FACE_ROLL_DEGREE, this.rollDir);
+ faceInfo.putInt(BUNDLE_KEY_GAZE_UP_DOWN_DEGREE, this.topbottomGaze);
+ faceInfo.putInt(BUNDLE_KEY_GAZE_LEFT_RIGHT_DEGREE, this.leftrightGaze);
+
+ faceInfo.putInt(BUNDLE_KEY_BLINK_DETECTED, this.blinkDetected);
+ faceInfo.putInt(BUNDLE_KEY_SMILE_SCORE, this.smileScore);
+ faceInfo.putInt(BUNDLE_KEY_FACE_RECOGNIZED, this.faceRecognized);
+
+ return faceInfo;
+ }
+
+}
diff --git a/core/java/org/codeaurora/camera/org.codeaurora.camera.xml b/core/java/org/codeaurora/camera/org.codeaurora.camera.xml
new file mode 100644
index 0000000..20b2aa0
--- /dev/null
+++ b/core/java/org/codeaurora/camera/org.codeaurora.camera.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-->
+
+<!-- This is the library that allows devices to use Camera QFace APIs. -->
+<permissions>
+ <library name="org.codeaurora.camera"
+ file="/system/framework/org.codeaurora.camera.jar" />
+</permissions>