summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt48
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java12
-rw-r--r--core/java/android/app/ApplicationPackageManager.java29
-rw-r--r--core/java/android/app/INotificationManager.aidl5
-rw-r--r--core/java/android/app/Notification.java2
-rw-r--r--core/java/android/app/NotificationManager.java13
-rw-r--r--core/java/android/app/usage/UsageEvents.java4
-rw-r--r--core/java/android/app/usage/UsageStats.java16
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java10
-rw-r--r--core/java/android/content/Context.java56
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl17
-rw-r--r--core/java/android/content/pm/KeySet.aidl19
-rw-r--r--core/java/android/content/pm/KeySet.java60
-rw-r--r--core/java/android/content/pm/PackageManager.java7
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java7
-rw-r--r--core/java/android/hardware/camera2/TotalCaptureResult.java24
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java81
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java50
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java2
-rw-r--r--core/java/android/net/NetworkBoundURLFactory.java35
-rw-r--r--core/java/android/provider/Settings.java17
-rw-r--r--core/java/android/security/IKeystoreService.java62
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java94
-rw-r--r--core/java/android/transition/ChangeBounds.java92
-rw-r--r--core/java/android/util/Spline.java325
-rw-r--r--core/java/android/view/RenderNodeAnimator.java52
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java4
-rw-r--r--core/res/res/color/btn_default_material_dark.xml4
-rw-r--r--core/res/res/color/btn_default_material_light.xml4
-rw-r--r--core/res/res/color/primary_text_disable_only_material_dark.xml4
-rw-r--r--core/res/res/color/primary_text_disable_only_material_light.xml4
-rw-r--r--core/res/res/color/primary_text_material_dark.xml4
-rw-r--r--core/res/res/color/primary_text_material_light.xml4
-rw-r--r--core/res/res/color/secondary_text_material_dark.xml22
-rw-r--r--core/res/res/color/secondary_text_material_light.xml22
-rw-r--r--core/res/res/drawable/progress_horizontal_material.xml4
-rw-r--r--core/res/res/layout/action_menu_item_layout.xml3
-rw-r--r--core/res/res/values/colors_material.xml19
-rw-r--r--core/res/res/values/dimens_material.xml5
-rw-r--r--core/res/res/values/ids.xml2
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--core/res/res/values/themes_material.xml20
-rw-r--r--docs/html/guide/topics/admin/device-admin.jd41
-rw-r--r--graphics/java/android/graphics/drawable/Ripple.java28
-rw-r--r--graphics/java/android/graphics/drawable/RippleBackground.java38
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java145
-rw-r--r--keystore/java/android/security/KeyStore.java30
-rw-r--r--libs/androidfw/tests/Android.mk1
-rw-r--r--libs/androidfw/tests/BackupData_test.cpp43
-rw-r--r--libs/androidfw/tests/ObbFile_test.cpp18
-rw-r--r--libs/androidfw/tests/Theme_test.cpp68
-rw-r--r--libs/androidfw/tests/data/app/AndroidManifest.xml (renamed from packages/DocumentsUI/res/drawable/grid_protect_background.xml)11
-rw-r--r--libs/androidfw/tests/data/app/R.h22
-rw-r--r--libs/androidfw/tests/data/app/app_arsc.h62
-rwxr-xr-xlibs/androidfw/tests/data/app/build6
-rw-r--r--libs/androidfw/tests/data/app/res/values/values.xml7
-rw-r--r--libs/androidfw/tests/data/system/AndroidManifest.xml19
-rw-r--r--libs/androidfw/tests/data/system/R.h23
-rwxr-xr-xlibs/androidfw/tests/data/system/build6
-rw-r--r--libs/androidfw/tests/data/system/res/values/themes.xml13
-rw-r--r--libs/androidfw/tests/data/system/system_arsc.h69
-rw-r--r--libs/hwui/AmbientShadow.cpp547
-rw-r--r--libs/hwui/AmbientShadow.h15
-rw-r--r--libs/hwui/Animator.cpp2
-rwxr-xr-xlibs/hwui/OpenGLRenderer.cpp4
-rw-r--r--libs/hwui/Vector.h17
-rw-r--r--libs/hwui/VertexBuffer.h39
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp1
-rw-r--r--media/java/android/media/MediaCodec.java13
-rw-r--r--media/java/android/media/session/MediaSession.java10
-rw-r--r--media/java/android/media/tv/TvContentRating.java10
-rw-r--r--packages/DocumentsUI/res/color/item_root_icon.xml21
-rw-r--r--packages/DocumentsUI/res/color/item_root_primary_text.xml22
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_grid_selection_check.pngbin0 -> 1575 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_grid_selection_check.pngbin0 -> 996 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_grid_selection_check.pngbin0 -> 2062 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_selection_check.pngbin0 -> 3976 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_grid_selection_check.pngbin0 -> 4126 bytes
-rw-r--r--packages/DocumentsUI/res/drawable/item_doc_grid_overlay.xml22
-rw-r--r--packages/DocumentsUI/res/drawable/item_doc_grid_overlay_icon.xml21
-rw-r--r--packages/DocumentsUI/res/drawable/item_doc_list_background.xml (renamed from packages/DocumentsUI/res/drawable/item_activated_overlay.xml)8
-rw-r--r--packages/DocumentsUI/res/drawable/item_root_background.xml (renamed from packages/DocumentsUI/res/drawable/item_activated.xml)0
-rw-r--r--packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml2
-rw-r--r--packages/DocumentsUI/res/layout/item_doc_grid.xml27
-rw-r--r--packages/DocumentsUI/res/layout/item_doc_list.xml2
-rw-r--r--packages/DocumentsUI/res/layout/item_root.xml12
-rw-r--r--packages/DocumentsUI/res/values/colors.xml14
-rw-r--r--packages/DocumentsUI/res/values/styles.xml1
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java38
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/IconUtils.java15
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsCache.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java12
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java25
-rw-r--r--packages/SystemUI/res/drawable/ic_android.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_close.xml24
-rw-r--r--packages/SystemUI/res/layout/keyguard_bottom_area.xml2
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml4
-rw-r--r--packages/SystemUI/res/values/strings.xml34
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java11
-rw-r--r--policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java6
-rw-r--r--policy/src/com/android/internal/policy/impl/GlobalActions.java8
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java9
-rw-r--r--services/accessibility/java/com/android/server/accessibility/TouchExplorer.java1
-rw-r--r--services/core/java/com/android/server/LockSettingsService.java73
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityManagerService.java20
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java2
-rw-r--r--services/core/java/com/android/server/am/ContentProviderRecord.java12
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java2
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java18
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java1
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java75
-rw-r--r--services/core/java/com/android/server/notification/RankingHelper.java11
-rw-r--r--services/core/java/com/android/server/notification/ValidateNotificationPeople.java118
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java22
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java89
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/AppWindowAnimator.java4
-rw-r--r--telecomm/java/android/telecomm/PhoneAccount.java2
-rw-r--r--telecomm/java/android/telecomm/TelecommManager.java65
-rw-r--r--telecomm/java/com/android/internal/telecomm/ITelecommService.aidl54
-rw-r--r--telecomm/java/com/android/internal/telecomm/RemoteServiceCallback.aidl2
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java4
-rw-r--r--tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java12
-rw-r--r--tools/aapt/Command.cpp6
-rw-r--r--tools/apilint/apilint.py76
131 files changed, 2740 insertions, 982 deletions
diff --git a/api/current.txt b/api/current.txt
index 117cafb..009b534 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1759,6 +1759,7 @@ package android {
field public static final int list = 16908298; // 0x102000a
field public static final int mask = 16908353; // 0x1020041
field public static final int message = 16908299; // 0x102000b
+ field public static final int navigationBarBackground = 16908355; // 0x1020043
field public static final int paste = 16908322; // 0x1020022
field public static final int primary = 16908300; // 0x102000c
field public static final int progress = 16908301; // 0x102000d
@@ -1767,6 +1768,7 @@ package android {
field public static final int selectTextMode = 16908333; // 0x102002d
field public static final int selectedIcon = 16908302; // 0x102000e
field public static final int startSelectingText = 16908328; // 0x1020028
+ field public static final int statusBarBackground = 16908354; // 0x1020042
field public static final int stopSelectingText = 16908329; // 0x1020029
field public static final int summary = 16908304; // 0x1020010
field public static final int switchInputMethod = 16908324; // 0x1020024
@@ -5748,7 +5750,7 @@ package android.app.usage {
}
public final class UsageStatsManager {
- method public android.util.ArrayMap<java.lang.String, android.app.usage.UsageStats> queryAndAggregateUsageStats(long, long);
+ method public java.util.Map<java.lang.String, android.app.usage.UsageStats> queryAndAggregateUsageStats(long, long);
method public android.app.usage.UsageEvents queryEvents(long, long);
method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long);
field public static final int INTERVAL_BEST = 4; // 0x4
@@ -7287,8 +7289,8 @@ package android.content {
method public void registerComponentCallbacks(android.content.ComponentCallbacks);
method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
- method public abstract void removeStickyBroadcast(android.content.Intent);
- method public abstract void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+ method public abstract deprecated void removeStickyBroadcast(android.content.Intent);
+ method public abstract deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public abstract void revokeUriPermission(android.net.Uri, int);
method public abstract void sendBroadcast(android.content.Intent);
method public abstract void sendBroadcast(android.content.Intent, java.lang.String);
@@ -7297,10 +7299,10 @@ package android.content {
method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String);
method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
method public abstract void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
- method public abstract void sendStickyBroadcast(android.content.Intent);
- method public abstract void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
- method public abstract void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
- method public abstract void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public abstract deprecated void sendStickyBroadcast(android.content.Intent);
+ method public abstract deprecated void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+ method public abstract deprecated void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public abstract deprecated void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
method public abstract void setTheme(int);
method public abstract deprecated void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
method public abstract deprecated void setWallpaper(java.io.InputStream) throws java.io.IOException;
@@ -8580,9 +8582,6 @@ package android.content.pm {
field public java.lang.String targetPackage;
}
- public class KeySet {
- }
-
public class LabeledIntent extends android.content.Intent {
ctor public LabeledIntent(android.content.Intent, java.lang.String, int, int);
ctor public LabeledIntent(android.content.Intent, java.lang.String, java.lang.CharSequence, int);
@@ -8818,7 +8817,6 @@ package android.content.pm {
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public abstract java.lang.String getInstallerPackageName(java.lang.String);
method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.content.pm.KeySet getKeySetByAlias(java.lang.String, java.lang.String);
method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public abstract java.lang.String getNameForUid(int);
@@ -8838,15 +8836,12 @@ package android.content.pm {
method public abstract android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.content.pm.KeySet getSigningKeySet(java.lang.String);
method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
method public abstract java.lang.String[] getSystemSharedLibraryNames();
method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
method public abstract boolean hasSystemFeature(java.lang.String);
method public abstract boolean isSafeMode();
- method public abstract boolean isSignedBy(java.lang.String, android.content.pm.KeySet);
- method public abstract boolean isSignedByExactly(java.lang.String, android.content.pm.KeySet);
method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
method public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(java.lang.String, int, int);
method public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
@@ -17199,10 +17194,6 @@ package android.net {
field public static final android.os.Parcelable.Creator CREATOR;
}
- public abstract interface NetworkBoundURLFactory {
- method public abstract java.net.URL getBoundURL(android.net.Network, java.net.URL) throws java.net.MalformedURLException;
- }
-
public final class NetworkCapabilities implements android.os.Parcelable {
ctor public NetworkCapabilities(android.net.NetworkCapabilities);
method public int describeContents();
@@ -28410,6 +28401,7 @@ package android.telecomm {
}
public static class PhoneAccount.Builder {
+ ctor public PhoneAccount.Builder();
method public android.telecomm.PhoneAccount build();
method public android.telecomm.PhoneAccount.Builder withAccountHandle(android.telecomm.PhoneAccountHandle);
method public android.telecomm.PhoneAccount.Builder withCapabilities(int);
@@ -29790,7 +29782,6 @@ package android.test.mock {
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public java.lang.String getInstallerPackageName(java.lang.String);
method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public android.content.pm.KeySet getKeySetByAlias(java.lang.String, java.lang.String);
method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public java.lang.String getNameForUid(int);
@@ -29809,15 +29800,12 @@ package android.test.mock {
method public android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo);
method public android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public android.content.pm.KeySet getSigningKeySet(java.lang.String);
method public android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
method public java.lang.String[] getSystemSharedLibraryNames();
method public java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
method public boolean hasSystemFeature(java.lang.String);
method public boolean isSafeMode();
- method public boolean isSignedBy(java.lang.String, android.content.pm.KeySet);
- method public boolean isSignedByExactly(java.lang.String, android.content.pm.KeySet);
method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
method public java.util.List<android.content.pm.ProviderInfo> queryContentProviders(java.lang.String, int, int);
method public java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
@@ -39575,22 +39563,6 @@ package android.widget {
}
-package com.android.internal.telecomm {
-
- public abstract interface RemoteServiceCallback implements android.os.IInterface {
- method public abstract void onError() throws android.os.RemoteException;
- method public abstract void onResult(java.util.List<android.content.ComponentName>, java.util.List<android.os.IBinder>) throws android.os.RemoteException;
- }
-
- public static abstract class RemoteServiceCallback.Stub extends android.os.Binder implements com.android.internal.telecomm.RemoteServiceCallback {
- ctor public RemoteServiceCallback.Stub();
- method public android.os.IBinder asBinder();
- method public static com.android.internal.telecomm.RemoteServiceCallback asInterface(android.os.IBinder);
- method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
- }
-
-}
-
package com.android.internal.util {
public abstract interface Predicate {
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index d9b40b1..da34094 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -866,6 +866,7 @@ public final class Pm {
private void runInstall() {
int installFlags = PackageManager.INSTALL_ALL_USERS;
+ int userId = UserHandle.USER_ALL;
String installerPackageName = null;
String opt;
@@ -909,6 +910,13 @@ public final class Pm {
}
} else if (opt.equals("--abi")) {
abi = checkAbiArgument(nextOptionData());
+ } else if (opt.equals("--user")) {
+ userId = Integer.parseInt(nextOptionData());
+ if (userId == UserHandle.USER_ALL) {
+ installFlags |= PackageManager.INSTALL_ALL_USERS;
+ } else {
+ installFlags &= ~PackageManager.INSTALL_ALL_USERS;
+ }
} else {
System.err.println("Error: Unknown option: " + opt);
return;
@@ -953,8 +961,8 @@ public final class Pm {
VerificationParams verificationParams = new VerificationParams(verificationURI,
originatingURI, referrerURI, VerificationParams.NO_UID, null);
- mPm.installPackage(apkFilePath, obs.getBinder(), installFlags, installerPackageName,
- verificationParams, abi);
+ mPm.installPackageAsUser(apkFilePath, obs.getBinder(), installFlags, installerPackageName,
+ verificationParams, abi, userId);
synchronized (obs) {
while (!obs.finished) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 9342ae5..6843827 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1494,57 +1494,52 @@ final class ApplicationPackageManager extends PackageManager {
return false;
}
+ /** @hide */
@Override
public KeySet getKeySetByAlias(String packageName, String alias) {
Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(alias);
- IBinder keySetToken;
+ KeySet ks;
try {
- keySetToken = mPM.getKeySetByAlias(packageName, alias);
+ ks = mPM.getKeySetByAlias(packageName, alias);
} catch (RemoteException e) {
return null;
}
- if (keySetToken == null) {
- return null;
- }
- return new KeySet(keySetToken);
+ return ks;
}
+ /** @hide */
@Override
public KeySet getSigningKeySet(String packageName) {
Preconditions.checkNotNull(packageName);
- IBinder keySetToken;
+ KeySet ks;
try {
- keySetToken = mPM.getSigningKeySet(packageName);
+ ks = mPM.getSigningKeySet(packageName);
} catch (RemoteException e) {
return null;
}
- if (keySetToken == null) {
- return null;
- }
- return new KeySet(keySetToken);
+ return ks;
}
-
+ /** @hide */
@Override
public boolean isSignedBy(String packageName, KeySet ks) {
Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(ks);
- IBinder keySetToken = ks.getToken();
try {
- return mPM.isPackageSignedByKeySet(packageName, keySetToken);
+ return mPM.isPackageSignedByKeySet(packageName, ks);
} catch (RemoteException e) {
return false;
}
}
+ /** @hide */
@Override
public boolean isSignedByExactly(String packageName, KeySet ks) {
Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(ks);
- IBinder keySetToken = ks.getToken();
try {
- return mPM.isPackageSignedByKeySetExactly(packageName, keySetToken);
+ return mPM.isPackageSignedByKeySetExactly(packageName, ks);
} catch (RemoteException e) {
return false;
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 214f50c..dbd180f 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -23,6 +23,7 @@ import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.net.Uri;
+import android.os.Bundle;
import android.service.notification.Condition;
import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
@@ -58,13 +59,15 @@ interface INotificationManager
void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
void cancelNotificationsFromListener(in INotificationListener token, in String[] keys);
- ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys);
+ ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim);
void requestHintsFromListener(in INotificationListener token, int hints);
int getHintsFromListener(in INotificationListener token);
void requestInterruptionFilterFromListener(in INotificationListener token, int interruptionFilter);
int getInterruptionFilterFromListener(in INotificationListener token);
+ void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
ComponentName getEffectsSuppressor();
+ boolean matchesCallFilter(in Bundle extras);
ZenModeConfig getZenModeConfig();
boolean setZenModeConfig(in ZenModeConfig config);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8a26ba5..966d2ce 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1424,6 +1424,8 @@ public class Notification implements Parcelable
extras.remove(Notification.EXTRA_LARGE_ICON);
extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
extras.remove(Notification.EXTRA_PICTURE);
+ // Prevent light notifications from being rebuilt.
+ extras.remove(Builder.EXTRA_NEEDS_REBUILD);
}
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index fc047de..7dc1ad6 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -20,6 +20,7 @@ import android.annotation.SdkConstant;
import android.app.Notification.Builder;
import android.content.ComponentName;
import android.content.Context;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -251,5 +252,17 @@ public class NotificationManager
}
}
+ /**
+ * @hide
+ */
+ public boolean matchesCallFilter(Bundle extras) {
+ INotificationManager service = getService();
+ try {
+ return service.matchesCallFilter(extras);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
private Context mContext;
}
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 2431ad0..fb80de2 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -106,7 +106,9 @@ public final class UsageEvents implements Parcelable {
}
/**
- * The time at which this event occurred.
+ * The time at which this event occurred, measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
*/
public long getTimeStamp() {
return mTimeStamp;
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index e47a802..abfc435 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -81,28 +81,36 @@ public final class UsageStats implements Parcelable {
}
/**
- * Get the beginning of the time range this {@link android.app.usage.UsageStats} represents.
+ * Get the beginning of the time range this {@link android.app.usage.UsageStats} represents,
+ * measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
*/
public long getFirstTimeStamp() {
return mBeginTimeStamp;
}
/**
- * Get the end of the time range this {@link android.app.usage.UsageStats} represents.
+ * Get the end of the time range this {@link android.app.usage.UsageStats} represents,
+ * measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
*/
public long getLastTimeStamp() {
return mEndTimeStamp;
}
/**
- * Get the last time this package was used.
+ * Get the last time this package was used, measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
*/
public long getLastTimeUsed() {
return mLastTimeUsed;
}
/**
- * Get the total time this package spent in the foreground.
+ * Get the total time this package spent in the foreground, measured in milliseconds.
*/
public long getTotalTimeInForeground() {
return mTotalTimeInForeground;
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index f9b8928..5830fcf 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -23,6 +23,7 @@ import android.util.ArrayMap;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
/**
* Provides access to device usage history and statistics. Usage data is aggregated into
@@ -149,7 +150,6 @@ public final class UsageStatsManager {
* @param endTime The exclusive end of the range of events to include in the results.
* @return A {@link UsageEvents}.
*/
- @SuppressWarnings("unchecked")
public UsageEvents queryEvents(long beginTime, long endTime) {
try {
UsageEvents iter = mService.queryEvents(beginTime, endTime,
@@ -170,15 +170,13 @@ public final class UsageStatsManager {
*
* @param beginTime The inclusive beginning of the range of stats to include in the results.
* @param endTime The exclusive end of the range of stats to include in the results.
- * @return An {@link android.util.ArrayMap} keyed by package name or null if no stats are
+ * @return A {@link java.util.Map} keyed by package name, or null if no stats are
* available.
*/
- public ArrayMap<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) {
+ public Map<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) {
List<UsageStats> stats = queryUsageStats(INTERVAL_BEST, beginTime, endTime);
if (stats.isEmpty()) {
- @SuppressWarnings("unchecked")
- ArrayMap<String, UsageStats> emptyStats = ArrayMap.EMPTY;
- return emptyStats;
+ return Collections.emptyMap();
}
ArrayMap<String, UsageStats> aggregatedStats = new ArrayMap<>();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index b7d7c25..f979a0c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1486,8 +1486,6 @@ public abstract class Context {
* @see #sendBroadcast(Intent)
* @see #sendBroadcast(Intent, String)
* @see #sendOrderedBroadcast(Intent, String)
- * @see #sendStickyBroadcast(Intent)
- * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
* @see android.content.BroadcastReceiver
* @see #registerReceiver
* @see android.app.Activity#RESULT_OK
@@ -1584,7 +1582,7 @@ public abstract class Context {
@Nullable Bundle initialExtras);
/**
- * Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
+ * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
* Intent you are sending stays around after the broadcast is complete,
* so that others can quickly retrieve that data through the return
* value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}. In
@@ -1595,6 +1593,12 @@ public abstract class Context {
* permission in order to use this API. If you do not hold that
* permission, {@link SecurityException} will be thrown.
*
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast, and the Intent will be held to
* be re-broadcast to future receivers.
@@ -1602,10 +1606,11 @@ public abstract class Context {
* @see #sendBroadcast(Intent)
* @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
*/
+ @Deprecated
public abstract void sendStickyBroadcast(Intent intent);
/**
- * Version of {@link #sendStickyBroadcast} that allows you to
+ * <p>Version of {@link #sendStickyBroadcast} that allows you to
* receive data back from the broadcast. This is accomplished by
* supplying your own BroadcastReceiver when calling, which will be
* treated as a final receiver at the end of the broadcast -- its
@@ -1622,6 +1627,12 @@ public abstract class Context {
*
* <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
*
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast.
* @param resultReceiver Your own BroadcastReceiver to treat as the final
@@ -1644,31 +1655,45 @@ public abstract class Context {
* @see #registerReceiver
* @see android.app.Activity#RESULT_OK
*/
+ @Deprecated
public abstract void sendStickyOrderedBroadcast(Intent intent,
BroadcastReceiver resultReceiver,
@Nullable Handler scheduler, int initialCode, @Nullable String initialData,
@Nullable Bundle initialExtras);
/**
- * Remove the data previously sent with {@link #sendStickyBroadcast},
+ * <p>Remove the data previously sent with {@link #sendStickyBroadcast},
* so that it is as if the sticky broadcast had never happened.
*
* <p>You must hold the {@link android.Manifest.permission#BROADCAST_STICKY}
* permission in order to use this API. If you do not hold that
* permission, {@link SecurityException} will be thrown.
*
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
* @param intent The Intent that was previously broadcast.
*
* @see #sendStickyBroadcast
*/
+ @Deprecated
public abstract void removeStickyBroadcast(Intent intent);
/**
- * Version of {@link #sendStickyBroadcast(Intent)} that allows you to specify the
+ * <p>Version of {@link #sendStickyBroadcast(Intent)} that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
* that are not pre-installed on the system image. Using it requires holding
* the INTERACT_ACROSS_USERS permission.
*
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast, and the Intent will be held to
* be re-broadcast to future receivers.
@@ -1676,10 +1701,11 @@ public abstract class Context {
*
* @see #sendBroadcast(Intent)
*/
+ @Deprecated
public abstract void sendStickyBroadcastAsUser(Intent intent, UserHandle user);
/**
- * Version of
+ * <p>Version of
* {@link #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)}
* that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
@@ -1688,6 +1714,12 @@ public abstract class Context {
*
* <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
*
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast.
* @param user UserHandle to send the intent to.
@@ -1705,13 +1737,14 @@ public abstract class Context {
*
* @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
*/
+ @Deprecated
public abstract void sendStickyOrderedBroadcastAsUser(Intent intent,
UserHandle user, BroadcastReceiver resultReceiver,
@Nullable Handler scheduler, int initialCode, @Nullable String initialData,
@Nullable Bundle initialExtras);
/**
- * Version of {@link #removeStickyBroadcast(Intent)} that allows you to specify the
+ * <p>Version of {@link #removeStickyBroadcast(Intent)} that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
* that are not pre-installed on the system image. Using it requires holding
* the INTERACT_ACROSS_USERS permission.
@@ -1720,11 +1753,18 @@ public abstract class Context {
* permission in order to use this API. If you do not hold that
* permission, {@link SecurityException} will be thrown.
*
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
* @param intent The Intent that was previously broadcast.
* @param user UserHandle to remove the sticky broadcast from.
*
* @see #sendStickyBroadcastAsUser
*/
+ @Deprecated
public abstract void removeStickyBroadcastAsUser(Intent intent, UserHandle user);
/**
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 44478d4..3e1f60a 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -32,6 +32,7 @@ import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
+import android.content.pm.KeySet;
import android.content.pm.PackageInfo;
import android.content.pm.ManifestDigest;
import android.content.pm.PackageCleanItem;
@@ -198,6 +199,14 @@ interface IPackageManager {
in VerificationParams verificationParams,
in String packageAbiOverride);
+ void installPackageAsUser(in String originPath,
+ in IPackageInstallObserver2 observer,
+ int flags,
+ in String installerPackageName,
+ in VerificationParams verificationParams,
+ in String packageAbiOverride,
+ int userId);
+
void finishPackageInstall(int token);
void setInstallerPackageName(in String targetPackage, in String installerPackageName);
@@ -446,8 +455,8 @@ interface IPackageManager {
boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId);
boolean getBlockUninstallForUser(String packageName, int userId);
- IBinder getKeySetByAlias(String packageName, String alias);
- IBinder getSigningKeySet(String packageName);
- boolean isPackageSignedByKeySet(String packageName, IBinder ks);
- boolean isPackageSignedByKeySetExactly(String packageName, IBinder ks);
+ KeySet getKeySetByAlias(String packageName, String alias);
+ KeySet getSigningKeySet(String packageName);
+ boolean isPackageSignedByKeySet(String packageName, in KeySet ks);
+ boolean isPackageSignedByKeySetExactly(String packageName, in KeySet ks);
}
diff --git a/core/java/android/content/pm/KeySet.aidl b/core/java/android/content/pm/KeySet.aidl
new file mode 100644
index 0000000..493d288
--- /dev/null
+++ b/core/java/android/content/pm/KeySet.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.content.pm;
+
+parcelable KeySet; \ No newline at end of file
diff --git a/core/java/android/content/pm/KeySet.java b/core/java/android/content/pm/KeySet.java
index fcdaa18..643db7e 100644
--- a/core/java/android/content/pm/KeySet.java
+++ b/core/java/android/content/pm/KeySet.java
@@ -17,13 +17,16 @@
package android.content.pm;
import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
/**
* Represents a {@code KeySet} that has been declared in the AndroidManifest.xml
* file for the application. A {@code KeySet} can be used explicitly to
* represent a trust relationship with other applications on the device.
+ * @hide
*/
-public class KeySet {
+public class KeySet implements Parcelable {
private IBinder token;
@@ -40,6 +43,7 @@ public class KeySet {
return token;
}
+ /** @hide */
@Override
public boolean equals(Object o) {
if (o instanceof KeySet) {
@@ -48,4 +52,58 @@ public class KeySet {
}
return false;
}
+
+ /** @hide */
+ @Override
+ public int hashCode() {
+ return token.hashCode();
+ }
+
+ /**
+ * Implement Parcelable
+ * @hide
+ */
+ public static final Parcelable.Creator<KeySet> CREATOR
+ = new Parcelable.Creator<KeySet>() {
+
+ /**
+ * Create a KeySet from a Parcel
+ *
+ * @param in The parcel containing the KeySet
+ */
+ public KeySet createFromParcel(Parcel source) {
+ return readFromParcel(source);
+ }
+
+ /**
+ * Create an array of null KeySets
+ */
+ public KeySet[] newArray(int size) {
+ return new KeySet[size];
+ }
+ };
+
+ /**
+ * @hide
+ */
+ private static KeySet readFromParcel(Parcel in) {
+ IBinder token = in.readStrongBinder();
+ return new KeySet(token);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeStrongBinder(token);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
} \ No newline at end of file
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index fa2bb4d..1b15ff5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3698,10 +3698,13 @@ public abstract class PackageManager {
*
* @param alias The alias for a given {@link KeySet} as defined in the
* application's AndroidManifest.xml.
+ * @hide
*/
public abstract KeySet getKeySetByAlias(String packageName, String alias);
- /** Return the signing {@link KeySet} for this application. */
+ /** Return the signing {@link KeySet} for this application.
+ * @hide
+ */
public abstract KeySet getSigningKeySet(String packageName);
/**
@@ -3709,6 +3712,7 @@ public abstract class PackageManager {
* of the keys specified by the {@link KeySet} ks. This will return true if
* the package has been signed by additional keys (a superset) as well.
* Compare to {@link #isSignedByExactly(String packageName, KeySet ks)}.
+ * @hide
*/
public abstract boolean isSignedBy(String packageName, KeySet ks);
@@ -3716,6 +3720,7 @@ public abstract class PackageManager {
* Return whether the package denoted by packageName has been signed by all
* of, and only, the keys specified by the {@link KeySet} ks. Compare to
* {@link #isSignedBy(String packageName, KeySet ks)}.
+ * @hide
*/
public abstract boolean isSignedByExactly(String packageName, KeySet ks);
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 3c9b7b3..a57b361 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1575,6 +1575,13 @@ public abstract class CameraMetadata<TKey> {
*/
public static final int CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO = 17;
+ /**
+ * <p>Turn on custom high dynamic range (HDR) mode.</p>
+ * @see CaptureRequest#CONTROL_SCENE_MODE
+ * @hide
+ */
+ public static final int CONTROL_SCENE_MODE_HDR = 18;
+
//
// Enumeration values for CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
//
diff --git a/core/java/android/hardware/camera2/TotalCaptureResult.java b/core/java/android/hardware/camera2/TotalCaptureResult.java
index ec4bc7d..0895fe3 100644
--- a/core/java/android/hardware/camera2/TotalCaptureResult.java
+++ b/core/java/android/hardware/camera2/TotalCaptureResult.java
@@ -19,6 +19,7 @@ package android.hardware.camera2;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.CaptureResultExtras;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -48,13 +49,23 @@ import java.util.List;
*/
public final class TotalCaptureResult extends CaptureResult {
+ private final List<CaptureResult> mPartialResults;
+
/**
- * Takes ownership of the passed-in properties object
+ * Takes ownership of the passed-in camera metadata and the partial results
+ *
+ * @param partials a list of partial results; {@code null} will be substituted for an empty list
* @hide
*/
public TotalCaptureResult(CameraMetadataNative results, CaptureRequest parent,
- CaptureResultExtras extras) {
+ CaptureResultExtras extras, List<CaptureResult> partials) {
super(results, parent, extras);
+
+ if (partials == null) {
+ mPartialResults = new ArrayList<>();
+ } else {
+ mPartialResults = partials;
+ }
}
/**
@@ -65,6 +76,8 @@ public final class TotalCaptureResult extends CaptureResult {
*/
public TotalCaptureResult(CameraMetadataNative results, int sequenceId) {
super(results, sequenceId);
+
+ mPartialResults = new ArrayList<>();
}
/**
@@ -73,14 +86,13 @@ public final class TotalCaptureResult extends CaptureResult {
* <p>The list is returned is unmodifiable; attempting to modify it will result in a
* {@code UnsupportedOperationException} being thrown.</p>
*
- * <p>The list size will be inclusive between {@code 1} and
- * {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT}, in ascending order
+ * <p>The list size will be inclusive between {@code 0} and
+ * {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT}, with elements in ascending order
* of when {@link CameraCaptureSession.CaptureListener#onCaptureProgressed} was invoked.</p>
*
* @return unmodifiable list of partial results
*/
public List<CaptureResult> getPartialResults() {
- // TODO
- return Collections.unmodifiableList(null);
+ return Collections.unmodifiableList(mPartialResults);
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index d75dfe6..f5666bf 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -41,6 +41,7 @@ import android.view.Surface;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -967,6 +968,8 @@ public class CameraDeviceImpl extends CameraDevice {
private long mCompletedFrameNumber = -1;
private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
+ /** Map frame numbers to list of partial results */
+ private final HashMap<Long, List<CaptureResult>> mPartialResults = new HashMap<>();
private void update() {
Iterator<Long> iter = mFutureErrorSet.iterator();
@@ -983,8 +986,8 @@ public class CameraDeviceImpl extends CameraDevice {
/**
* This function is called every time when a result or an error is received.
- * @param frameNumber: the frame number corresponding to the result or error
- * @param isError: true if it is an error, false if it is not an error
+ * @param frameNumber the frame number corresponding to the result or error
+ * @param isError true if it is an error, false if it is not an error
*/
public void updateTracker(long frameNumber, boolean isError) {
if (isError) {
@@ -1006,6 +1009,55 @@ public class CameraDeviceImpl extends CameraDevice {
update();
}
+ /**
+ * This function is called every time a result has been completed.
+ *
+ * <p>It keeps a track of all the partial results already created for a particular
+ * frame number.</p>
+ *
+ * @param frameNumber the frame number corresponding to the result
+ * @param result the total or partial result
+ * @param partial {@true} if the result is partial, {@code false} if total
+ */
+ public void updateTracker(long frameNumber, CaptureResult result, boolean partial) {
+
+ if (!partial) {
+ // Update the total result's frame status as being successful
+ updateTracker(frameNumber, /*isError*/false);
+ // Don't keep a list of total results, we don't need to track them
+ return;
+ }
+
+ if (result == null) {
+ // Do not record blank results; this also means there will be no total result
+ // so it doesn't matter that the partials were not recorded
+ return;
+ }
+
+ // Partial results must be aggregated in-order for that frame number
+ List<CaptureResult> partials = mPartialResults.get(frameNumber);
+ if (partials == null) {
+ partials = new ArrayList<>();
+ mPartialResults.put(frameNumber, partials);
+ }
+
+ partials.add(result);
+ }
+
+ /**
+ * Attempt to pop off all of the partial results seen so far for the {@code frameNumber}.
+ *
+ * <p>Once popped-off, the partial results are forgotten (unless {@code updateTracker}
+ * is called again with new partials for that frame number).</p>
+ *
+ * @param frameNumber the frame number corresponding to the result
+ * @return a list of partial results for that frame with at least 1 element,
+ * or {@code null} if there were no partials recorded for that frame
+ */
+ public List<CaptureResult> popPartialResults(long frameNumber) {
+ return mPartialResults.remove(frameNumber);
+ }
+
public long getCompletedFrameNumber() {
return mCompletedFrameNumber;
}
@@ -1244,12 +1296,6 @@ public class CameraDeviceImpl extends CameraDevice {
boolean isPartialResult =
(resultExtras.getPartialResultCount() < mTotalPartialCount);
- // Update tracker (increment counter) when it's not a partial result.
- if (!isPartialResult) {
- mFrameNumberTracker.updateTracker(frameNumber,
- /*error*/false);
- }
-
// Check if we have a listener for this
if (holder == null) {
if (DEBUG) {
@@ -1257,6 +1303,9 @@ public class CameraDeviceImpl extends CameraDevice {
"holder is null, early return at frame "
+ frameNumber);
}
+
+ mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
+
return;
}
@@ -1266,6 +1315,8 @@ public class CameraDeviceImpl extends CameraDevice {
"camera is closed, early return at frame "
+ frameNumber);
}
+
+ mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
return;
}
@@ -1273,6 +1324,8 @@ public class CameraDeviceImpl extends CameraDevice {
Runnable resultDispatch = null;
+ CaptureResult finalResult;
+
// Either send a partial result or the final capture completed result
if (isPartialResult) {
final CaptureResult resultAsCapture =
@@ -1290,9 +1343,14 @@ public class CameraDeviceImpl extends CameraDevice {
}
}
};
+
+ finalResult = resultAsCapture;
} else {
+ List<CaptureResult> partialResults =
+ mFrameNumberTracker.popPartialResults(frameNumber);
+
final TotalCaptureResult resultAsCapture =
- new TotalCaptureResult(result, request, resultExtras);
+ new TotalCaptureResult(result, request, resultExtras, partialResults);
// Final capture result
resultDispatch = new Runnable() {
@@ -1306,10 +1364,15 @@ public class CameraDeviceImpl extends CameraDevice {
}
}
};
+
+ finalResult = resultAsCapture;
}
holder.getHandler().post(resultDispatch);
+ // Collect the partials for a total result; or mark the frame as totally completed
+ mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult);
+
// Fire onCaptureSequenceCompleted
if (!isPartialResult) {
checkAndFireSequenceComplete();
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index febb015..f47ce79 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -67,7 +67,6 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
/**
* Implementation of camera metadata marshal/unmarshal across Binder to
@@ -655,6 +654,15 @@ public class CameraMetadataNative implements Parcelable {
private Face[] getFaces() {
Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE);
+ byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES);
+ Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES);
+ int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS);
+ int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS);
+
+ if (areValuesAllNull(faceDetectMode, faceScores, faceRectangles, faceIds, faceLandmarks)) {
+ return null;
+ }
+
if (faceDetectMode == null) {
Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE");
faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
@@ -670,8 +678,6 @@ public class CameraMetadataNative implements Parcelable {
}
// Face scores and rectangles are required by SIMPLE and FULL mode.
- byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES);
- Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES);
if (faceScores == null || faceRectangles == null) {
Log.w(TAG, "Expect face scores and rectangles to be non-null");
return new Face[0];
@@ -683,8 +689,6 @@ public class CameraMetadataNative implements Parcelable {
// To be safe, make number of faces is the minimal of all face info metadata length.
int numFaces = Math.min(faceScores.length, faceRectangles.length);
// Face id and landmarks are only required by FULL mode.
- int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS);
- int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS);
if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
if (faceIds == null || faceLandmarks == null) {
Log.w(TAG, "Expect face ids and landmarks to be non-null for FULL mode," +
@@ -755,22 +759,32 @@ public class CameraMetadataNative implements Parcelable {
private LensShadingMap getLensShadingMap() {
float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP);
+ Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE);
+
+ // Do not warn if lsmArray is null while s is not. This is valid.
if (lsmArray == null) {
- Log.w(TAG, "getLensShadingMap - Lens shading map was null.");
return null;
}
- Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE);
+
+ if (s == null) {
+ Log.w(TAG, "getLensShadingMap - Lens shading map size was null.");
+ return null;
+ }
+
LensShadingMap map = new LensShadingMap(lsmArray, s.getHeight(), s.getWidth());
return map;
}
private Location getGpsLocation() {
String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
- Location l = new Location(translateProcessToLocationProvider(processingMethod));
-
double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES);
Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP);
+ if (areValuesAllNull(processingMethod, coords, timeStamp)) {
+ return null;
+ }
+
+ Location l = new Location(translateProcessToLocationProvider(processingMethod));
if (timeStamp != null) {
l.setTime(timeStamp);
} else {
@@ -873,7 +887,13 @@ public class CameraMetadataNative implements Parcelable {
float[] red = getBase(CaptureRequest.TONEMAP_CURVE_RED);
float[] green = getBase(CaptureRequest.TONEMAP_CURVE_GREEN);
float[] blue = getBase(CaptureRequest.TONEMAP_CURVE_BLUE);
+
+ if (areValuesAllNull(red, green, blue)) {
+ return null;
+ }
+
if (red == null || green == null || blue == null) {
+ Log.w(TAG, "getTonemapCurve - missing tone curve components");
return null;
}
TonemapCurve tc = new TonemapCurve(red, green, blue);
@@ -1208,6 +1228,18 @@ public class CameraMetadataNative implements Parcelable {
}
}
+ /** Check if input arguments are all {@code null}.
+ *
+ * @param objs Input arguments for null check
+ * @return {@code true} if input arguments are all {@code null}, otherwise {@code false}
+ */
+ private static boolean areValuesAllNull(Object... objs) {
+ for (Object o : objs) {
+ if (o != null) return false;
+ }
+ return true;
+ }
+
static {
/*
* We use a class initializer to allow the native code to cache some field offsets
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index ee0ca9c..a8d1018 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -882,6 +882,7 @@ public class LegacyMetadataMapper {
Parameters.SCENE_MODE_PARTY,
Parameters.SCENE_MODE_CANDLELIGHT,
Parameters.SCENE_MODE_BARCODE,
+ Parameters.SCENE_MODE_HDR,
};
private final static int[] sSceneModes = {
@@ -901,6 +902,7 @@ public class LegacyMetadataMapper {
CameraCharacteristics.CONTROL_SCENE_MODE_PARTY,
CameraCharacteristics.CONTROL_SCENE_MODE_CANDLELIGHT,
CameraCharacteristics.CONTROL_SCENE_MODE_BARCODE,
+ CameraCharacteristics.CONTROL_SCENE_MODE_HDR,
};
static int convertSceneModeFromLegacy(String mode) {
diff --git a/core/java/android/net/NetworkBoundURLFactory.java b/core/java/android/net/NetworkBoundURLFactory.java
deleted file mode 100644
index 356100e..0000000
--- a/core/java/android/net/NetworkBoundURLFactory.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.net;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
-/**
- * An interface that describes a factory for network-specific {@link URL} objects.
- */
-public interface NetworkBoundURLFactory {
- /**
- * Returns a {@link URL} based on the given URL but bound to the specified {@code Network},
- * such that opening the URL will send all network traffic on the specified Network.
- *
- * @return a {@link URL} bound to this {@code Network}.
- * @throws MalformedURLException if the URL was not valid, or this factory cannot handle the
- * specified URL (e.g., if it does not support the protocol of the URL).
- */
- public URL getBoundURL(Network network, URL url) throws MalformedURLException;
-}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ae11f47..33e0468 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -904,6 +904,15 @@ public final class Settings {
public static final String ACTION_APP_NOTIFICATION_SETTINGS
= "android.settings.APP_NOTIFICATION_SETTINGS";
+ /**
+ * Activity Action: Show notification redaction settings.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_APP_NOTIFICATION_REDACTION
+ = "android.settings.ACTION_APP_NOTIFICATION_REDACTION";
+
/** @hide */ public static final String EXTRA_APP_UID = "app_uid";
/** @hide */ public static final String EXTRA_APP_PACKAGE = "app_package";
@@ -3714,6 +3723,14 @@ public final class Settings {
"lock_screen_allow_private_notifications";
/**
+ * Set by the system to track if the user needs to see the call to action for
+ * the lockscreen notification policy.
+ * @hide
+ */
+ public static final String SHOW_NOTE_ABOUT_NOTIFICATION_HIDING =
+ "show_note_about_notification_hiding";
+
+ /**
* The Logging ID (a unique 64-bit value) as a hex string.
* Used as a pseudonymous identifier for logging.
* @deprecated This identifier is poorly initialized and has
diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java
index f8bf45b..7e9aba0 100644
--- a/core/java/android/security/IKeystoreService.java
+++ b/core/java/android/security/IKeystoreService.java
@@ -478,6 +478,59 @@ public interface IKeystoreService extends IInterface {
}
return _result;
}
+
+ public int reset_uid(int uid) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ int _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(uid);
+ mRemote.transact(Stub.TRANSACTION_reset_uid, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
+ public int sync_uid(int srcUid, int dstUid) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ int _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(srcUid);
+ _data.writeInt(dstUid);
+ mRemote.transact(Stub.TRANSACTION_sync_uid, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
+ public int password_uid(String password, int uid) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ int _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeString(password);
+ _data.writeInt(uid);
+ mRemote.transact(Stub.TRANSACTION_password_uid, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
}
private static final String DESCRIPTOR = "android.security.keystore";
@@ -505,6 +558,9 @@ public interface IKeystoreService extends IInterface {
static final int TRANSACTION_duplicate = IBinder.FIRST_CALL_TRANSACTION + 20;
static final int TRANSACTION_is_hardware_backed = IBinder.FIRST_CALL_TRANSACTION + 21;
static final int TRANSACTION_clear_uid = IBinder.FIRST_CALL_TRANSACTION + 22;
+ static final int TRANSACTION_reset_uid = IBinder.FIRST_CALL_TRANSACTION + 23;
+ static final int TRANSACTION_sync_uid = IBinder.FIRST_CALL_TRANSACTION + 24;
+ static final int TRANSACTION_password_uid = IBinder.FIRST_CALL_TRANSACTION + 25;
/**
* Cast an IBinder object into an IKeystoreService interface, generating
@@ -597,4 +653,10 @@ public interface IKeystoreService extends IInterface {
public int is_hardware_backed(String string) throws RemoteException;
public int clear_uid(long uid) throws RemoteException;
+
+ public int reset_uid(int uid) throws RemoteException;
+
+ public int sync_uid(int sourceUid, int targetUid) throws RemoteException;
+
+ public int password_uid(String password, int uid) throws RemoteException;
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index a544b2d..cb0bcf2 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -81,6 +81,33 @@ public abstract class NotificationListenerService extends Service {
* This does not change the interruption filter, only the effects. **/
public static final int HINT_HOST_DISABLE_EFFECTS = 1;
+ /**
+ * The full trim of the StatusBarNotification including all its features.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int TRIM_FULL = 0;
+
+ /**
+ * A light trim of the StatusBarNotification excluding the following features:
+ *
+ * <ol>
+ * <li>{@link Notification#tickerView tickerView}</li>
+ * <li>{@link Notification#contentView contentView}</li>
+ * <li>{@link Notification#largeIcon largeIcon}</li>
+ * <li>{@link Notification#bigContentView bigContentView}</li>
+ * <li>{@link Notification#headsUpContentView headsUpContentView}</li>
+ * <li>{@link Notification#EXTRA_LARGE_ICON extras[EXTRA_LARGE_ICON]}</li>
+ * <li>{@link Notification#EXTRA_LARGE_ICON_BIG extras[EXTRA_LARGE_ICON_BIG]}</li>
+ * <li>{@link Notification#EXTRA_PICTURE extras[EXTRA_PICTURE]}</li>
+ * </ol>
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int TRIM_LIGHT = 1;
+
private INotificationListenerWrapper mWrapper = null;
private RankingMap mRankingMap;
@@ -314,13 +341,53 @@ public abstract class NotificationListenerService extends Service {
}
/**
+ * Sets the notification trim that will be received via {@link #onNotificationPosted}.
+ *
+ * <p>
+ * Setting a trim other than {@link #TRIM_FULL} enables listeners that don't need access to the
+ * full notification features right away to reduce their memory footprint. Full notifications
+ * can be requested on-demand via {@link #getActiveNotifications(int)}.
+ *
+ * <p>
+ * Set to {@link #TRIM_FULL} initially.
+ *
+ * @hide
+ *
+ * @param trim trim of the notifications to be passed via {@link #onNotificationPosted}.
+ * See <code>TRIM_*</code> constants.
+ */
+ @SystemApi
+ public final void setOnNotificationPostedTrim(int trim) {
+ if (!isBound()) return;
+ try {
+ getNotificationInterface().setOnNotificationPostedTrimFromListener(mWrapper, trim);
+ } catch (RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ }
+
+ /**
* Request the list of outstanding notifications (that is, those that are visible to the
* current user). Useful when you don't know what's already been posted.
*
* @return An array of active notifications, sorted in natural order.
*/
public StatusBarNotification[] getActiveNotifications() {
- return getActiveNotifications(null);
+ return getActiveNotifications(null, TRIM_FULL);
+ }
+
+ /**
+ * Request the list of outstanding notifications (that is, those that are visible to the
+ * current user). Useful when you don't know what's already been posted.
+ *
+ * @hide
+ *
+ * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants.
+ * @return An array of active notifications, sorted in natural order.
+ */
+ @SystemApi
+ public StatusBarNotification[] getActiveNotifications(int trim) {
+ return getActiveNotifications(null, trim);
}
/**
@@ -328,14 +395,33 @@ public abstract class NotificationListenerService extends Service {
* notifications but didn't want to retain the bits, and now need to go back and extract
* more data out of those notifications.
*
+ * @param keys the keys of the notifications to request
* @return An array of notifications corresponding to the requested keys, in the
* same order as the key list.
*/
public StatusBarNotification[] getActiveNotifications(String[] keys) {
- if (!isBound()) return null;
+ return getActiveNotifications(keys, TRIM_FULL);
+ }
+
+ /**
+ * Request one or more notifications by key. Useful if you have been keeping track of
+ * notifications but didn't want to retain the bits, and now need to go back and extract
+ * more data out of those notifications.
+ *
+ * @hide
+ *
+ * @param keys the keys of the notifications to request
+ * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants.
+ * @return An array of notifications corresponding to the requested keys, in the
+ * same order as the key list.
+ */
+ @SystemApi
+ public StatusBarNotification[] getActiveNotifications(String[] keys, int trim) {
+ if (!isBound())
+ return null;
try {
- ParceledListSlice<StatusBarNotification> parceledList =
- getNotificationInterface().getActiveNotificationsFromListener(mWrapper, keys);
+ ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface()
+ .getActiveNotificationsFromListener(mWrapper, keys, trim);
List<StatusBarNotification> list = parceledList.getList();
int N = list.size();
diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java
index ebb1a5c..eb17429 100644
--- a/core/java/android/transition/ChangeBounds.java
+++ b/core/java/android/transition/ChangeBounds.java
@@ -31,6 +31,7 @@ import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.util.IntProperty;
import android.util.Property;
import android.view.View;
import android.view.ViewGroup;
@@ -185,25 +186,36 @@ public class ChangeBounds extends Transition {
}
if (numChanges > 0) {
if (!mResizeClip) {
- if (startLeft != endLeft) view.setLeft(startLeft);
- if (startTop != endTop) view.setTop(startTop);
- if (startRight != endRight) view.setRight(startRight);
- if (startBottom != endBottom) view.setBottom(startBottom);
- ObjectAnimator topLeftAnimator = null;
- if (startLeft != endLeft || startTop != endTop) {
- Path topLeftPath = getPathMotion().getPath(startLeft, startTop,
- endLeft, endTop);
- topLeftAnimator = ObjectAnimator.ofInt(view, "left", "top", topLeftPath);
- }
- ObjectAnimator bottomRightAnimator = null;
- if (startRight != endRight || startBottom != endBottom) {
- Path bottomRightPath = getPathMotion().getPath(startRight, startBottom,
- endRight, endBottom);
- bottomRightAnimator = ObjectAnimator.ofInt(view, "right", "bottom",
- bottomRightPath);
+ Animator anim;
+ if (startWidth == endWidth && startHeight == endHeight) {
+ view.offsetLeftAndRight(startLeft - view.getLeft());
+ view.offsetTopAndBottom(startTop - view.getTop());
+ Path positionPath = getPathMotion().getPath(0, 0, endLeft - startLeft,
+ endTop - startTop);
+ anim = ObjectAnimator.ofInt(view, new HorizontalOffsetProperty(),
+ new VerticalOffsetProperty(), positionPath);
+ } else {
+ if (startLeft != endLeft) view.setLeft(startLeft);
+ if (startTop != endTop) view.setTop(startTop);
+ if (startRight != endRight) view.setRight(startRight);
+ if (startBottom != endBottom) view.setBottom(startBottom);
+ ObjectAnimator topLeftAnimator = null;
+ if (startLeft != endLeft || startTop != endTop) {
+ Path topLeftPath = getPathMotion().getPath(startLeft, startTop,
+ endLeft, endTop);
+ topLeftAnimator = ObjectAnimator
+ .ofInt(view, "left", "top", topLeftPath);
+ }
+ ObjectAnimator bottomRightAnimator = null;
+ if (startRight != endRight || startBottom != endBottom) {
+ Path bottomRightPath = getPathMotion().getPath(startRight, startBottom,
+ endRight, endBottom);
+ bottomRightAnimator = ObjectAnimator.ofInt(view, "right", "bottom",
+ bottomRightPath);
+ }
+ anim = TransitionUtils.mergeAnimators(topLeftAnimator,
+ bottomRightAnimator);
}
- Animator anim = TransitionUtils.mergeAnimators(topLeftAnimator,
- bottomRightAnimator);
if (view.getParent() instanceof ViewGroup) {
final ViewGroup parent = (ViewGroup) view.getParent();
parent.suppressLayout(true);
@@ -341,4 +353,48 @@ public class ChangeBounds extends Transition {
}
return null;
}
+
+ private abstract static class OffsetProperty extends IntProperty<View> {
+ int mPreviousValue;
+
+ public OffsetProperty(String name) {
+ super(name);
+ }
+
+ @Override
+ public void setValue(View view, int value) {
+ int offset = value - mPreviousValue;
+ offsetBy(view, offset);
+ mPreviousValue = value;
+ }
+
+ @Override
+ public Integer get(View object) {
+ return null;
+ }
+
+ protected abstract void offsetBy(View view, int by);
+ }
+
+ private static class HorizontalOffsetProperty extends OffsetProperty {
+ public HorizontalOffsetProperty() {
+ super("offsetLeftAndRight");
+ }
+
+ @Override
+ protected void offsetBy(View view, int by) {
+ view.offsetLeftAndRight(by);
+ }
+ }
+
+ private static class VerticalOffsetProperty extends OffsetProperty {
+ public VerticalOffsetProperty() {
+ super("offsetTopAndBottom");
+ }
+
+ @Override
+ protected void offsetBy(View view, int by) {
+ view.offsetTopAndBottom(by);
+ }
+ }
}
diff --git a/core/java/android/util/Spline.java b/core/java/android/util/Spline.java
index ed027eb..41a2e5d 100644
--- a/core/java/android/util/Spline.java
+++ b/core/java/android/util/Spline.java
@@ -20,15 +20,34 @@ package android.util;
* Performs spline interpolation given a set of control points.
* @hide
*/
-public final class Spline {
- private final float[] mX;
- private final float[] mY;
- private final float[] mM;
-
- private Spline(float[] x, float[] y, float[] m) {
- mX = x;
- mY = y;
- mM = m;
+public abstract class Spline {
+
+ /**
+ * Interpolates the value of Y = f(X) for given X.
+ * Clamps X to the domain of the spline.
+ *
+ * @param x The X value.
+ * @return The interpolated Y = f(X) value.
+ */
+ public abstract float interpolate(float x);
+
+ /**
+ * Creates an appropriate spline based on the properties of the control points.
+ *
+ * If the control points are monotonic then the resulting spline will preserve that and
+ * otherwise optimize for error bounds.
+ */
+ public static Spline createSpline(float[] x, float[] y) {
+ if (!isStrictlyIncreasing(x)) {
+ throw new IllegalArgumentException("The control points must all have strictly "
+ + "increasing X values.");
+ }
+
+ if (isMonotonic(y)) {
+ return createMonotoneCubicSpline(x, y);
+ } else {
+ return createLinearSpline(x, y);
+ }
}
/**
@@ -50,107 +69,229 @@ public final class Spline {
* @throws IllegalArgumentException if the control points are not monotonic.
*/
public static Spline createMonotoneCubicSpline(float[] x, float[] y) {
- if (x == null || y == null || x.length != y.length || x.length < 2) {
- throw new IllegalArgumentException("There must be at least two control "
- + "points and the arrays must be of equal length.");
- }
+ return new MonotoneCubicSpline(x, y);
+ }
- final int n = x.length;
- float[] d = new float[n - 1]; // could optimize this out
- float[] m = new float[n];
+ /**
+ * Creates a linear spline from a given set of control points.
+ *
+ * Like a monotone cubic spline, the interpolated curve will be monotonic if the control points
+ * are monotonic.
+ *
+ * @param x The X component of the control points, strictly increasing.
+ * @param y The Y component of the control points.
+ * @return
+ *
+ * @throws IllegalArgumentException if the X or Y arrays are null, have
+ * different lengths or have fewer than 2 values.
+ * @throws IllegalArgumentException if the X components of the control points are not strictly
+ * increasing.
+ */
+ public static Spline createLinearSpline(float[] x, float[] y) {
+ return new LinearSpline(x, y);
+ }
- // Compute slopes of secant lines between successive points.
- for (int i = 0; i < n - 1; i++) {
- float h = x[i + 1] - x[i];
- if (h <= 0f) {
- throw new IllegalArgumentException("The control points must all "
- + "have strictly increasing X values.");
+ private static boolean isStrictlyIncreasing(float[] x) {
+ if (x == null || x.length < 2) {
+ throw new IllegalArgumentException("There must be at least two control points.");
+ }
+ float prev = x[0];
+ for (int i = 1; i < x.length; i++) {
+ float curr = x[i];
+ if (curr <= prev) {
+ return false;
}
- d[i] = (y[i + 1] - y[i]) / h;
+ prev = curr;
}
+ return true;
+ }
- // Initialize the tangents as the average of the secants.
- m[0] = d[0];
- for (int i = 1; i < n - 1; i++) {
- m[i] = (d[i - 1] + d[i]) * 0.5f;
+ private static boolean isMonotonic(float[] x) {
+ if (x == null || x.length < 2) {
+ throw new IllegalArgumentException("There must be at least two control points.");
}
- m[n - 1] = d[n - 2];
-
- // Update the tangents to preserve monotonicity.
- for (int i = 0; i < n - 1; i++) {
- if (d[i] == 0f) { // successive Y values are equal
- m[i] = 0f;
- m[i + 1] = 0f;
- } else {
- float a = m[i] / d[i];
- float b = m[i + 1] / d[i];
- if (a < 0f || b < 0f) {
- throw new IllegalArgumentException("The control points must have "
- + "monotonic Y values.");
- }
- float h = FloatMath.hypot(a, b);
- if (h > 9f) {
- float t = 3f / h;
- m[i] = t * a * d[i];
- m[i + 1] = t * b * d[i];
- }
+ float prev = x[0];
+ for (int i = 1; i < x.length; i++) {
+ float curr = x[i];
+ if (curr < prev) {
+ return false;
}
+ prev = curr;
}
- return new Spline(x, y, m);
+ return true;
}
- /**
- * Interpolates the value of Y = f(X) for given X.
- * Clamps X to the domain of the spline.
- *
- * @param x The X value.
- * @return The interpolated Y = f(X) value.
- */
- public float interpolate(float x) {
- // Handle the boundary cases.
- final int n = mX.length;
- if (Float.isNaN(x)) {
- return x;
+ public static class MonotoneCubicSpline extends Spline {
+ private float[] mX;
+ private float[] mY;
+ private float[] mM;
+
+ public MonotoneCubicSpline(float[] x, float[] y) {
+ if (x == null || y == null || x.length != y.length || x.length < 2) {
+ throw new IllegalArgumentException("There must be at least two control "
+ + "points and the arrays must be of equal length.");
+ }
+
+ final int n = x.length;
+ float[] d = new float[n - 1]; // could optimize this out
+ float[] m = new float[n];
+
+ // Compute slopes of secant lines between successive points.
+ for (int i = 0; i < n - 1; i++) {
+ float h = x[i + 1] - x[i];
+ if (h <= 0f) {
+ throw new IllegalArgumentException("The control points must all "
+ + "have strictly increasing X values.");
+ }
+ d[i] = (y[i + 1] - y[i]) / h;
+ }
+
+ // Initialize the tangents as the average of the secants.
+ m[0] = d[0];
+ for (int i = 1; i < n - 1; i++) {
+ m[i] = (d[i - 1] + d[i]) * 0.5f;
+ }
+ m[n - 1] = d[n - 2];
+
+ // Update the tangents to preserve monotonicity.
+ for (int i = 0; i < n - 1; i++) {
+ if (d[i] == 0f) { // successive Y values are equal
+ m[i] = 0f;
+ m[i + 1] = 0f;
+ } else {
+ float a = m[i] / d[i];
+ float b = m[i + 1] / d[i];
+ if (a < 0f || b < 0f) {
+ throw new IllegalArgumentException("The control points must have "
+ + "monotonic Y values.");
+ }
+ float h = FloatMath.hypot(a, b);
+ if (h > 9f) {
+ float t = 3f / h;
+ m[i] = t * a * d[i];
+ m[i + 1] = t * b * d[i];
+ }
+ }
+ }
+
+ mX = x;
+ mY = y;
+ mM = m;
}
- if (x <= mX[0]) {
- return mY[0];
+
+ @Override
+ public float interpolate(float x) {
+ // Handle the boundary cases.
+ final int n = mX.length;
+ if (Float.isNaN(x)) {
+ return x;
+ }
+ if (x <= mX[0]) {
+ return mY[0];
+ }
+ if (x >= mX[n - 1]) {
+ return mY[n - 1];
+ }
+
+ // Find the index 'i' of the last point with smaller X.
+ // We know this will be within the spline due to the boundary tests.
+ int i = 0;
+ while (x >= mX[i + 1]) {
+ i += 1;
+ if (x == mX[i]) {
+ return mY[i];
+ }
+ }
+
+ // Perform cubic Hermite spline interpolation.
+ float h = mX[i + 1] - mX[i];
+ float t = (x - mX[i]) / h;
+ return (mY[i] * (1 + 2 * t) + h * mM[i] * t) * (1 - t) * (1 - t)
+ + (mY[i + 1] * (3 - 2 * t) + h * mM[i + 1] * (t - 1)) * t * t;
}
- if (x >= mX[n - 1]) {
- return mY[n - 1];
+
+ // For debugging.
+ @Override
+ public String toString() {
+ StringBuilder str = new StringBuilder();
+ final int n = mX.length;
+ str.append("MonotoneCubicSpline{[");
+ for (int i = 0; i < n; i++) {
+ if (i != 0) {
+ str.append(", ");
+ }
+ str.append("(").append(mX[i]);
+ str.append(", ").append(mY[i]);
+ str.append(": ").append(mM[i]).append(")");
+ }
+ str.append("]}");
+ return str.toString();
}
+ }
- // Find the index 'i' of the last point with smaller X.
- // We know this will be within the spline due to the boundary tests.
- int i = 0;
- while (x >= mX[i + 1]) {
- i += 1;
- if (x == mX[i]) {
- return mY[i];
+ public static class LinearSpline extends Spline {
+ private final float[] mX;
+ private final float[] mY;
+ private final float[] mM;
+
+ public LinearSpline(float[] x, float[] y) {
+ if (x == null || y == null || x.length != y.length || x.length < 2) {
+ throw new IllegalArgumentException("There must be at least two control "
+ + "points and the arrays must be of equal length.");
+ }
+ final int N = x.length;
+ mM = new float[N-1];
+ for (int i = 0; i < N-1; i++) {
+ mM[i] = (y[i+1] - y[i]) / (x[i+1] - x[i]);
}
+ mX = x;
+ mY = y;
}
- // Perform cubic Hermite spline interpolation.
- float h = mX[i + 1] - mX[i];
- float t = (x - mX[i]) / h;
- return (mY[i] * (1 + 2 * t) + h * mM[i] * t) * (1 - t) * (1 - t)
- + (mY[i + 1] * (3 - 2 * t) + h * mM[i + 1] * (t - 1)) * t * t;
- }
+ @Override
+ public float interpolate(float x) {
+ // Handle the boundary cases.
+ final int n = mX.length;
+ if (Float.isNaN(x)) {
+ return x;
+ }
+ if (x <= mX[0]) {
+ return mY[0];
+ }
+ if (x >= mX[n - 1]) {
+ return mY[n - 1];
+ }
- // For debugging.
- @Override
- public String toString() {
- StringBuilder str = new StringBuilder();
- final int n = mX.length;
- str.append("[");
- for (int i = 0; i < n; i++) {
- if (i != 0) {
- str.append(", ");
- }
- str.append("(").append(mX[i]);
- str.append(", ").append(mY[i]);
- str.append(": ").append(mM[i]).append(")");
+ // Find the index 'i' of the last point with smaller X.
+ // We know this will be within the spline due to the boundary tests.
+ int i = 0;
+ while (x >= mX[i + 1]) {
+ i += 1;
+ if (x == mX[i]) {
+ return mY[i];
+ }
+ }
+ return mY[i] + mM[i] * (x - mX[i]);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder str = new StringBuilder();
+ final int n = mX.length;
+ str.append("LinearSpline{[");
+ for (int i = 0; i < n; i++) {
+ if (i != 0) {
+ str.append(", ");
+ }
+ str.append("(").append(mX[i]);
+ str.append(", ").append(mY[i]);
+ if (i < n-1) {
+ str.append(": ").append(mM[i]);
+ }
+ str.append(")");
+ }
+ str.append("]}");
+ return str.toString();
}
- str.append("]");
- return str.toString();
}
}
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 413ea04..fa4a13a 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -87,8 +87,11 @@ public class RenderNodeAnimator extends Animator {
private float mFinalValue;
private TimeInterpolator mInterpolator;
- private boolean mStarted = false;
- private boolean mFinished = false;
+ private static final int STATE_PREPARE = 0;
+ private static final int STATE_DELAYED = 1;
+ private static final int STATE_RUNNING = 2;
+ private static final int STATE_FINISHED = 3;
+ private int mState = STATE_PREPARE;
private long mUnscaledDuration = 300;
private long mUnscaledStartDelay = 0;
@@ -142,7 +145,7 @@ public class RenderNodeAnimator extends Animator {
}
private void checkMutable() {
- if (mStarted) {
+ if (mState != STATE_PREPARE) {
throw new IllegalStateException("Animator has already started, cannot change it now!");
}
}
@@ -170,11 +173,11 @@ public class RenderNodeAnimator extends Animator {
throw new IllegalStateException("Missing target!");
}
- if (mStarted) {
+ if (mState != STATE_PREPARE) {
throw new IllegalStateException("Already started!");
}
- mStarted = true;
+ mState = STATE_DELAYED;
applyInterpolator();
if (mStartDelay <= 0 || !mUiThreadHandlesDelay) {
@@ -186,6 +189,7 @@ public class RenderNodeAnimator extends Animator {
}
private void doStart() {
+ mState = STATE_RUNNING;
nStart(mNativePtr.get(), this);
// Alpha is a special snowflake that has the canonical value stored
@@ -197,11 +201,7 @@ public class RenderNodeAnimator extends Animator {
mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
}
- final ArrayList<AnimatorListener> listeners = cloneListeners();
- final int numListeners = listeners == null ? 0 : listeners.size();
- for (int i = 0; i < numListeners; i++) {
- listeners.get(i).onAnimationStart(this);
- }
+ notifyStartListeners();
if (mViewTarget != null) {
// Kick off a frame to start the process
@@ -209,10 +209,21 @@ public class RenderNodeAnimator extends Animator {
}
}
+ private void notifyStartListeners() {
+ final ArrayList<AnimatorListener> listeners = cloneListeners();
+ final int numListeners = listeners == null ? 0 : listeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ listeners.get(i).onAnimationStart(this);
+ }
+ }
+
@Override
public void cancel() {
- if (!mFinished) {
- getHelper().removeDelayedAnimation(this);
+ if (mState != STATE_FINISHED) {
+ if (mState == STATE_DELAYED) {
+ getHelper().removeDelayedAnimation(this);
+ notifyStartListeners();
+ }
nEnd(mNativePtr.get());
final ArrayList<AnimatorListener> listeners = cloneListeners();
@@ -220,12 +231,17 @@ public class RenderNodeAnimator extends Animator {
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationCancel(this);
}
+
+ if (mViewTarget != null) {
+ // Kick off a frame to flush the state change
+ mViewTarget.invalidateViewProperty(true, false);
+ }
}
}
@Override
public void end() {
- if (!mFinished) {
+ if (mState != STATE_FINISHED) {
nEnd(mNativePtr.get());
}
}
@@ -299,12 +315,12 @@ public class RenderNodeAnimator extends Animator {
@Override
public boolean isRunning() {
- return mStarted && !mFinished;
+ return mState == STATE_DELAYED || mState == STATE_RUNNING;
}
@Override
public boolean isStarted() {
- return mStarted;
+ return mState != STATE_PREPARE;
}
@Override
@@ -319,7 +335,11 @@ public class RenderNodeAnimator extends Animator {
}
protected void onFinished() {
- mFinished = true;
+ if (mState == STATE_DELAYED) {
+ getHelper().removeDelayedAnimation(this);
+ notifyStartListeners();
+ }
+ mState = STATE_FINISHED;
final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 61b4567..b6e7353 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -23,7 +23,6 @@ import android.app.usage.UsageStatsManager;
import android.os.AsyncTask;
import android.provider.Settings;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.Slog;
import android.widget.AbsListView;
import android.widget.GridView;
@@ -73,6 +72,7 @@ import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -100,7 +100,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
private boolean mResolvingHome = false;
private UsageStatsManager mUsm;
- private ArrayMap<String, UsageStats> mStats;
+ private Map<String, UsageStats> mStats;
private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
private boolean mRegistered;
diff --git a/core/res/res/color/btn_default_material_dark.xml b/core/res/res/color/btn_default_material_dark.xml
index 7c904cd..9be1417 100644
--- a/core/res/res/color/btn_default_material_dark.xml
+++ b/core/res/res/color/btn_default_material_dark.xml
@@ -16,7 +16,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
- android:alpha="@dimen/disabled_alpha_material"
- android:color="@color/button_material_dark"/>
+ android:alpha="@dimen/disabled_alpha_material_dark"
+ android:color="@color/button_material_dark"/>
<item android:color="@color/button_material_dark"/>
</selector>
diff --git a/core/res/res/color/btn_default_material_light.xml b/core/res/res/color/btn_default_material_light.xml
index 738f9ad..af5afe6 100644
--- a/core/res/res/color/btn_default_material_light.xml
+++ b/core/res/res/color/btn_default_material_light.xml
@@ -16,7 +16,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
- android:alpha="@dimen/disabled_alpha_material"
- android:color="@color/button_material_light"/>
+ android:alpha="@dimen/disabled_alpha_material_light"
+ android:color="@color/button_material_light"/>
<item android:color="@color/button_material_light"/>
</selector>
diff --git a/core/res/res/color/primary_text_disable_only_material_dark.xml b/core/res/res/color/primary_text_disable_only_material_dark.xml
index cdae790..a6296c9 100644
--- a/core/res/res/color/primary_text_disable_only_material_dark.xml
+++ b/core/res/res/color/primary_text_disable_only_material_dark.xml
@@ -16,7 +16,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
- android:alpha="@dimen/disabled_alpha_material"
- android:color="@color/bright_foreground_material_dark"/>
+ android:alpha="@dimen/disabled_alpha_material_dark"
+ android:color="@color/bright_foreground_material_dark"/>
<item android:color="@color/bright_foreground_material_dark"/>
</selector>
diff --git a/core/res/res/color/primary_text_disable_only_material_light.xml b/core/res/res/color/primary_text_disable_only_material_light.xml
index 0bf14d0..b781844 100644
--- a/core/res/res/color/primary_text_disable_only_material_light.xml
+++ b/core/res/res/color/primary_text_disable_only_material_light.xml
@@ -16,7 +16,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
- android:alpha="@dimen/disabled_alpha_material"
- android:color="@color/bright_foreground_material_light"/>
+ android:alpha="@dimen/disabled_alpha_material_light"
+ android:color="@color/bright_foreground_material_light"/>
<item android:color="@color/bright_foreground_material_light"/>
</selector>
diff --git a/core/res/res/color/primary_text_material_dark.xml b/core/res/res/color/primary_text_material_dark.xml
index 6ad837b..690f0ec 100644
--- a/core/res/res/color/primary_text_material_dark.xml
+++ b/core/res/res/color/primary_text_material_dark.xml
@@ -16,7 +16,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
- android:alpha="@dimen/disabled_alpha_material"
- android:color="@color/primary_text_default_material_dark"/>
+ android:alpha="@dimen/disabled_alpha_material_dark"
+ android:color="@color/primary_text_default_material_dark"/>
<item android:color="@color/primary_text_default_material_dark"/>
</selector>
diff --git a/core/res/res/color/primary_text_material_light.xml b/core/res/res/color/primary_text_material_light.xml
index 4c19e12..634ad94 100644
--- a/core/res/res/color/primary_text_material_light.xml
+++ b/core/res/res/color/primary_text_material_light.xml
@@ -16,7 +16,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
- android:alpha="@dimen/disabled_alpha_material"
- android:color="@color/primary_text_default_material_light"/>
+ android:alpha="@dimen/disabled_alpha_material_light"
+ android:color="@color/primary_text_default_material_light"/>
<item android:color="@color/primary_text_default_material_light"/>
</selector>
diff --git a/core/res/res/color/secondary_text_material_dark.xml b/core/res/res/color/secondary_text_material_dark.xml
new file mode 100644
index 0000000..5bddf96
--- /dev/null
+++ b/core/res/res/color/secondary_text_material_dark.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:alpha="@dimen/disabled_alpha_material_dark"
+ android:color="@color/secondary_text_default_material_dark"/>
+ <item android:color="@color/secondary_text_default_material_dark"/>
+</selector>
diff --git a/core/res/res/color/secondary_text_material_light.xml b/core/res/res/color/secondary_text_material_light.xml
new file mode 100644
index 0000000..3c354cb
--- /dev/null
+++ b/core/res/res/color/secondary_text_material_light.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:alpha="@dimen/disabled_alpha_material_light"
+ android:color="@color/secondary_text_default_material_light"/>
+ <item android:color="@color/secondary_text_default_material_light"/>
+</selector>
diff --git a/core/res/res/drawable/progress_horizontal_material.xml b/core/res/res/drawable/progress_horizontal_material.xml
index 7a1079c..6b64337 100644
--- a/core/res/res/drawable/progress_horizontal_material.xml
+++ b/core/res/res/drawable/progress_horizontal_material.xml
@@ -18,13 +18,13 @@
<item android:id="@id/background">
<nine-patch android:src="@drawable/progress_mtrl_alpha"
android:tint="?attr/colorControlNormal"
- android:alpha="0.5" />
+ android:alpha="?attr/disabledAlpha" />
</item>
<item android:id="@id/secondaryProgress">
<scale android:scaleWidth="100%">
<nine-patch android:src="@drawable/progress_mtrl_alpha"
android:tint="?attr/colorControlActivated"
- android:alpha="0.5" />
+ android:alpha="?attr/disabledAlpha" />
</scale>
</item>
<item android:id="@id/progress">
diff --git a/core/res/res/layout/action_menu_item_layout.xml b/core/res/res/layout/action_menu_item_layout.xml
index 04d1f7b..6961f8d 100644
--- a/core/res/res/layout/action_menu_item_layout.xml
+++ b/core/res/res/layout/action_menu_item_layout.xml
@@ -25,5 +25,4 @@
android:paddingStart="8dip"
android:paddingEnd="8dip"
android:textAppearance="?attr/actionMenuTextAppearance"
- android:textColor="?attr/actionMenuTextColor"
- style="?android:attr/actionButtonStyle" />
+ style="?attr/actionButtonStyle" />
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index c9292eb..d8e14a0 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -58,19 +58,14 @@
<!-- Text & foreground colors -->
<eat-comment />
- <!-- Black 87% -->
<color name="primary_text_default_material_light">#de000000</color>
- <!-- Black 54% -->
- <color name="secondary_text_material_light">#8a000000</color>
- <!-- Black 54% (TODO: same as secondary?) -->
- <color name="tertiary_text_material_light">#8a000000</color>
-
- <!-- White 87% -->
- <color name="primary_text_default_material_dark">#deffffff</color>
- <!-- White 38% -->
- <color name="secondary_text_material_dark">#61ffffff</color>
- <!-- White 38% (TODO: same as secondary?) -->
- <color name="tertiary_text_material_dark">#61ffffff</color>
+ <color name="secondary_text_default_material_light">#8a000000</color>
+
+ <color name="primary_text_default_material_dark">#ffffffff</color>
+ <color name="secondary_text_default_material_dark">#b3ffffff</color>
+
+ <item name="disabled_alpha_material_light" format="float" type="dimen">0.26</item>
+ <item name="disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
<!-- Primary & accent colors -->
<eat-comment />
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index f5c9299..5f7f0ed 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -77,8 +77,5 @@
<!-- Default rounded corner for controls -->
<dimen name="control_corner_material">2dp</dimen>
- <!-- Default alpha value for disabled elements. -->
- <item name="disabled_alpha_material" format="float" type="dimen">0.26</item>
-
- <dimen name="alert_dialog_padding_material">12dp</dimen>
+ <dimen name="alert_dialog_padding_material">18dp</dimen>
</resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 4c59f73..bd24f3e 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -87,4 +87,6 @@
<item type="id" name="transitionPosition" />
<item type="id" name="transitionTransform" />
<item type="id" name="parentMatrix" />
+ <item type="id" name="statusBarBackground" />
+ <item type="id" name="navigationBarBackground" />
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d452739..5e76a87 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2288,6 +2288,8 @@
<public-padding type="id" name="l_resource_pad" end="0x01020040" />
<public type="id" name="mask" />
+ <public type="id" name="statusBarBackground" />
+ <public type="id" name="navigationBarBackground" />
<public-padding type="style" name="l_resource_pad" end="0x01030200" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 89fac13..2296a12 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -46,7 +46,7 @@ please see themes_device_defaults.xml.
<item name="colorForegroundInverse">@color/bright_foreground_material_light</item>
<item name="colorBackground">@color/background_material_dark</item>
<item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
- <item name="disabledAlpha">@dimen/disabled_alpha_material</item>
+ <item name="disabledAlpha">@dimen/disabled_alpha_material_dark</item>
<item name="backgroundDimAmount">0.6</item>
<!-- Text styles -->
@@ -58,8 +58,8 @@ please see themes_device_defaults.xml.
<item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_dark</item>
<item name="textColorSecondary">@color/secondary_text_material_dark</item>
<item name="textColorSecondaryInverse">@color/secondary_text_material_light</item>
- <item name="textColorTertiary">@color/tertiary_text_material_dark</item>
- <item name="textColorTertiaryInverse">@color/tertiary_text_material_light</item>
+ <item name="textColorTertiary">@color/secondary_text_material_dark</item>
+ <item name="textColorTertiaryInverse">@color/secondary_text_material_light</item>
<item name="textColorHint">@color/hint_foreground_material_dark</item>
<item name="textColorHintInverse">@color/hint_foreground_material_light</item>
<item name="textColorHighlight">@color/highlighted_text_material_dark</item>
@@ -387,7 +387,7 @@ please see themes_device_defaults.xml.
<item name="colorForegroundInverse">@color/bright_foreground_material_dark</item>
<item name="colorBackground">@color/background_material_light</item>
<item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
- <item name="disabledAlpha">@dimen/disabled_alpha_material</item>
+ <item name="disabledAlpha">@dimen/disabled_alpha_material_light</item>
<item name="backgroundDimAmount">0.6</item>
<!-- Text styles -->
@@ -398,8 +398,8 @@ please see themes_device_defaults.xml.
<item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
<item name="textColorSecondary">@color/secondary_text_material_light</item>
<item name="textColorSecondaryInverse">@color/secondary_text_material_dark</item>
- <item name="textColorTertiary">@color/tertiary_text_material_light</item>
- <item name="textColorTertiaryInverse">@color/tertiary_text_material_dark</item>
+ <item name="textColorTertiary">@color/secondary_text_material_light</item>
+ <item name="textColorTertiaryInverse">@color/secondary_text_material_dark</item>
<item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_light</item>
<item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_material_dark</item>
<item name="textColorHint">@color/hint_foreground_material_light</item>
@@ -750,8 +750,8 @@ please see themes_device_defaults.xml.
<item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
<item name="textColorSecondary">@color/secondary_text_material_light</item>
<item name="textColorSecondaryInverse">@color/secondary_text_material_dark</item>
- <item name="textColorTertiary">@color/tertiary_text_material_light</item>
- <item name="textColorTertiaryInverse">@color/tertiary_text_material_dark</item>
+ <item name="textColorTertiary">@color/secondary_text_material_light</item>
+ <item name="textColorTertiaryInverse">@color/secondary_text_material_dark</item>
<item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_light</item>
<item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_material_dark</item>
<item name="textColorHint">@color/hint_foreground_material_light</item>
@@ -790,8 +790,8 @@ please see themes_device_defaults.xml.
<item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_dark</item>
<item name="textColorSecondary">@color/secondary_text_material_dark</item>
<item name="textColorSecondaryInverse">@color/secondary_text_material_light</item>
- <item name="textColorTertiary">@color/tertiary_text_material_dark</item>
- <item name="textColorTertiaryInverse">@color/tertiary_text_material_light</item>
+ <item name="textColorTertiary">@color/secondary_text_material_dark</item>
+ <item name="textColorTertiaryInverse">@color/secondary_text_material_light</item>
<item name="textColorHint">@color/hint_foreground_material_dark</item>
<item name="textColorHintInverse">@color/hint_foreground_material_light</item>
<item name="textColorHighlight">@color/highlighted_text_material_dark</item>
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
index ee6b814..bed4b4d 100644
--- a/docs/html/guide/topics/admin/device-admin.jd
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -28,12 +28,6 @@ page.tags=devicepolicymanager,policy,security
<li>{@link android.app.admin.DevicePolicyManager}</li>
<li>{@link android.app.admin.DeviceAdminInfo}</li>
</ol>
- <h2>Related samples</h2>
- <ol>
- <li><a
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.html">
-DeviceAdminSample</a></li>
-</ol>
</div>
</div>
@@ -232,18 +226,12 @@ Administration API lets you do the following:</p> <ul>
<h2 id="sample">Sample Application</h2>
-<p>The examples used in this document are based on the <a
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.html">
-Device Administration API
-sample</a>, which is included in the SDK samples. For information on downloading and
-installing the SDK samples, see <a
-href="{@docRoot}resources/samples/get.html">
-Getting the Samples</a>. Here is the <a
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.html">
-complete code</a> for
-the sample. </p>
-<p>The
-sample application offers a demo of device admin features. It presents users
+<p>The examples used in this document are based on the Device Administration API
+sample, which is included in the SDK samples (available through the
+Android SDK Manager) and located on your system as
+<code>&lt;sdk_root&gt;/ApiDemos/app/src/main/java/com/example/android/apis/app/DeviceAdminSample.java</code>.</p>
+
+<p>The sample application offers a demo of device admin features. It presents users
with a user interface that lets them enable the device admin application. Once
they've enabled the application, they can use the buttons in the user interface
to do the following:</p>
@@ -676,7 +664,8 @@ mDPM.setMaximumTimeToLock(mDeviceAdminSample, timeMs);
<p>You can also programmatically tell the device to lock immediately:</p>
<pre>
DevicePolicyManager mDPM;
-mDPM.lockNow();</pre>
+mDPM.lockNow();
+</pre>
@@ -692,12 +681,12 @@ wiped after a specific number of failed password attempts.</p>
<pre>
DevicePolicyManager mDPM;
mDPM.wipeData(0);</pre>
-<p>The {@link android.app.admin.DevicePolicyManager#wipeData wipeData()} method takes as its parameter a bit mask of
-additional options. Currently the value must be 0. </p>
+<p>The {@link android.app.admin.DevicePolicyManager#wipeData wipeData()} method takes as its
+ parameter a bit mask of additional options. Currently the value must be 0. </p>
<h4>Disable camera</h4>
<p>Beginning with Android 4.0, you can disable the camera. Note that this doesn't have to be a permanent disabling. The camera can be enabled/disabled dynamically based on context, time, and so on. </p>
-<p>You control whether the camera is disabled by using the
+<p>You control whether the camera is disabled by using the
{@link android.app.admin.DevicePolicyManager#setCameraDisabled(android.content.ComponentName, boolean) setCameraDisabled()} method. For example, this snippet sets the camera to be enabled or disabled based on a checkbox setting:</p>
<pre>private CheckBoxPreference mDisableCameraCheckbox;
@@ -708,8 +697,8 @@ mDPM.setCameraDisabled(mDeviceAdminSample, mDisableCameraCheckbox.isChecked());<
</pre>
-<h4 id=storage">Storage encryption</h4>
-<p>Beginning with Android 3.0, you can use the
+<h4 id="storage">Storage encryption</h4>
+<p>Beginning with Android 3.0, you can use the
{@link android.app.admin.DevicePolicyManager#setStorageEncryption(android.content.ComponentName,boolean) setStorageEncryption()}
method to set a policy requiring encryption of the storage area, where supported.</p>
@@ -722,5 +711,5 @@ ComponentName mDeviceAdminSample;
mDPM.setStorageEncryption(mDeviceAdminSample, true);
</pre>
<p>
-See the <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.html"> Device Administration API sample</a> for a complete
-example of how to enable storage encryption.</p>
+See the Device Administration API sample for a complete example of how to enable storage encryption.
+</p> \ No newline at end of file
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 063ac09..cd919a6 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -105,6 +105,9 @@ class Ripple {
/** Whether we have an explicit maximum radius. */
private boolean mHasMaxRadius;
+ /** Whether we were canceled externally and should avoid self-removal. */
+ private boolean mCanceled;
+
/**
* Creates a new ripple.
*/
@@ -295,6 +298,8 @@ class Ripple {
* Starts the enter animation.
*/
public void enter() {
+ cancel();
+
final int radiusDuration = (int)
(1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
@@ -332,7 +337,8 @@ class Ripple {
* Starts the exit animation.
*/
public void exit() {
- cancelSoftwareAnimations();
+ cancel();
+
final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
final float remaining;
if (mAnimRadius != null && mAnimRadius.isRunning()) {
@@ -399,9 +405,15 @@ class Ripple {
invalidateSelf();
}
+ /**
+ * Jump all animations to their end state. The caller is responsible for
+ * removing the ripple from the list of animating ripples.
+ */
public void jump() {
+ mCanceled = true;
endSoftwareAnimations();
endHardwareAnimations();
+ mCanceled = false;
}
private void endSoftwareAnimations() {
@@ -436,6 +448,8 @@ class Ripple {
mPendingAnimations.clear();
removeSelf();
}
+
+ mHardwareAnimating = false;
}
private Paint getTempPaint() {
@@ -479,11 +493,14 @@ class Ripple {
}
/**
- * Cancel all animations.
+ * Cancels all animations. The caller is responsible for removing
+ * the ripple from the list of animating ripples.
*/
public void cancel() {
+ mCanceled = true;
cancelSoftwareAnimations();
cancelHardwareAnimations(true);
+ mCanceled = false;
}
private void cancelSoftwareAnimations() {
@@ -517,13 +534,16 @@ class Ripple {
if (cancelPending && !mPendingAnimations.isEmpty()) {
mPendingAnimations.clear();
- removeSelf();
}
+
+ mHardwareAnimating = false;
}
private void removeSelf() {
// The owner will invalidate itself.
- mOwner.removeRipple(this);
+ if (!mCanceled) {
+ mOwner.removeRipple(this);
+ }
}
private void invalidateSelf() {
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index 49862bc..40a5e18 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -42,8 +42,9 @@ class RippleBackground {
private static final float GLOBAL_SPEED = 1.0f;
private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024.0f * GLOBAL_SPEED;
private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED;
- private static final float WAVE_OUTER_OPACITY_VELOCITY_MAX = 4.5f * GLOBAL_SPEED;
- private static final float WAVE_OUTER_OPACITY_VELOCITY_MIN = 1.5f * GLOBAL_SPEED;
+ private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX = 4.5f * GLOBAL_SPEED;
+ private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN = 1.5f * GLOBAL_SPEED;
+ private static final float WAVE_OUTER_OPACITY_ENTER_VELOCITY = 10.0f * GLOBAL_SPEED;
private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f;
private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f;
@@ -106,6 +107,9 @@ class RippleBackground {
/** Whether we have an explicit maximum radius. */
private boolean mHasMaxRadius;
+ /** Whether we were canceled externally and should avoid self-removal. */
+ private boolean mCanceled;
+
/**
* Creates a new ripple.
*/
@@ -283,9 +287,11 @@ class RippleBackground {
* Starts the enter animation.
*/
public void enter() {
+ cancel();
+
final int radiusDuration = (int)
(1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
- final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY_MIN);
+ final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_ENTER_VELOCITY);
final ObjectAnimator cX = ObjectAnimator.ofFloat(this, "xGravity", 1);
cX.setAutoCancel(true);
@@ -320,7 +326,7 @@ class RippleBackground {
* Starts the exit animation.
*/
public void exit() {
- cancelSoftwareAnimations();
+ cancel();
// Scale the outer max opacity and opacity velocity based
// on the size of the outer radius.
@@ -328,8 +334,8 @@ class RippleBackground {
final float outerSizeInfluence = MathUtils.constrain(
(mOuterRadius - WAVE_OUTER_SIZE_INFLUENCE_MIN * mDensity)
/ (WAVE_OUTER_SIZE_INFLUENCE_MAX * mDensity), 0, 1);
- final float outerOpacityVelocity = MathUtils.lerp(WAVE_OUTER_OPACITY_VELOCITY_MIN,
- WAVE_OUTER_OPACITY_VELOCITY_MAX, outerSizeInfluence);
+ final float outerOpacityVelocity = MathUtils.lerp(WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN,
+ WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX, outerSizeInfluence);
// Determine at what time the inner and outer opacity intersect.
// inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000
@@ -403,9 +409,15 @@ class RippleBackground {
invalidateSelf();
}
+ /**
+ * Jump all animations to their end state. The caller is responsible for
+ * removing the ripple from the list of animating ripples.
+ */
public void jump() {
+ mCanceled = true;
endSoftwareAnimations();
endHardwareAnimations();
+ mCanceled = false;
}
private void endSoftwareAnimations() {
@@ -436,6 +448,8 @@ class RippleBackground {
mPendingAnimations.clear();
removeSelf();
}
+
+ mHardwareAnimating = false;
}
private Paint getTempPaint() {
@@ -508,11 +522,14 @@ class RippleBackground {
}
/**
- * Cancel all animations.
+ * Cancel all animations. The caller is responsible for removing
+ * the ripple from the list of animating ripples.
*/
public void cancel() {
+ mCanceled = true;
cancelSoftwareAnimations();
cancelHardwareAnimations(true);
+ mCanceled = false;
}
private void cancelSoftwareAnimations() {
@@ -543,13 +560,16 @@ class RippleBackground {
if (cancelPending && !mPendingAnimations.isEmpty()) {
mPendingAnimations.clear();
- removeSelf();
}
+
+ mHardwareAnimating = false;
}
private void removeSelf() {
// The owner will invalidate itself.
- mOwner.removeBackground(this);
+ if (!mCanceled) {
+ mOwner.removeBackground(this);
+ }
}
private void invalidateSelf() {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 7402bdb..b90fd81 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -140,8 +140,8 @@ public class RippleDrawable extends LayerDrawable {
* Lazily-created array of actively animating ripples. Inactive ripples are
* pruned during draw(). The locations of these will not change.
*/
- private Ripple[] mAnimatingRipples;
- private int mAnimatingRipplesCount = 0;
+ private Ripple[] mExitingRipples;
+ private int mExitingRipplesCount = 0;
/** Paint used to control appearance of ripples. */
private Paint mRipplePaint;
@@ -156,12 +156,6 @@ public class RippleDrawable extends LayerDrawable {
private boolean mOverrideBounds;
/**
- * Whether hotspots are being cleared. Used to prevent re-entry by
- * animation finish listeners.
- */
- private boolean mClearingHotspots;
-
- /**
* Constructor used for drawable inflation.
*/
RippleDrawable() {
@@ -209,19 +203,21 @@ public class RippleDrawable extends LayerDrawable {
mBackground.jump();
}
- mClearingHotspots = true;
- final int count = mAnimatingRipplesCount;
- final Ripple[] ripples = mAnimatingRipples;
+ cancelExitingRipples();
+ invalidateSelf();
+ }
+
+ private void cancelExitingRipples() {
+ final int count = mExitingRipplesCount;
+ final Ripple[] ripples = mExitingRipples;
for (int i = 0; i < count; i++) {
- ripples[i].jump();
+ ripples[i].cancel();
}
+
if (ripples != null) {
Arrays.fill(ripples, 0, count, null);
}
- mAnimatingRipplesCount = 0;
- mClearingHotspots = false;
-
- invalidateSelf();
+ mExitingRipplesCount = 0;
}
@Override
@@ -287,9 +283,9 @@ public class RippleDrawable extends LayerDrawable {
if (mRippleActive != active) {
mRippleActive = active;
if (active) {
- activateRipple();
+ tryRippleEnter();
} else {
- removeRipple();
+ tryRippleExit();
}
}
}
@@ -298,9 +294,9 @@ public class RippleDrawable extends LayerDrawable {
if (mBackgroundActive != active) {
mBackgroundActive = active;
if (active) {
- activateBackground();
+ tryBackgroundEnter();
} else {
- removeBackground();
+ tryBackgroundExit();
}
}
}
@@ -327,11 +323,11 @@ public class RippleDrawable extends LayerDrawable {
// If we just became visible, ensure the background and ripple
// visibilities are consistent with their internal states.
if (mRippleActive) {
- activateRipple();
+ tryRippleEnter();
}
if (mBackgroundActive) {
- activateBackground();
+ tryBackgroundEnter();
}
}
@@ -491,7 +487,7 @@ public class RippleDrawable extends LayerDrawable {
/**
* Creates an active hotspot at the specified location.
*/
- private void activateBackground() {
+ private void tryBackgroundEnter() {
if (mBackground == null) {
final float x;
final float y;
@@ -511,7 +507,7 @@ public class RippleDrawable extends LayerDrawable {
mBackground.enter();
}
- private void removeBackground() {
+ private void tryBackgroundExit() {
if (mBackground != null) {
// Don't null out the background, we need it to draw!
mBackground.exit();
@@ -519,10 +515,11 @@ public class RippleDrawable extends LayerDrawable {
}
/**
- * Creates an active hotspot at the specified location.
+ * Attempts to start an enter animation for the active hotspot. Fails if
+ * there are too many animating ripples.
*/
- private void activateRipple() {
- if (mAnimatingRipplesCount >= MAX_RIPPLES) {
+ private void tryRippleEnter() {
+ if (mExitingRipplesCount >= MAX_RIPPLES) {
// This should never happen unless the user is tapping like a maniac
// or there is a bug that's preventing ripples from being removed.
return;
@@ -545,29 +542,27 @@ public class RippleDrawable extends LayerDrawable {
final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
mRipple.setup(mState.mMaxRadius, color, mDensity);
mRipple.enter();
-
- if (mAnimatingRipples == null) {
- mAnimatingRipples = new Ripple[MAX_RIPPLES];
- }
- mAnimatingRipples[mAnimatingRipplesCount++] = mRipple;
}
- @Override
- public void invalidateSelf() {
- // Don't invalidate when we're clearing hotspots. We'll handle that
- // manually when we're done.
- if (!mClearingHotspots) {
- super.invalidateSelf();
- }
- }
-
- private void removeRipple() {
+ /**
+ * Attempts to start an exit animation for the active hotspot. Fails if
+ * there is no active hotspot.
+ */
+ private void tryRippleExit() {
if (mRipple != null) {
+ if (mExitingRipples == null) {
+ mExitingRipples = new Ripple[MAX_RIPPLES];
+ }
+ mExitingRipples[mExitingRipplesCount++] = mRipple;
mRipple.exit();
mRipple = null;
}
}
+ /**
+ * Cancels and removes the active ripple, all exiting ripples, and the
+ * background. Nothing will be drawn after this method is called.
+ */
private void clearHotspots() {
if (mRipple != null) {
mRipple.cancel();
@@ -579,18 +574,7 @@ public class RippleDrawable extends LayerDrawable {
mBackground = null;
}
- mClearingHotspots = true;
- final int count = mAnimatingRipplesCount;
- final Ripple[] ripples = mAnimatingRipples;
- for (int i = 0; i < count; i++) {
- ripples[i].cancel();
- }
- if (ripples != null) {
- Arrays.fill(ripples, 0, count, null);
- }
- mAnimatingRipplesCount = 0;
- mClearingHotspots = false;
-
+ cancelExitingRipples();
invalidateSelf();
}
@@ -612,8 +596,8 @@ public class RippleDrawable extends LayerDrawable {
* Notifies all the animating ripples that the hotspot bounds have changed.
*/
private void onHotspotBoundsChanged() {
- final int count = mAnimatingRipplesCount;
- final Ripple[] ripples = mAnimatingRipples;
+ final int count = mExitingRipplesCount;
+ final Ripple[] ripples = mExitingRipples;
for (int i = 0; i < count; i++) {
ripples[i].onHotspotBoundsChanged();
}
@@ -683,22 +667,21 @@ public class RippleDrawable extends LayerDrawable {
}
/**
- * Removes a ripple from the animating ripple list.
+ * Removes a ripple from the exiting ripple list.
*
* @param ripple the ripple to remove
*/
void removeRipple(Ripple ripple) {
- if (!mClearingHotspots) {
- // Ripple ripple ripple ripple. Ripple ripple.
- final Ripple[] ripples = mAnimatingRipples;
- final int count = mAnimatingRipplesCount;
- final int index = getRippleIndex(ripple);
- if (index >= 0) {
- System.arraycopy(ripples, index + 1, ripples, index, count - (index + 1));
- ripples[count - 1] = null;
- mAnimatingRipplesCount--;
- invalidateSelf();
- }
+ // Ripple ripple ripple ripple. Ripple ripple.
+ final Ripple[] ripples = mExitingRipples;
+ final int count = mExitingRipplesCount;
+ final int index = getRippleIndex(ripple);
+ if (index >= 0) {
+ System.arraycopy(ripples, index + 1, ripples, index, count - (index + 1));
+ ripples[count - 1] = null;
+ mExitingRipplesCount--;
+
+ invalidateSelf();
}
}
@@ -710,8 +693,8 @@ public class RippleDrawable extends LayerDrawable {
}
private int getRippleIndex(Ripple ripple) {
- final Ripple[] ripples = mAnimatingRipples;
- final int count = mAnimatingRipplesCount;
+ final Ripple[] ripples = mExitingRipples;
+ final int count = mExitingRipplesCount;
for (int i = 0; i < count; i++) {
if (ripples[i] == ripple) {
return i;
@@ -727,7 +710,7 @@ public class RippleDrawable extends LayerDrawable {
// We don't need a layer if we don't expect to draw any ripples, we have
// an explicit mask, or if the non-mask content is all opaque.
boolean needsLayer = false;
- if ((mAnimatingRipplesCount > 0 || mBackground != null) && mMask == null) {
+ if ((mExitingRipplesCount > 0 || mBackground != null) && mMask == null) {
for (int i = 0; i < count; i++) {
if (array[i].mId != R.id.mask
&& array[i].mDrawable.getOpacity() != PixelFormat.OPAQUE) {
@@ -831,10 +814,17 @@ public class RippleDrawable extends LayerDrawable {
int restoreTranslate = -1;
// Draw ripples and update the animating ripples array.
- final int count = mAnimatingRipplesCount;
- final Ripple[] ripples = mAnimatingRipples;
- for (int i = 0; i < count; i++) {
- final Ripple ripple = ripples[i];
+ final int count = mExitingRipplesCount;
+ final Ripple[] ripples = mExitingRipples;
+ for (int i = 0; i <= count; i++) {
+ final Ripple ripple;
+ if (i < count) {
+ ripple = ripples[i];
+ } else if (mRipple != null) {
+ ripple = mRipple;
+ } else {
+ continue;
+ }
// If we're masking the ripple layer, make sure we have a layer
// first. This will merge SRC_OVER (directly) onto the canvas.
@@ -898,8 +888,9 @@ public class RippleDrawable extends LayerDrawable {
final int cX = (int) mHotspotBounds.exactCenterX();
final int cY = (int) mHotspotBounds.exactCenterY();
final Rect rippleBounds = mTempRect;
- final Ripple[] activeRipples = mAnimatingRipples;
- final int N = mAnimatingRipplesCount;
+
+ final Ripple[] activeRipples = mExitingRipples;
+ final int N = mExitingRipplesCount;
for (int i = 0; i < N; i++) {
activeRipples[i].getBounds(rippleBounds);
rippleBounds.offset(cX, cY);
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 6ac49ee..0db8c77 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -331,6 +331,36 @@ public class KeyStore {
}
}
+ public boolean resetUid(int uid) {
+ try {
+ mError = mBinder.reset_uid(uid);
+ return mError == NO_ERROR;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return false;
+ }
+ }
+
+ public boolean syncUid(int sourceUid, int targetUid) {
+ try {
+ mError = mBinder.sync_uid(sourceUid, targetUid);
+ return mError == NO_ERROR;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return false;
+ }
+ }
+
+ public boolean passwordUid(String password, int uid) {
+ try {
+ mError = mBinder.password_uid(password, uid);
+ return mError == NO_ERROR;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return false;
+ }
+ }
+
public int getLastError() {
return mError;
}
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index a10c387..5808d20 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -26,6 +26,7 @@ testFiles := \
Idmap_test.cpp \
ResTable_test.cpp \
Split_test.cpp \
+ Theme_test.cpp \
TypeWrappers_test.cpp \
ZipUtils_test.cpp
diff --git a/libs/androidfw/tests/BackupData_test.cpp b/libs/androidfw/tests/BackupData_test.cpp
index 17f91ca..92af7fe 100644
--- a/libs/androidfw/tests/BackupData_test.cpp
+++ b/libs/androidfw/tests/BackupData_test.cpp
@@ -45,7 +45,7 @@ namespace android {
class BackupDataTest : public testing::Test {
protected:
char* m_external_storage;
- char* m_filename;
+ String8 mFilename;
String8 mKey1;
String8 mKey2;
String8 mKey3;
@@ -53,15 +53,13 @@ protected:
virtual void SetUp() {
m_external_storage = getenv("EXTERNAL_STORAGE");
+ mFilename.append(m_external_storage);
+ mFilename.append(TEST_FILENAME);
- const int totalLen = strlen(m_external_storage) + strlen(TEST_FILENAME) + 1;
- m_filename = new char[totalLen];
- snprintf(m_filename, totalLen, "%s%s", m_external_storage, TEST_FILENAME);
-
- ::unlink(m_filename);
- int fd = ::open(m_filename, O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ ::unlink(mFilename.string());
+ int fd = ::open(mFilename.string(), O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd < 0) {
- FAIL() << "Couldn't create " << m_filename << " for writing";
+ FAIL() << "Couldn't create " << mFilename.string() << " for writing";
}
mKey1 = String8(KEY1);
mKey2 = String8(KEY2);
@@ -74,7 +72,7 @@ protected:
};
TEST_F(BackupDataTest, WriteAndReadSingle) {
- int fd = ::open(m_filename, O_WRONLY);
+ int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
EXPECT_EQ(NO_ERROR, writer->WriteEntityHeader(mKey1, sizeof(DATA1)))
@@ -83,7 +81,7 @@ TEST_F(BackupDataTest, WriteAndReadSingle) {
<< "WriteEntityData returned an error";
::close(fd);
- fd = ::open(m_filename, O_RDONLY);
+ fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
EXPECT_EQ(NO_ERROR, reader->Status())
<< "Reader ctor failed";
@@ -116,7 +114,7 @@ TEST_F(BackupDataTest, WriteAndReadSingle) {
}
TEST_F(BackupDataTest, WriteAndReadMultiple) {
- int fd = ::open(m_filename, O_WRONLY);
+ int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, sizeof(DATA1));
writer->WriteEntityData(DATA1, sizeof(DATA1));
@@ -124,7 +122,7 @@ TEST_F(BackupDataTest, WriteAndReadMultiple) {
writer->WriteEntityData(DATA2, sizeof(DATA2));
::close(fd);
- fd = ::open(m_filename, O_RDONLY);
+ fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
@@ -164,7 +162,7 @@ TEST_F(BackupDataTest, WriteAndReadMultiple) {
}
TEST_F(BackupDataTest, SkipEntity) {
- int fd = ::open(m_filename, O_WRONLY);
+ int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, sizeof(DATA1));
writer->WriteEntityData(DATA1, sizeof(DATA1));
@@ -174,7 +172,7 @@ TEST_F(BackupDataTest, SkipEntity) {
writer->WriteEntityData(DATA3, sizeof(DATA3));
::close(fd);
- fd = ::open(m_filename, O_RDONLY);
+ fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
@@ -219,14 +217,14 @@ TEST_F(BackupDataTest, SkipEntity) {
}
TEST_F(BackupDataTest, DeleteEntity) {
- int fd = ::open(m_filename, O_WRONLY);
+ int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, sizeof(DATA1));
writer->WriteEntityData(DATA1, sizeof(DATA1));
writer->WriteEntityHeader(mKey2, -1);
::close(fd);
- fd = ::open(m_filename, O_RDONLY);
+ fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
@@ -258,7 +256,7 @@ TEST_F(BackupDataTest, DeleteEntity) {
}
TEST_F(BackupDataTest, EneityAfterDelete) {
- int fd = ::open(m_filename, O_WRONLY);
+ int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, sizeof(DATA1));
writer->WriteEntityData(DATA1, sizeof(DATA1));
@@ -267,7 +265,7 @@ TEST_F(BackupDataTest, EneityAfterDelete) {
writer->WriteEntityData(DATA3, sizeof(DATA3));
::close(fd);
- fd = ::open(m_filename, O_RDONLY);
+ fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
@@ -319,7 +317,7 @@ TEST_F(BackupDataTest, EneityAfterDelete) {
}
TEST_F(BackupDataTest, OnlyDeleteEntities) {
- int fd = ::open(m_filename, O_WRONLY);
+ int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, -1);
writer->WriteEntityHeader(mKey2, -1);
@@ -327,7 +325,7 @@ TEST_F(BackupDataTest, OnlyDeleteEntities) {
writer->WriteEntityHeader(mKey4, -1);
::close(fd);
- fd = ::open(m_filename, O_RDONLY);
+ fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
@@ -387,13 +385,13 @@ TEST_F(BackupDataTest, OnlyDeleteEntities) {
}
TEST_F(BackupDataTest, ReadDeletedEntityData) {
- int fd = ::open(m_filename, O_WRONLY);
+ int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, -1);
writer->WriteEntityHeader(mKey2, -1);
::close(fd);
- fd = ::open(m_filename, O_RDONLY);
+ fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
@@ -431,6 +429,7 @@ TEST_F(BackupDataTest, ReadDeletedEntityData) {
EXPECT_EQ(-1, (int) dataSize)
<< "not recognizing deletion on second entity";
+ delete[] dataBytes;
delete writer;
delete reader;
}
diff --git a/libs/androidfw/tests/ObbFile_test.cpp b/libs/androidfw/tests/ObbFile_test.cpp
index 7a4dd13..1151121 100644
--- a/libs/androidfw/tests/ObbFile_test.cpp
+++ b/libs/androidfw/tests/ObbFile_test.cpp
@@ -34,20 +34,18 @@ namespace android {
class ObbFileTest : public testing::Test {
protected:
sp<ObbFile> mObbFile;
- char* mExternalStorage;
- char* mFileName;
+ String8 mFileName;
virtual void SetUp() {
mObbFile = new ObbFile();
- mExternalStorage = getenv("EXTERNAL_STORAGE");
+ char* externalStorage = getenv("EXTERNAL_STORAGE");
- const int totalLen = strlen(mExternalStorage) + strlen(TEST_FILENAME) + 1;
- mFileName = new char[totalLen];
- snprintf(mFileName, totalLen, "%s%s", mExternalStorage, TEST_FILENAME);
+ mFileName.append(externalStorage);
+ mFileName.append(TEST_FILENAME);
- int fd = ::open(mFileName, O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ int fd = ::open(mFileName.string(), O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd < 0) {
- FAIL() << "Couldn't create " << mFileName << " for tests";
+ FAIL() << "Couldn't create " << mFileName.string() << " for tests";
}
}
@@ -71,12 +69,12 @@ TEST_F(ObbFileTest, WriteThenRead) {
EXPECT_TRUE(mObbFile->setSalt(salt, SALT_SIZE))
<< "Salt should be successfully set";
- EXPECT_TRUE(mObbFile->writeTo(mFileName))
+ EXPECT_TRUE(mObbFile->writeTo(mFileName.string()))
<< "couldn't write to fake .obb file";
mObbFile = new ObbFile();
- EXPECT_TRUE(mObbFile->readFrom(mFileName))
+ EXPECT_TRUE(mObbFile->readFrom(mFileName.string()))
<< "couldn't read from fake .obb file";
EXPECT_EQ(versionNum, mObbFile->getVersion())
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
new file mode 100644
index 0000000..4d07130
--- /dev/null
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#include <androidfw/ResourceTypes.h>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include "TestHelpers.h"
+#include "data/system/R.h"
+#include "data/app/R.h"
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+namespace {
+
+#include "data/system/system_arsc.h"
+#include "data/app/app_arsc.h"
+
+enum { MAY_NOT_BE_BAG = false };
+
+/**
+ * TODO(adamlesinski): Enable when fixed.
+ */
+TEST(ThemeTest, DISABLED_shouldCopyThemeFromDifferentResTable) {
+ ResTable table;
+ ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len));
+ ASSERT_EQ(NO_ERROR, table.add(app_arsc, app_arsc_len));
+
+ ResTable::Theme theme1(table);
+ ASSERT_EQ(NO_ERROR, theme1.applyStyle(app::R::style::Theme_One));
+ Res_value val;
+ ASSERT_GE(theme1.getAttribute(android::R::attr::background, &val), 0);
+ ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, val.dataType);
+ ASSERT_EQ(uint32_t(0xffff0000), val.data);
+ ASSERT_GE(theme1.getAttribute(app::R::attr::number, &val), 0);
+ ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+ ASSERT_EQ(uint32_t(1), val.data);
+
+ ResTable table2;
+ ASSERT_EQ(NO_ERROR, table2.add(system_arsc, system_arsc_len));
+ ASSERT_EQ(NO_ERROR, table2.add(app_arsc, app_arsc_len));
+
+ ResTable::Theme theme2(table2);
+ ASSERT_EQ(NO_ERROR, theme2.setTo(theme1));
+ ASSERT_GE(theme2.getAttribute(android::R::attr::background, &val), 0);
+ ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, val.dataType);
+ ASSERT_EQ(uint32_t(0xffff0000), val.data);
+ ASSERT_GE(theme2.getAttribute(app::R::attr::number, &val), 0);
+ ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+ ASSERT_EQ(uint32_t(1), val.data);
+}
+
+}
diff --git a/packages/DocumentsUI/res/drawable/grid_protect_background.xml b/libs/androidfw/tests/data/app/AndroidManifest.xml
index 2e7aadd..bfa3a39 100644
--- a/packages/DocumentsUI/res/drawable/grid_protect_background.xml
+++ b/libs/androidfw/tests/data/app/AndroidManifest.xml
@@ -14,11 +14,6 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false">
- <color android:color="#88000000" />
- </item>
- <item>
- <color android:color="#88252525" />
- </item>
-</selector>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.app">
+</manifest>
diff --git a/libs/androidfw/tests/data/app/R.h b/libs/androidfw/tests/data/app/R.h
new file mode 100644
index 0000000..780a116
--- /dev/null
+++ b/libs/androidfw/tests/data/app/R.h
@@ -0,0 +1,22 @@
+#ifndef __APP_R_H
+#define __APP_R_H
+
+namespace app {
+namespace R {
+
+namespace attr {
+ enum {
+ number = 0x7f010000, // default
+ };
+}
+
+namespace style {
+ enum {
+ Theme_One = 0x7f020000, // default
+ };
+}
+
+} // namespace R
+} // namespace app
+
+#endif // __APP_R_H
diff --git a/libs/androidfw/tests/data/app/app_arsc.h b/libs/androidfw/tests/data/app/app_arsc.h
new file mode 100644
index 0000000..d5d9a3b
--- /dev/null
+++ b/libs/androidfw/tests/data/app/app_arsc.h
@@ -0,0 +1,62 @@
+unsigned char app_arsc[] = {
+ 0x02, 0x00, 0x0c, 0x00, 0xc4, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x9c, 0x02, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
+ 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
+ 0x64, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00,
+ 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+ 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6e, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
+ 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00
+};
+unsigned int app_arsc_len = 708;
diff --git a/libs/androidfw/tests/data/app/build b/libs/androidfw/tests/data/app/build
new file mode 100755
index 0000000..89c4641
--- /dev/null
+++ b/libs/androidfw/tests/data/app/build
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+aapt package -v -I ../system/bundle.apk -M AndroidManifest.xml -S res -F bundle.apk -f && \
+unzip bundle.apk resources.arsc && \
+mv resources.arsc app.arsc && \
+xxd -i app.arsc > app_arsc.h
diff --git a/libs/androidfw/tests/data/app/res/values/values.xml b/libs/androidfw/tests/data/app/res/values/values.xml
new file mode 100644
index 0000000..b0ead38
--- /dev/null
+++ b/libs/androidfw/tests/data/app/res/values/values.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <attr name="number" format="integer"/>
+ <style name="Theme.One" parent="@android:style/Theme.One">
+ <item name="number">1</item>
+ </style>
+</resources>
diff --git a/libs/androidfw/tests/data/system/AndroidManifest.xml b/libs/androidfw/tests/data/system/AndroidManifest.xml
new file mode 100644
index 0000000..af105ee
--- /dev/null
+++ b/libs/androidfw/tests/data/system/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+</manifest>
diff --git a/libs/androidfw/tests/data/system/R.h b/libs/androidfw/tests/data/system/R.h
new file mode 100644
index 0000000..7a9d3db
--- /dev/null
+++ b/libs/androidfw/tests/data/system/R.h
@@ -0,0 +1,23 @@
+#ifndef __ANDROID_R_H
+#define __ANDROID_R_H
+
+namespace android {
+namespace R {
+
+namespace attr {
+ enum {
+ background = 0x01010000, // default
+ foreground = 0x01010001, // default
+ };
+}
+
+namespace style {
+ enum {
+ Theme_One = 0x01020000, // default
+ };
+}
+
+} // namespace R
+} // namespace android
+
+#endif // __ANDROID_R_H
diff --git a/libs/androidfw/tests/data/system/build b/libs/androidfw/tests/data/system/build
new file mode 100755
index 0000000..2a3ac0b
--- /dev/null
+++ b/libs/androidfw/tests/data/system/build
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+aapt package -x -M AndroidManifest.xml -S res -F bundle.apk -f && \
+unzip bundle.apk resources.arsc && \
+mv resources.arsc system.arsc && \
+xxd -i system.arsc > system_arsc.h
diff --git a/libs/androidfw/tests/data/system/res/values/themes.xml b/libs/androidfw/tests/data/system/res/values/themes.xml
new file mode 100644
index 0000000..b29848e
--- /dev/null
+++ b/libs/androidfw/tests/data/system/res/values/themes.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <public name="background" type="attr" id="0x01010000"/>
+ <public name="foreground" type="attr" id="0x01010001"/>
+ <public name="Theme.One" type="style" id="0x01020000"/>
+
+ <attr name="background" format="color|reference"/>
+ <attr name="foreground" format="color|reference"/>
+ <style name="Theme.One" parent="">
+ <item name="android:background">#ff0000</item>
+ <item name="android:foreground">#000000</item>
+ </style>
+</resources>
diff --git a/libs/androidfw/tests/data/system/system_arsc.h b/libs/androidfw/tests/data/system/system_arsc.h
new file mode 100644
index 0000000..215ecae
--- /dev/null
+++ b/libs/androidfw/tests/data/system/system_arsc.h
@@ -0,0 +1,69 @@
+unsigned char system_arsc[] = {
+ 0x02, 0x00, 0x0c, 0x00, 0x18, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf0, 0x02, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
+ 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00,
+ 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+ 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x67, 0x00,
+ 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x67, 0x00,
+ 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
+ 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
+ 0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x44, 0x00,
+ 0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff,
+ 0x01, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff
+};
+unsigned int system_arsc_len = 792;
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index 9cc83ed..7834ef8 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -16,6 +16,43 @@
#define LOG_TAG "OpenGLRenderer"
+/**
+ * Extra vertices for the corner for smoother corner.
+ * Only for outer vertices.
+ * Note that we use such extra memory to avoid an extra loop.
+ */
+// For half circle, we could add EXTRA_VERTEX_PER_PI vertices.
+// Set to 1 if we don't want to have any.
+#define EXTRA_CORNER_VERTEX_PER_PI 12
+
+// For the whole polygon, the sum of all the deltas b/t normals is 2 * M_PI,
+// therefore, the maximum number of extra vertices will be twice bigger.
+#define MAX_EXTRA_CORNER_VERTEX_NUMBER (2 * EXTRA_CORNER_VERTEX_PER_PI)
+
+// For each RADIANS_DIVISOR, we would allocate one more vertex b/t the normals.
+#define CORNER_RADIANS_DIVISOR (M_PI / EXTRA_CORNER_VERTEX_PER_PI)
+
+/**
+ * Extra vertices for the Edge for interpolation artifacts.
+ * Same value for both inner and outer vertices.
+ */
+#define EXTRA_EDGE_VERTEX_PER_PI 50
+
+#define MAX_EXTRA_EDGE_VERTEX_NUMBER (2 * EXTRA_EDGE_VERTEX_PER_PI)
+
+#define EDGE_RADIANS_DIVISOR (M_PI / EXTRA_EDGE_VERTEX_PER_PI)
+
+/**
+ * Other constants:
+ */
+// For the edge of the penumbra, the opacity is 0.
+#define OUTER_OPACITY (0.0f)
+
+// Once the alpha difference is greater than this threshold, we will allocate extra
+// edge vertices.
+// If this is set to negative value, then all the edge will be tessellated.
+#define ALPHA_THRESHOLD (0.1f / 255.0f)
+
#include <math.h>
#include <utils/Log.h>
#include <utils/Vector.h>
@@ -23,11 +60,97 @@
#include "AmbientShadow.h"
#include "ShadowTessellator.h"
#include "Vertex.h"
+#include "utils/MathUtils.h"
namespace android {
namespace uirenderer {
/**
+ * Local utility functions.
+ */
+inline Vector2 getNormalFromVertices(const Vector3* vertices, int current, int next) {
+ // Convert from Vector3 to Vector2 first.
+ Vector2 currentVertex = { vertices[current].x, vertices[current].y };
+ Vector2 nextVertex = { vertices[next].x, vertices[next].y };
+
+ return ShadowTessellator::calculateNormal(currentVertex, nextVertex);
+}
+
+// The input z value will be converted to be non-negative inside.
+// The output must be ranged from 0 to 1.
+inline float getAlphaFromFactoredZ(float factoredZ) {
+ return 1.0 / (1 + MathUtils::max(factoredZ, 0.0f));
+}
+
+inline float getTransformedAlphaFromAlpha(float alpha) {
+ return acosf(1.0f - 2.0f * alpha);
+}
+
+// The output is ranged from 0 to M_PI.
+inline float getTransformedAlphaFromFactoredZ(float factoredZ) {
+ return getTransformedAlphaFromAlpha(getAlphaFromFactoredZ(factoredZ));
+}
+
+inline int getExtraVertexNumber(const Vector2& vector1, const Vector2& vector2,
+ float divisor) {
+ // The formula is :
+ // extraNumber = floor(acos(dot(n1, n2)) / (M_PI / EXTRA_VERTEX_PER_PI))
+ // The value ranges for each step are:
+ // dot( ) --- [-1, 1]
+ // acos( ) --- [0, M_PI]
+ // floor(...) --- [0, EXTRA_VERTEX_PER_PI]
+ float dotProduct = vector1.dot(vector2);
+ // TODO: Use look up table for the dotProduct to extraVerticesNumber
+ // computation, if needed.
+ float angle = acosf(dotProduct);
+ return (int) floor(angle / divisor);
+}
+
+inline void checkOverflow(int used, int total, const char* bufferName) {
+ LOG_ALWAYS_FATAL_IF(used > total, "Error: %s overflow!!! used %d, total %d",
+ bufferName, used, total);
+}
+
+inline int getEdgeExtraAndUpdateSpike(Vector2* currentSpike,
+ const Vector3& secondVertex, const Vector3& centroid) {
+ Vector2 secondSpike = {secondVertex.x - centroid.x, secondVertex.y - centroid.y};
+ secondSpike.normalize();
+
+ int result = getExtraVertexNumber(secondSpike, *currentSpike, EDGE_RADIANS_DIVISOR);
+ *currentSpike = secondSpike;
+ return result;
+}
+
+// Given the caster's vertex count, compute all the buffers size depending on
+// whether or not the caster is opaque.
+inline void computeBufferSize(int* totalVertexCount, int* totalIndexCount,
+ int* totalUmbraCount, int casterVertexCount, bool isCasterOpaque) {
+ // Compute the size of the vertex buffer.
+ int outerVertexCount = casterVertexCount * 2 + MAX_EXTRA_CORNER_VERTEX_NUMBER +
+ MAX_EXTRA_EDGE_VERTEX_NUMBER;
+ int innerVertexCount = casterVertexCount + MAX_EXTRA_EDGE_VERTEX_NUMBER;
+ *totalVertexCount = outerVertexCount + innerVertexCount;
+
+ // Compute the size of the index buffer.
+ *totalIndexCount = 2 * outerVertexCount + 2;
+
+ // Compute the size of the umber buffer.
+ // For translucent object, keep track of the umbra(inner) vertex in order to draw
+ // inside. We only need to store the index information.
+ *totalUmbraCount = 0;
+ if (!isCasterOpaque) {
+ // Add the centroid if occluder is translucent.
+ *totalVertexCount++;
+ *totalIndexCount += 2 * innerVertexCount + 1;
+ *totalUmbraCount = innerVertexCount;
+ }
+}
+
+inline bool needsExtraForEdge(float firstAlpha, float secondAlpha) {
+ return abs(firstAlpha - secondAlpha) > ALPHA_THRESHOLD;
+}
+
+/**
* Calculate the shadows as a triangle strips while alpha value as the
* shadow values.
*
@@ -43,290 +166,198 @@ namespace uirenderer {
*
* @param shadowVertexBuffer Return an floating point array of (x, y, a)
* triangle strips mode.
+ *
+ * An simple illustration:
+ * For now let's mark the outer vertex as Pi, the inner as Vi, the centroid as C.
+ *
+ * First project the occluder to the Z=0 surface.
+ * Then we got all the inner vertices. And we compute the normal for each edge.
+ * According to the normal, we generate outer vertices. E.g: We generate P1 / P4
+ * as extra corner vertices to make the corner looks round and smoother.
+ *
+ * Due to the fact that the alpha is not linear interpolated along the inner
+ * edge, when the alpha is different, we may add extra vertices such as P2.1, P2.2,
+ * V0.1, V0.2 to avoid the visual artifacts.
+ *
+ * (P3)
+ * (P2) (P2.1) (P2.2) | ' (P4)
+ * (P1)' | | | | '
+ * ' | | | | '
+ * (P0) ------------------------------------------------(P5)
+ * | (V0) (V0.1) (V0.2) |(V1)
+ * | |
+ * | |
+ * | (C) |
+ * | |
+ * | |
+ * | |
+ * | |
+ * (V3)-----------------------------------(V2)
*/
void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
- const Vector3* vertices, int vertexCount, const Vector3& centroid3d,
+ const Vector3* casterVertices, int casterVertexCount, const Vector3& centroid3d,
float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) {
- const int rays = SHADOW_RAY_COUNT;
- // Validate the inputs.
- if (vertexCount < 3 || heightFactor <= 0 || rays <= 0
- || geomFactor <= 0) {
-#if DEBUG_SHADOW
- ALOGW("Invalid input for createAmbientShadow(), early return!");
-#endif
- return;
- }
+ shadowVertexBuffer.setMode(VertexBuffer::kIndices);
- Vector<Vector2> dir; // TODO: use C++11 unique_ptr
- dir.setCapacity(rays);
- float rayDist[rays];
- float rayHeight[rays];
- calculateRayDirections(rays, vertices, vertexCount, centroid3d, dir.editArray());
-
- // Calculate the length and height of the points along the edge.
- //
- // The math here is:
- // Intersect each ray (starting from the centroid) with the polygon.
- for (int i = 0; i < rays; i++) {
- int edgeIndex;
- float edgeFraction;
- float rayDistance;
- calculateIntersection(vertices, vertexCount, centroid3d, dir[i], edgeIndex,
- edgeFraction, rayDistance);
- rayDist[i] = rayDistance;
- if (edgeIndex < 0 || edgeIndex >= vertexCount) {
-#if DEBUG_SHADOW
- ALOGW("Invalid edgeIndex!");
-#endif
- edgeIndex = 0;
- }
- float h1 = vertices[edgeIndex].z;
- float h2 = vertices[((edgeIndex + 1) % vertexCount)].z;
- rayHeight[i] = h1 + edgeFraction * (h2 - h1);
- }
+ // In order to computer the outer vertices in one loop, we need pre-compute
+ // the normal by the vertex (n - 1) to vertex 0, and the spike and alpha value
+ // for vertex 0.
+ Vector2 previousNormal = getNormalFromVertices(casterVertices,
+ casterVertexCount - 1 , 0);
+ Vector2 currentSpike = {casterVertices[0].x - centroid3d.x,
+ casterVertices[0].y - centroid3d.y};
+ currentSpike.normalize();
+ float currentAlpha = getAlphaFromFactoredZ(casterVertices[0].z * heightFactor);
- // The output buffer length basically is roughly rays * layers, but since we
- // need triangle strips, so we need to duplicate vertices to accomplish that.
+ // Preparing all the output data.
+ int totalVertexCount, totalIndexCount, totalUmbraCount;
+ computeBufferSize(&totalVertexCount, &totalIndexCount, &totalUmbraCount,
+ casterVertexCount, isCasterOpaque);
AlphaVertex* shadowVertices =
- shadowVertexBuffer.alloc<AlphaVertex>(SHADOW_VERTEX_COUNT);
-
- // Calculate the vertex of the shadows.
- //
- // The math here is:
- // Along the edges of the polygon, for each intersection point P (generated above),
- // calculate the normal N, which should be perpendicular to the edge of the
- // polygon (represented by the neighbor intersection points) .
- // Shadow's vertices will be generated as : P + N * scale.
- const Vector2 centroid2d = {centroid3d.x, centroid3d.y};
- for (int rayIndex = 0; rayIndex < rays; rayIndex++) {
- Vector2 normal = {1.0f, 0.0f};
- calculateNormal(rays, rayIndex, dir.array(), rayDist, normal);
-
- // The vertex should be start from rayDist[i] then scale the
- // normalizeNormal!
- Vector2 intersection = dir[rayIndex] * rayDist[rayIndex] +
- centroid2d;
-
- // outer ring of points, expanded based upon height of each ray intersection
- float expansionDist = rayHeight[rayIndex] * heightFactor *
- geomFactor;
- AlphaVertex::set(&shadowVertices[rayIndex],
- intersection.x + normal.x * expansionDist,
- intersection.y + normal.y * expansionDist,
- 0.0f);
-
- // inner ring of points
- float opacity = 1.0 / (1 + rayHeight[rayIndex] * heightFactor);
- // NOTE: Shadow alpha values are transformed when stored in alphavertices,
- // so that they can be consumed directly by gFS_Main_ApplyVertexAlphaShadowInterp
- float transformedOpacity = acos(1.0f - 2.0f * opacity);
- AlphaVertex::set(&shadowVertices[rays + rayIndex],
- intersection.x,
- intersection.y,
- transformedOpacity);
- }
+ shadowVertexBuffer.alloc<AlphaVertex>(totalVertexCount);
+ int vertexBufferIndex = 0;
+ uint16_t* indexBuffer = shadowVertexBuffer.allocIndices<uint16_t>(totalIndexCount);
+ int indexBufferIndex = 0;
+ uint16_t umbraVertices[totalUmbraCount];
+ int umbraIndex = 0;
- if (isCasterOpaque) {
- // skip inner ring, calc bounds over filled portion of buffer
- shadowVertexBuffer.computeBounds<AlphaVertex>(2 * rays);
- shadowVertexBuffer.setMode(VertexBuffer::kOnePolyRingShadow);
- } else {
- // If caster isn't opaque, we need to to fill the umbra by storing the umbra's
- // centroid in the innermost ring of vertices.
- float centroidAlpha = 1.0 / (1 + centroid3d.z * heightFactor);
- AlphaVertex centroidXYA;
- AlphaVertex::set(&centroidXYA, centroid2d.x, centroid2d.y, centroidAlpha);
- for (int rayIndex = 0; rayIndex < rays; rayIndex++) {
- shadowVertices[2 * rays + rayIndex] = centroidXYA;
- }
- // calc bounds over entire buffer
- shadowVertexBuffer.computeBounds<AlphaVertex>();
- shadowVertexBuffer.setMode(VertexBuffer::kTwoPolyRingShadow);
- }
+ for (int i = 0; i < casterVertexCount; i++) {
+ // Corner: first figure out the extra vertices we need for the corner.
+ const Vector3& innerVertex = casterVertices[i];
+ Vector2 currentNormal = getNormalFromVertices(casterVertices, i,
+ (i + 1) % casterVertexCount);
+
+ int extraVerticesNumber = getExtraVertexNumber(currentNormal, previousNormal,
+ CORNER_RADIANS_DIVISOR);
+ float expansionDist = innerVertex.z * heightFactor * geomFactor;
+ const int cornerSlicesNumber = extraVerticesNumber + 1; // Minimal as 1.
#if DEBUG_SHADOW
- for (int i = 0; i < SHADOW_VERTEX_COUNT; i++) {
- ALOGD("ambient shadow value: i %d, (x:%f, y:%f, a:%f)", i, shadowVertices[i].x,
- shadowVertices[i].y, shadowVertices[i].alpha);
- }
+ ALOGD("cornerSlicesNumber is %d", cornerSlicesNumber);
#endif
-}
-/**
- * Generate an array of rays' direction vectors.
- * To make sure the vertices generated are clockwise, the directions are from PI
- * to -PI.
- *
- * @param rays The number of rays shooting out from the centroid.
- * @param vertices Vertices of the polygon.
- * @param vertexCount The number of vertices.
- * @param centroid3d The centroid of the polygon.
- * @param dir Return the array of ray vectors.
- */
-void AmbientShadow::calculateRayDirections(const int rays, const Vector3* vertices,
- const int vertexCount, const Vector3& centroid3d, Vector2* dir) {
- // If we don't have enough rays, then fall back to the uniform distribution.
- if (vertexCount * 2 > rays) {
- float deltaAngle = 2 * M_PI / rays;
- for (int i = 0; i < rays; i++) {
- dir[i].x = cosf(M_PI - deltaAngle * i);
- dir[i].y = sinf(M_PI - deltaAngle * i);
+ // Corner: fill the corner Vertex Buffer(VB) and Index Buffer(IB).
+ // We fill the inner vertex first, such that we can fill the index buffer
+ // inside the loop.
+ int currentInnerVertexIndex = vertexBufferIndex;
+ if (!isCasterOpaque) {
+ umbraVertices[umbraIndex++] = vertexBufferIndex;
}
- return;
- }
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], casterVertices[i].x,
+ casterVertices[i].y,
+ getTransformedAlphaFromAlpha(currentAlpha));
- // If we have enough rays, then we assign each vertices a ray, and distribute
- // the rest uniformly.
- float rayThetas[rays];
-
- const int uniformRayCount = rays - vertexCount;
- const float deltaAngle = 2 * M_PI / uniformRayCount;
-
- // We have to generate all the vertices' theta anyway and we also need to
- // find the minimal, so let's precompute it first.
- // Since the incoming polygon is clockwise, we can find the dip to identify
- // the minimal theta.
- float polyThetas[vertexCount];
- int maxPolyThetaIndex = 0;
- for (int i = 0; i < vertexCount; i++) {
- polyThetas[i] = atan2(vertices[i].y - centroid3d.y,
- vertices[i].x - centroid3d.x);
- if (i > 0 && polyThetas[i] > polyThetas[i - 1]) {
- maxPolyThetaIndex = i;
- }
- }
+ const Vector3& innerStart = casterVertices[i];
- // Both poly's thetas and uniform thetas are in decrease order(clockwise)
- // from PI to -PI.
- int polyThetaIndex = maxPolyThetaIndex;
- float polyTheta = polyThetas[maxPolyThetaIndex];
- int uniformThetaIndex = 0;
- float uniformTheta = M_PI;
- for (int i = 0; i < rays; i++) {
- // Compare both thetas and pick the smaller one and move on.
- bool hasThetaCollision = abs(polyTheta - uniformTheta) < MINIMAL_DELTA_THETA;
- if (polyTheta > uniformTheta || hasThetaCollision) {
- if (hasThetaCollision) {
- // Shift the uniformTheta to middle way between current polyTheta
- // and next uniform theta. The next uniform theta can wrap around
- // to exactly PI safely here.
- // Note that neither polyTheta nor uniformTheta can be FLT_MAX
- // due to the hasThetaCollision is true.
- uniformTheta = (polyTheta + M_PI - deltaAngle * (uniformThetaIndex + 1)) / 2;
-#if DEBUG_SHADOW
- ALOGD("Shifted uniformTheta to %f", uniformTheta);
-#endif
- }
- rayThetas[i] = polyTheta;
- polyThetaIndex = (polyThetaIndex + 1) % vertexCount;
- if (polyThetaIndex != maxPolyThetaIndex) {
- polyTheta = polyThetas[polyThetaIndex];
- } else {
- // out of poly points.
- polyTheta = - FLT_MAX;
- }
- } else {
- rayThetas[i] = uniformTheta;
- uniformThetaIndex++;
- if (uniformThetaIndex < uniformRayCount) {
- uniformTheta = M_PI - deltaAngle * uniformThetaIndex;
- } else {
- // out of uniform points.
- uniformTheta = - FLT_MAX;
+ // outerStart is the first outer vertex for this inner vertex.
+ // outerLast is the last outer vertex for this inner vertex.
+ Vector2 outerStart = {0, 0};
+ Vector2 outerLast = {0, 0};
+ // This will create vertices from [0, cornerSlicesNumber] inclusively,
+ // which means minimally 2 vertices even without the extra ones.
+ for (int j = 0; j <= cornerSlicesNumber; j++) {
+ Vector2 averageNormal =
+ previousNormal * (cornerSlicesNumber - j) + currentNormal * j;
+ averageNormal /= cornerSlicesNumber;
+ averageNormal.normalize();
+ Vector2 outerVertex;
+ outerVertex.x = innerVertex.x + averageNormal.x * expansionDist;
+ outerVertex.y = innerVertex.y + averageNormal.y * expansionDist;
+
+ indexBuffer[indexBufferIndex++] = vertexBufferIndex;
+ indexBuffer[indexBufferIndex++] = currentInnerVertexIndex;
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], outerVertex.x,
+ outerVertex.y, OUTER_OPACITY);
+
+ if (j == 0) {
+ outerStart = outerVertex;
+ } else if (j == cornerSlicesNumber) {
+ outerLast = outerVertex;
}
}
- }
+ previousNormal = currentNormal;
+
+ // Edge: first figure out the extra vertices needed for the edge.
+ const Vector3& innerNext = casterVertices[(i + 1) % casterVertexCount];
+ float nextAlpha = getAlphaFromFactoredZ(innerNext.z * heightFactor);
+ if (needsExtraForEdge(currentAlpha, nextAlpha)) {
+ // TODO: See if we can / should cache this outer vertex across the loop.
+ Vector2 outerNext;
+ float expansionDist = innerNext.z * heightFactor * geomFactor;
+ outerNext.x = innerNext.x + currentNormal.x * expansionDist;
+ outerNext.y = innerNext.y + currentNormal.y * expansionDist;
- for (int i = 0; i < rays; i++) {
+ // Compute the angle and see how many extra points we need.
+ int extraVerticesNumber = getEdgeExtraAndUpdateSpike(&currentSpike,
+ innerNext, centroid3d);
#if DEBUG_SHADOW
- ALOGD("No. %d : %f", i, rayThetas[i] * 180 / M_PI);
+ ALOGD("extraVerticesNumber %d for edge %d", extraVerticesNumber, i);
#endif
- // TODO: Fix the intersection precision problem and remvoe the delta added
- // here.
- dir[i].x = cosf(rayThetas[i] + MINIMAL_DELTA_THETA);
- dir[i].y = sinf(rayThetas[i] + MINIMAL_DELTA_THETA);
- }
-}
+ // Edge: fill the edge's VB and IB.
+ // This will create vertices pair from [1, extraVerticesNumber - 1].
+ // If there is no extra vertices created here, the edge will be drawn
+ // as just 2 triangles.
+ for (int k = 1; k < extraVerticesNumber; k++) {
+ int startWeight = extraVerticesNumber - k;
+ Vector2 currentOuter =
+ (outerLast * startWeight + outerNext * k) / extraVerticesNumber;
+ indexBuffer[indexBufferIndex++] = vertexBufferIndex;
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], currentOuter.x,
+ currentOuter.y, OUTER_OPACITY);
-/**
- * Calculate the intersection of a ray hitting the polygon.
- *
- * @param vertices The shadow caster's polygon, which is represented in a
- * Vector3 array.
- * @param vertexCount The length of caster's polygon in terms of number of vertices.
- * @param start The starting point of the ray.
- * @param dir The direction vector of the ray.
- *
- * @param outEdgeIndex Return the index of the segment (or index of the starting
- * vertex) that ray intersect with.
- * @param outEdgeFraction Return the fraction offset from the segment starting
- * index.
- * @param outRayDist Return the ray distance from centroid to the intersection.
- */
-void AmbientShadow::calculateIntersection(const Vector3* vertices, int vertexCount,
- const Vector3& start, const Vector2& dir, int& outEdgeIndex,
- float& outEdgeFraction, float& outRayDist) {
- float startX = start.x;
- float startY = start.y;
- float dirX = dir.x;
- float dirY = dir.y;
- // Start the search from the last edge from poly[len-1] to poly[0].
- int p1 = vertexCount - 1;
-
- for (int p2 = 0; p2 < vertexCount; p2++) {
- float p1x = vertices[p1].x;
- float p1y = vertices[p1].y;
- float p2x = vertices[p2].x;
- float p2y = vertices[p2].y;
-
- // The math here is derived from:
- // f(t, v) = p1x * (1 - t) + p2x * t - (startX + dirX * v) = 0;
- // g(t, v) = p1y * (1 - t) + p2y * t - (startY + dirY * v) = 0;
- float div = (dirX * (p1y - p2y) + dirY * p2x - dirY * p1x);
- if (div != 0) {
- float t = (dirX * (p1y - startY) + dirY * startX - dirY * p1x) / (div);
- if (t > 0 && t <= 1) {
- float t2 = (p1x * (startY - p2y)
- + p2x * (p1y - startY)
- + startX * (p2y - p1y)) / div;
- if (t2 > 0) {
- outEdgeIndex = p1;
- outRayDist = t2;
- outEdgeFraction = t;
- return;
+ if (!isCasterOpaque) {
+ umbraVertices[umbraIndex++] = vertexBufferIndex;
}
+ Vector3 currentInner =
+ (innerStart * startWeight + innerNext * k) / extraVerticesNumber;
+ indexBuffer[indexBufferIndex++] = vertexBufferIndex;
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], currentInner.x,
+ currentInner.y,
+ getTransformedAlphaFromFactoredZ(currentInner.z * heightFactor));
}
}
- p1 = p2;
+ currentAlpha = nextAlpha;
}
- return;
-};
-/**
- * Calculate the normal at the intersection point between a ray and the polygon.
- *
- * @param rays The total number of rays.
- * @param currentRayIndex The index of the ray which the normal is based on.
- * @param dir The array of the all the rays directions.
- * @param rayDist The pre-computed ray distances array.
- *
- * @param normal Return the normal.
- */
-void AmbientShadow::calculateNormal(int rays, int currentRayIndex,
- const Vector2* dir, const float* rayDist, Vector2& normal) {
- int preIndex = (currentRayIndex - 1 + rays) % rays;
- int postIndex = (currentRayIndex + 1) % rays;
- Vector2 p1 = dir[preIndex] * rayDist[preIndex];
- Vector2 p2 = dir[postIndex] * rayDist[postIndex];
-
- // Now the rays are going CW around the poly.
- Vector2 delta = p2 - p1;
- if (delta.length() != 0) {
- delta.normalize();
- // Calculate the normal , which is CCW 90 rotate to the delta.
- normal.x = - delta.y;
- normal.y = delta.x;
+ indexBuffer[indexBufferIndex++] = 1;
+ indexBuffer[indexBufferIndex++] = 0;
+
+ if (!isCasterOpaque) {
+ // Add the centroid as the last one in the vertex buffer.
+ float centroidOpacity =
+ getTransformedAlphaFromFactoredZ(centroid3d.z * heightFactor);
+ int centroidIndex = vertexBufferIndex;
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid3d.x,
+ centroid3d.y, centroidOpacity);
+
+ for (int i = 0; i < umbraIndex; i++) {
+ // Note that umbraVertices[0] is always 0.
+ // So the start and the end of the umbra are using the "0".
+ // And penumbra ended with 0, so a degenerated triangle is formed b/t
+ // the umbra and penumbra.
+ indexBuffer[indexBufferIndex++] = umbraVertices[i];
+ indexBuffer[indexBufferIndex++] = centroidIndex;
+ }
+ indexBuffer[indexBufferIndex++] = 0;
}
+
+ // At the end, update the real index and vertex buffer size.
+ shadowVertexBuffer.updateVertexCount(vertexBufferIndex);
+ shadowVertexBuffer.updateIndexCount(indexBufferIndex);
+
+ checkOverflow(vertexBufferIndex, totalVertexCount, "Vertex Buffer");
+ checkOverflow(indexBufferIndex, totalIndexCount, "Index Buffer");
+ checkOverflow(umbraIndex, totalUmbraCount, "Umbra Buffer");
+
+#if DEBUG_SHADOW
+ for (int i = 0; i < vertexBufferIndex; i++) {
+ ALOGD("vertexBuffer i %d, (%f, %f %f)", i, shadowVertices[i].x, shadowVertices[i].y,
+ shadowVertices[i].alpha);
+ }
+ for (int i = 0; i < indexBufferIndex; i++) {
+ ALOGD("indexBuffer i %d, indexBuffer[i] %d", i, indexBuffer[i]);
+ }
+#endif
}
}; // namespace uirenderer
diff --git a/libs/hwui/AmbientShadow.h b/libs/hwui/AmbientShadow.h
index 68df246..9660dc0 100644
--- a/libs/hwui/AmbientShadow.h
+++ b/libs/hwui/AmbientShadow.h
@@ -28,27 +28,12 @@ namespace uirenderer {
/**
* AmbientShadow is used to calculate the ambient shadow value around a polygon.
- *
- * TODO: calculateIntersection() now is O(N*M), where N is the number of
- * polygon's vertics and M is the number of rays. In fact, by staring tracing
- * the vertex from the previous intersection, the algorithm can be O(N + M);
*/
class AmbientShadow {
public:
static void createAmbientShadow(bool isCasterOpaque, const Vector3* poly,
int polyLength, const Vector3& centroid3d, float heightFactor,
float geomFactor, VertexBuffer& shadowVertexBuffer);
-
-private:
- static void calculateRayDirections(const int rays, const Vector3* vertices,
- const int vertexCount, const Vector3& centroid3d, Vector2* dir);
-
- static void calculateIntersection(const Vector3* poly, int nbVertices,
- const Vector3& start, const Vector2& dir, int& outEdgeIndex,
- float& outEdgeFraction, float& outRayDist);
-
- static void calculateNormal(int rays, int currentRayIndex, const Vector2* dir,
- const float* rayDist, Vector2& normal);
}; // AmbientShadow
}; // namespace uirenderer
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 1c697d5..da65f38 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -95,6 +95,8 @@ void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) {
// Oh boy, we're starting! Man the battle stations!
if (mPlayState == RUNNING) {
transitionToRunning(context);
+ } else if (mPlayState == FINISHED) {
+ callOnFinishedListener(context);
}
}
}
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index bbf0551..0f36c06 100755
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2417,6 +2417,10 @@ status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
} else if (mode == VertexBuffer::kTwoPolyRingShadow) {
mCaches.bindShadowIndicesBuffer();
glDrawElements(GL_TRIANGLE_STRIP, TWO_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
+ } else if (mode == VertexBuffer::kIndices) {
+ mCaches.unbindIndicesBuffer();
+ glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(), GL_UNSIGNED_SHORT,
+ vertexBuffer.getIndices());
}
if (isAA) {
diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h
index 2a9f01c..d033ed9 100644
--- a/libs/hwui/Vector.h
+++ b/libs/hwui/Vector.h
@@ -111,6 +111,23 @@ public:
float y;
float z;
+ Vector3 operator+(const Vector3& v) const {
+ return (Vector3){x + v.x, y + v.y, z + v.z};
+ }
+
+ Vector3 operator-(const Vector3& v) const {
+ return (Vector3){x - v.x, y - v.y, z - v.z};
+ }
+
+ Vector3 operator/(float s) const {
+ return (Vector3){x / s, y / s, z / s};
+ }
+
+ Vector3 operator*(float s) const {
+ return (Vector3){x * s, y * s, z * s};
+ }
+
+
void dump() {
ALOGD("Vector3[%.2f, %.2f, %.2f]", x, y, z);
}
diff --git a/libs/hwui/VertexBuffer.h b/libs/hwui/VertexBuffer.h
index 3837f88..966fa4e 100644
--- a/libs/hwui/VertexBuffer.h
+++ b/libs/hwui/VertexBuffer.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_HWUI_VERTEX_BUFFER_H
#define ANDROID_HWUI_VERTEX_BUFFER_H
+#include "utils/MathUtils.h"
namespace android {
namespace uirenderer {
@@ -26,19 +27,27 @@ public:
enum Mode {
kStandard = 0,
kOnePolyRingShadow = 1,
- kTwoPolyRingShadow = 2
+ kTwoPolyRingShadow = 2,
+ kIndices = 3
};
VertexBuffer()
: mBuffer(0)
+ , mIndices(0)
, mVertexCount(0)
+ , mIndexCount(0)
+ , mAllocatedVertexCount(0)
+ , mAllocatedIndexCount(0)
, mByteCount(0)
, mMode(kStandard)
+ , mReallocBuffer(0)
, mCleanupMethod(NULL)
+ , mCleanupIndexMethod(NULL)
{}
~VertexBuffer() {
if (mCleanupMethod) mCleanupMethod(mBuffer);
+ if (mCleanupIndexMethod) mCleanupIndexMethod(mIndices);
}
/**
@@ -59,6 +68,7 @@ public:
mReallocBuffer = reallocBuffer + vertexCount;
return reallocBuffer;
}
+ mAllocatedVertexCount = vertexCount;
mVertexCount = vertexCount;
mByteCount = mVertexCount * sizeof(TYPE);
mReallocBuffer = mBuffer = (void*)new TYPE[vertexCount];
@@ -69,6 +79,17 @@ public:
}
template <class TYPE>
+ TYPE* allocIndices(int indexCount) {
+ mAllocatedIndexCount = indexCount;
+ mIndexCount = indexCount;
+ mIndices = (void*)new TYPE[indexCount];
+
+ mCleanupIndexMethod = &(cleanup<TYPE>);
+
+ return (TYPE*)mIndices;
+ }
+
+ template <class TYPE>
void copyInto(const VertexBuffer& srcBuffer, float xOffset, float yOffset) {
int verticesToCopy = srcBuffer.getVertexCount();
@@ -103,9 +124,17 @@ public:
}
const void* getBuffer() const { return mBuffer; }
+ const void* getIndices() const { return mIndices; }
const Rect& getBounds() const { return mBounds; }
unsigned int getVertexCount() const { return mVertexCount; }
unsigned int getSize() const { return mByteCount; }
+ unsigned int getIndexCount() const { return mIndexCount; }
+ void updateIndexCount(unsigned int newCount) {
+ mIndexCount = MathUtils::min(newCount, mAllocatedIndexCount);
+ }
+ void updateVertexCount(unsigned int newCount) {
+ newCount = MathUtils::min(newCount, mAllocatedVertexCount);
+ }
Mode getMode() const { return mMode; }
void setBounds(Rect bounds) { mBounds = bounds; }
@@ -127,14 +156,22 @@ private:
}
Rect mBounds;
+
void* mBuffer;
+ void* mIndices;
+
unsigned int mVertexCount;
+ unsigned int mIndexCount;
+ unsigned int mAllocatedVertexCount;
+ unsigned int mAllocatedIndexCount;
unsigned int mByteCount;
+
Mode mMode;
void* mReallocBuffer; // used for multi-allocation
void (*mCleanupMethod)(void*);
+ void (*mCleanupIndexMethod)(void*);
};
}; // namespace uirenderer
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index ecfedf6..491a295 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -314,6 +314,7 @@ void CanvasContext::destroyHardwareResources() {
stopDrawing();
if (mEglManager.hasEglContext()) {
requireGlContext();
+ freePrefetechedLayers();
mRootRenderNode->destroyHardwareResources();
Caches::getInstance().flush(Caches::kFlushMode_Layers);
}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 032f07f..3e8ee93 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -557,12 +557,15 @@ final public class MediaCodec {
int i = 0;
for (Map.Entry<String, Object> entry: formatMap.entrySet()) {
if (entry.getKey().equals(MediaFormat.KEY_AUDIO_SESSION_ID)) {
- // TODO: Wire up as soon as AudioService is ready. Check entry.getValue() for
- // non-integral type.
- // long audioHwSync = audioService.getAudioHwSyncForSession(entry.getValue());
- long audioHwSync = 0;
+ int sessionId = 0;
+ try {
+ sessionId = (Integer)entry.getValue();
+ }
+ catch (Exception e) {
+ throw new IllegalArgumentException("Wrong Session ID Parameter!");
+ }
keys[i] = "audio-hw-sync";
- values[i] = audioHwSync;
+ values[i] = AudioSystem.getAudioHwSyncForSession(sessionId);
} else {
keys[i] = entry.getKey();
values[i] = entry.getValue();
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 711831b..ae8ce4b 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -683,6 +683,7 @@ public final class MediaSession {
*
* @param mediaButtonIntent an intent containing the KeyEvent as an
* extra
+ * @return True if the event was handled, false otherwise.
*/
public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {
if (mSession != null
@@ -695,36 +696,43 @@ public final class MediaSession {
case KeyEvent.KEYCODE_MEDIA_PLAY:
if ((validActions & PlaybackState.ACTION_PLAY) != 0) {
onPlay();
+ return true;
}
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
if ((validActions & PlaybackState.ACTION_PAUSE) != 0) {
onPause();
+ return true;
}
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
onSkipToNext();
+ return true;
}
break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
if ((validActions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0) {
onSkipToPrevious();
+ return true;
}
break;
case KeyEvent.KEYCODE_MEDIA_STOP:
if ((validActions & PlaybackState.ACTION_STOP) != 0) {
onStop();
+ return true;
}
break;
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
if ((validActions & PlaybackState.ACTION_FAST_FORWARD) != 0) {
onFastForward();
+ return true;
}
break;
case KeyEvent.KEYCODE_MEDIA_REWIND:
if ((validActions & PlaybackState.ACTION_REWIND) != 0) {
onRewind();
+ return true;
}
break;
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
@@ -737,8 +745,10 @@ public final class MediaSession {
| PlaybackState.ACTION_PAUSE)) != 0;
if (isPlaying && canPause) {
onPause();
+ return true;
} else if (!isPlaying && canPlay) {
onPlay();
+ return true;
}
break;
}
diff --git a/media/java/android/media/tv/TvContentRating.java b/media/java/android/media/tv/TvContentRating.java
index 0bda2b3..93b40fb 100644
--- a/media/java/android/media/tv/TvContentRating.java
+++ b/media/java/android/media/tv/TvContentRating.java
@@ -126,7 +126,7 @@ import java.util.Objects;
* code snippet:
* </p>
* <pre>
- * String rating = TvContentRating.createRating(
+ * TvContentRating rating = TvContentRating.createRating(
* "com.android.tv",
* "US_TV",
* "US_TV_PG",
@@ -136,7 +136,7 @@ import java.util.Objects;
* <table>
* <tr>
* <th>Constant Value</th>
- * <th>Comment</th>
+ * <th>Description</th>
* </tr>
* <tr>
* <td>com.android.tv</td>
@@ -148,7 +148,7 @@ import java.util.Objects;
* <table>
* <tr>
* <th>Constant Value</th>
- * <th>Comment</th>
+ * <th>Description</th>
* </tr>
* <tr>
* <td>AM_TV_RS</td>
@@ -346,7 +346,7 @@ import java.util.Objects;
* <tr>
* <th>Rating System</th>
* <th>Constant Value</th>
- * <th>Comment</th>
+ * <th>Description</th>
* </tr>
* <tr>
* <td valign="top" rowspan="6">AM_TV_RS</td>
@@ -1419,7 +1419,7 @@ import java.util.Objects;
* <tr>
* <th>Rating System</th>
* <th>Constant Value</th>
- * <th>Comment</th>
+ * <th>Description</th>
* </tr>
* <tr>
* <td valign="top" rowspan="6">NL_TV</td>
diff --git a/packages/DocumentsUI/res/color/item_root_icon.xml b/packages/DocumentsUI/res/color/item_root_icon.xml
new file mode 100644
index 0000000..1374e61
--- /dev/null
+++ b/packages/DocumentsUI/res/color/item_root_icon.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:state_activated="true" android:color="@*android:color/primary_text_default_material_dark" />
+ <item android:state_focused="false" android:state_activated="true" android:color="@*android:color/primary_text_default_material_dark" />
+ <item android:color="@*android:color/secondary_text_material_light" />
+</selector>
diff --git a/packages/DocumentsUI/res/color/item_root_primary_text.xml b/packages/DocumentsUI/res/color/item_root_primary_text.xml
new file mode 100644
index 0000000..7e703fa
--- /dev/null
+++ b/packages/DocumentsUI/res/color/item_root_primary_text.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:state_activated="true" android:color="@*android:color/primary_text_default_material_dark" />
+ <item android:state_focused="false" android:state_activated="true" android:color="@*android:color/primary_text_default_material_dark" />
+ <item android:state_enabled="false" android:alpha="@*android:dimen/disabled_alpha_material_light" android:color="@*android:color/primary_text_default_material_light" />
+ <item android:color="@*android:color/primary_text_default_material_light" />
+</selector>
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_selection_check.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_selection_check.png
new file mode 100644
index 0000000..f3007c2
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_selection_check.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_selection_check.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_selection_check.png
new file mode 100644
index 0000000..16f2ab9
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_selection_check.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_selection_check.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_selection_check.png
new file mode 100644
index 0000000..0885320
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_selection_check.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_selection_check.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_selection_check.png
new file mode 100644
index 0000000..083bbcc
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_selection_check.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_grid_selection_check.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_grid_selection_check.png
new file mode 100644
index 0000000..74b1ca5
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_grid_selection_check.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/item_doc_grid_overlay.xml b/packages/DocumentsUI/res/drawable/item_doc_grid_overlay.xml
new file mode 100644
index 0000000..3fbd25e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/item_doc_grid_overlay.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:state_activated="true" android:drawable="@color/item_doc_grid_overlay_activated" />
+ <item android:state_focused="false" android:state_activated="true" android:drawable="@color/item_doc_grid_overlay_activated" />
+ <item android:state_enabled="false" android:drawable="@color/item_doc_grid_overlay_disabled" />
+ <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/packages/DocumentsUI/res/drawable/item_doc_grid_overlay_icon.xml b/packages/DocumentsUI/res/drawable/item_doc_grid_overlay_icon.xml
new file mode 100644
index 0000000..d40de1e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/item_doc_grid_overlay_icon.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android" android:constantSize="true">
+ <item android:state_focused="true" android:state_activated="true" android:drawable="@drawable/ic_grid_selection_check" />
+ <item android:state_focused="false" android:state_activated="true" android:drawable="@drawable/ic_grid_selection_check" />
+ <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/packages/DocumentsUI/res/drawable/item_activated_overlay.xml b/packages/DocumentsUI/res/drawable/item_doc_list_background.xml
index 83e4d7e..b879542 100644
--- a/packages/DocumentsUI/res/drawable/item_activated_overlay.xml
+++ b/packages/DocumentsUI/res/drawable/item_doc_list_background.xml
@@ -15,11 +15,7 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="true" android:state_activated="true">
- <color android:color="@color/accent_color_overlay" />
- </item>
- <item android:state_focused="false" android:state_activated="true">
- <color android:color="@color/accent_color_overlay" />
- </item>
+ <item android:state_focused="true" android:state_activated="true" android:drawable="@color/item_doc_list_background_activated" />
+ <item android:state_focused="false" android:state_activated="true" android:drawable="@color/item_doc_list_background_activated" />
<item android:drawable="@android:color/transparent" />
</selector>
diff --git a/packages/DocumentsUI/res/drawable/item_activated.xml b/packages/DocumentsUI/res/drawable/item_root_background.xml
index 1b3f44a..1b3f44a 100644
--- a/packages/DocumentsUI/res/drawable/item_activated.xml
+++ b/packages/DocumentsUI/res/drawable/item_root_background.xml
diff --git a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
index 95af7e9..d124320 100644
--- a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
@@ -17,7 +17,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/item_activated">
+ android:background="@drawable/item_doc_list_background">
<LinearLayout
android:layout_width="match_parent"
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index bdb3184..d62d050 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -17,9 +17,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/grid_item_height"
- android:orientation="vertical"
- android:background="@color/grid_item_background"
- android:foreground="@drawable/item_activated_overlay">
+ android:background="@color/item_doc_grid_background">
<ImageView
android:id="@+id/icon_thumb"
@@ -44,7 +42,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/grid_protect_background"
+ android:background="@color/item_doc_grid_protect_background"
android:orientation="vertical"
android:paddingStart="16dp"
android:paddingEnd="12dp"
@@ -68,7 +66,7 @@
android:ellipsize="middle"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
- android:textColor="?android:attr/textColorPrimaryInverse" />
+ android:textColor="@*android:color/primary_text_default_material_dark" />
<ImageView
android:id="@android:id/icon1"
@@ -97,7 +95,7 @@
android:ellipsize="end"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Caption"
- android:textColor="?android:attr/textColorPrimaryInverse" />
+ android:textColor="@*android:color/primary_text_default_material_dark" />
<TextView
android:id="@+id/size"
@@ -109,7 +107,7 @@
android:ellipsize="end"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Caption"
- android:textColor="?android:attr/textColorPrimaryInverse" />
+ android:textColor="@*android:color/primary_text_default_material_dark" />
<ImageView
android:id="@android:id/icon2"
@@ -126,4 +124,19 @@
</LinearLayout>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:src="@drawable/item_doc_grid_overlay"
+ android:contentDescription="@null"
+ android:duplicateParentState="true" />
+
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:src="@drawable/item_doc_grid_overlay_icon"
+ android:scaleType="center"
+ android:contentDescription="@null"
+ android:duplicateParentState="true" />
+
</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index c5f1842..c576669 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -17,7 +17,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/item_activated">
+ android:background="@drawable/item_doc_list_background">
<LinearLayout
android:layout_width="match_parent"
diff --git a/packages/DocumentsUI/res/layout/item_root.xml b/packages/DocumentsUI/res/layout/item_root.xml
index 266b9b0..bd83923 100644
--- a/packages/DocumentsUI/res/layout/item_root.xml
+++ b/packages/DocumentsUI/res/layout/item_root.xml
@@ -23,19 +23,21 @@
android:gravity="center_vertical"
android:orientation="horizontal"
android:baselineAligned="false"
- android:background="@drawable/item_activated">
+ android:background="@drawable/item_root_background">
<FrameLayout
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
- android:layout_marginEnd="16dp">
+ android:layout_marginEnd="16dp"
+ android:duplicateParentState="true">
<ImageView
android:id="@android:id/icon"
android:layout_width="@dimen/root_icon_size"
android:layout_height="match_parent"
android:scaleType="centerInside"
- android:contentDescription="@null" />
+ android:contentDescription="@null"
+ android:duplicateParentState="true" />
</FrameLayout>
@@ -54,7 +56,7 @@
android:ellipsize="end"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="?android:attr/textColorPrimary" />
+ android:textColor="@color/item_root_primary_text" />
<TextView
android:id="@android:id/summary"
@@ -64,7 +66,7 @@
android:ellipsize="end"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="?android:attr/textColorSecondary" />
+ android:textColor="@color/item_root_primary_text" />
</LinearLayout>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index 7442b09..2ceb968 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -18,8 +18,16 @@
<color name="material_grey_50">#fffafafa</color>
<color name="material_grey_300">#ffeeeeee</color>
- <!-- Half-alpha of material_teal_500 -->
- <color name="accent_color_overlay">#8800bcd4</color>
+ <color name="item_doc_grid_background">@color/material_grey_300</color>
+
+ <color name="item_doc_grid_protect_background">#88000000</color>
+
+ <color name="item_doc_grid_overlay_activated">#88000000</color>
+ <color name="item_doc_grid_overlay_disabled">#88ffffff</color>
+
+ <color name="item_doc_list_overlay_disabled">#88ffffff</color>
+
+ <!-- 10% alpha of material_deep_teal_500 -->
+ <color name="item_doc_list_background_activated">#1a009688</color>
- <color name="grid_item_background">@color/material_grey_300</color>
</resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index 5cfe046..7693da3 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -28,6 +28,7 @@
<item name="android:colorAccent">@*android:color/material_deep_teal_500</item>
<item name="android:windowActionBar">false</item>
+ <item name="android:windowActionModeOverlay">true</item>
<item name="android:windowNoTitle">true</item>
<item name="*android:windowFixedWidthMajor">@null</item>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index caa07ab..39c2252 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -807,6 +807,9 @@ public class DirectoryFragment extends Fragment {
|| MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, docMimeType);
final boolean showThumbnail = supportsThumbnail && allowThumbnail && !mSvelteRecents;
+ final boolean enabled = isDocumentEnabled(docMimeType, docFlags);
+ final float iconAlpha = (state.derivedMode == MODE_LIST && !enabled) ? 0.5f : 1f;
+
boolean cacheHit = false;
if (showThumbnail) {
final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
@@ -817,7 +820,7 @@ public class DirectoryFragment extends Fragment {
} else {
iconThumb.setImageDrawable(null);
final ThumbnailAsyncTask task = new ThumbnailAsyncTask(
- uri, iconMime, iconThumb, mThumbSize);
+ uri, iconMime, iconThumb, mThumbSize, iconAlpha);
iconThumb.setTag(task);
ProviderExecutor.forAuthority(docAuthority).execute(task);
}
@@ -886,7 +889,7 @@ public class DirectoryFragment extends Fragment {
// hint to remind user they're a directory.
if (Document.MIME_TYPE_DIR.equals(docMimeType) && state.derivedMode == MODE_GRID
&& showThumbnail) {
- iconDrawable = IconUtils.applyTint(context, R.drawable.ic_doc_folder,
+ iconDrawable = IconUtils.applyTintAttr(context, R.drawable.ic_doc_folder,
android.R.attr.textColorPrimaryInverse);
}
@@ -940,20 +943,12 @@ public class DirectoryFragment extends Fragment {
line2.setVisibility(hasLine2 ? View.VISIBLE : View.GONE);
}
- final boolean enabled = isDocumentEnabled(docMimeType, docFlags);
- if (enabled) {
- setEnabledRecursive(convertView, true);
- iconMime.setAlpha(1f);
- iconThumb.setAlpha(1f);
- if (icon1 != null) icon1.setAlpha(1f);
- if (icon2 != null) icon2.setAlpha(1f);
- } else {
- setEnabledRecursive(convertView, false);
- iconMime.setAlpha(0.5f);
- iconThumb.setAlpha(0.5f);
- if (icon1 != null) icon1.setAlpha(0.5f);
- if (icon2 != null) icon2.setAlpha(0.5f);
- }
+ setEnabledRecursive(convertView, enabled);
+
+ iconMime.setAlpha(iconAlpha);
+ iconThumb.setAlpha(iconAlpha);
+ if (icon1 != null) icon1.setAlpha(iconAlpha);
+ if (icon2 != null) icon2.setAlpha(iconAlpha);
return convertView;
}
@@ -1000,14 +995,16 @@ public class DirectoryFragment extends Fragment {
private final ImageView mIconMime;
private final ImageView mIconThumb;
private final Point mThumbSize;
+ private final float mTargetAlpha;
private final CancellationSignal mSignal;
- public ThumbnailAsyncTask(
- Uri uri, ImageView iconMime, ImageView iconThumb, Point thumbSize) {
+ public ThumbnailAsyncTask(Uri uri, ImageView iconMime, ImageView iconThumb, Point thumbSize,
+ float targetAlpha) {
mUri = uri;
mIconMime = iconMime;
mIconThumb = iconThumb;
mThumbSize = thumbSize;
+ mTargetAlpha = targetAlpha;
mSignal = new CancellationSignal();
}
@@ -1051,11 +1048,10 @@ public class DirectoryFragment extends Fragment {
mIconThumb.setTag(null);
mIconThumb.setImageBitmap(result);
- final float targetAlpha = mIconMime.isEnabled() ? 1f : 0.5f;
- mIconMime.setAlpha(targetAlpha);
+ mIconMime.setAlpha(mTargetAlpha);
mIconMime.animate().alpha(0f).start();
mIconThumb.setAlpha(0f);
- mIconThumb.animate().alpha(targetAlpha).start();
+ mIconThumb.animate().alpha(mTargetAlpha).start();
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index b2e38fc..416aeb0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -266,15 +266,16 @@ public class IconUtils {
}
}
- public static Drawable applyTint(Context context, int drawableId, int tintAttrId) {
- final Resources res = context.getResources();
-
- final TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(tintAttrId, outValue, true);
-
+ public static Drawable applyTintColor(Context context, int drawableId, int tintColorId) {
final Drawable icon = context.getDrawable(drawableId);
icon.mutate();
- icon.setTintList(res.getColorStateList(outValue.resourceId));
+ icon.setTintList(context.getResources().getColorStateList(tintColorId));
return icon;
}
+
+ public static Drawable applyTintAttr(Context context, int drawableId, int tintAttrId) {
+ final TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(tintAttrId, outValue, true);
+ return applyTintColor(context, drawableId, outValue.resourceId);
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index a465ecd..f81690a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -58,7 +58,7 @@ import java.util.concurrent.TimeUnit;
* Cache of known storage backends and their roots.
*/
public class RootsCache {
- private static final boolean LOGD = true;
+ private static final boolean LOGD = false;
public static final Uri sNotificationUri = Uri.parse(
"content://com.android.documentsui.roots/");
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index b19e028..884cf31 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -235,7 +235,7 @@ public class RootsFragment extends Fragment {
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
final Context context = convertView.getContext();
- icon.setImageDrawable(root.loadIcon(context));
+ icon.setImageDrawable(root.loadDrawerIcon(context));
title.setText(root.title);
// Show available space if no summary
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index fcfe518..97d8ed0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -211,9 +211,17 @@ public class RootInfo implements Durable, Parcelable {
}
}
+ public Drawable loadDrawerIcon(Context context) {
+ if (derivedIcon != 0) {
+ return IconUtils.applyTintColor(context, derivedIcon, R.color.item_root_icon);
+ } else {
+ return IconUtils.loadPackageIcon(context, authority, icon);
+ }
+ }
+
public Drawable loadGridIcon(Context context) {
if (derivedIcon != 0) {
- return IconUtils.applyTint(context, derivedIcon,
+ return IconUtils.applyTintAttr(context, derivedIcon,
android.R.attr.textColorPrimaryInverse);
} else {
return IconUtils.loadPackageIcon(context, authority, icon);
@@ -222,7 +230,7 @@ public class RootInfo implements Durable, Parcelable {
public Drawable loadToolbarIcon(Context context) {
if (derivedIcon != 0) {
- return IconUtils.applyTint(context, derivedIcon,
+ return IconUtils.applyTintAttr(context, derivedIcon,
android.R.attr.colorControlNormal);
} else {
return IconUtils.loadPackageIcon(context, authority, icon);
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 299e50c..a3bed4f 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -187,6 +187,9 @@
<!-- Default for Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1==on -->
<integer name="def_lock_screen_show_notifications">1</integer>
+ <!-- Default for Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS -->
+ <bool name="def_lock_screen_allow_private_notifications">true</bool>
+
<!-- Default for Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 1==on -->
<integer name="def_heads_up_enabled">1</integer>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index edefb13..fd5e6fe 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -70,7 +70,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 108;
+ private static final int DATABASE_VERSION = 109;
private Context mContext;
private int mUserHandle;
@@ -1673,8 +1673,8 @@ public class DatabaseHelper extends SQLiteOpenHelper {
try {
stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+ " VALUES(?,?);");
- loadBooleanSetting(stmt, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
- R.bool.def_guest_user_enabled);
+ loadIntegerSetting(stmt, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ R.integer.def_lock_screen_show_notifications);
if (mUserHandle == UserHandle.USER_OWNER) {
final int oldShow = getIntValueFromTable(db,
TABLE_GLOBAL, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, -1);
@@ -1733,6 +1733,22 @@ public class DatabaseHelper extends SQLiteOpenHelper {
upgradeVersion = 108;
}
+ if (upgradeVersion < 109) {
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ try {
+ stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+ + " VALUES(?,?);");
+ loadBooleanSetting(stmt, Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ R.bool.def_lock_screen_allow_private_notifications);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (stmt != null) stmt.close();
+ }
+ upgradeVersion = 109;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
@@ -2301,6 +2317,9 @@ public class DatabaseHelper extends SQLiteOpenHelper {
loadIntegerSetting(stmt, Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
R.integer.def_lock_screen_show_notifications);
+ loadBooleanSetting(stmt, Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ R.bool.def_lock_screen_allow_private_notifications);
+
} finally {
if (stmt != null) stmt.close();
}
diff --git a/packages/SystemUI/res/drawable/ic_android.xml b/packages/SystemUI/res/drawable/ic_android.xml
new file mode 100644
index 0000000..19ee9a7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_android.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M6.000000,18.000000c0.000000,0.600000 0.400000,1.000000 1.000000,1.000000l1.000000,0.000000l0.000000,3.500000C8.000000,23.299999 8.700000,24.000000 9.500000,24.000000c0.800000,0.000000 1.500000,-0.700000 1.500000,-1.500000L11.000000,19.000000l2.000000,0.000000l0.000000,3.500000c0.000000,0.800000 0.700000,1.500000 1.500000,1.500000c0.800000,0.000000 1.500000,-0.700000 1.500000,-1.500000L16.000000,19.000000l1.000000,0.000000c0.600000,0.000000 1.000000,-0.400000 1.000000,-1.000000L18.000000,8.000000L6.000000,8.000000L6.000000,18.000000zM3.500000,8.000000C2.700000,8.000000 2.000000,8.700000 2.000000,9.500000l0.000000,7.000000C2.000000,17.299999 2.700000,18.000000 3.500000,18.000000C4.300000,18.000000 5.000000,17.299999 5.000000,16.500000l0.000000,-7.000000C5.000000,8.700000 4.300000,8.000000 3.500000,8.000000zM20.500000,8.000000C19.700001,8.000000 19.000000,8.700000 19.000000,9.500000l0.000000,7.000000c0.000000,0.800000 0.700000,1.500000 1.500000,1.500000c0.800000,0.000000 1.500000,-0.700000 1.500000,-1.500000l0.000000,-7.000000C22.000000,8.700000 21.299999,8.000000 20.500000,8.000000zM15.500000,2.200000l1.300000,-1.300000c0.200000,-0.200000 0.200000,-0.500000 0.000000,-0.700000c-0.200000,-0.200000 -0.500000,-0.200000 -0.700000,0.000000l-1.500000,1.500000C13.900000,1.200000 13.000000,1.000000 12.000000,1.000000c-1.000000,0.000000 -1.900000,0.200000 -2.700000,0.600000L7.900000,0.100000C7.700000,0.000000 7.300000,0.000000 7.100000,0.100000C7.000000,0.300000 7.000000,0.700000 7.100000,0.900000l1.300000,1.300000C7.000000,3.300000 6.000000,5.000000 6.000000,7.000000l12.000000,0.000000C18.000000,5.000000 17.000000,3.200000 15.500000,2.200000zM10.000000,5.000000L9.000000,5.000000L9.000000,4.000000l1.000000,0.000000L10.000000,5.000000zM15.000000,5.000000l-1.000000,0.000000L14.000000,4.000000l1.000000,0.000000L15.000000,5.000000z"
+ android:fillColor="#ffffffff"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_close.xml b/packages/SystemUI/res/drawable/ic_close.xml
new file mode 100644
index 0000000..7d93d45
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_close.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
+ android:fillColor="#FF000000"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index ef0c9bb..ca07c87 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -67,6 +67,6 @@
android:src="@drawable/ic_lock_24dp"
android:scaleType="center"
android:tint="#ffffffff"
- android:contentDescription="@string/accessibility_unlock_button_not_secured" />
+ android:contentDescription="@string/accessibility_unlock_button" />
</com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index eff3758..351177b 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -38,8 +38,8 @@
android:id="@+id/more_text"
android:layout_width="32dp"
android:layout_height="32dp"
- android:layout_marginStart="20dp"
- android:layout_marginEnd="16dp"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="12dp"
android:layout_gravity="center_vertical"
android:background="@drawable/keyguard_overflow_number_background"
android:gravity="center"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b000a48..b488c56 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -213,6 +213,8 @@
<string name="accessibility_camera_button">Camera</string>
<!-- Content description of the phone button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_phone_button">Phone</string>
+ <!-- Content description of the unlock button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_unlock_button">Unlock</string>
<!-- Click action label for accessibility for the unlock button. [CHAR LIMIT=NONE] -->
<string name="unlock_label">unlock</string>
<!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] -->
@@ -220,17 +222,6 @@
<!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] -->
<string name="camera_label">open camera</string>
- <!-- Content description of the lock icon when device is secured (lock closed) and trust not managed (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_unlock_button_secured">Device secured.</string>
- <!-- Content description of the lock icon when device is not secured (lock open) and trust not managed (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_unlock_button_not_secured">Device not secured.</string>
- <!-- Content description of the lock icon when device is secured (lock closed) and trust managed (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_unlock_button_secured_trust_managed">Device secured, trust agent active.</string>
- <!-- Content description of the lock icon when device is not secured (lock open) and trust managed (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_unlock_button_not_secured_trust_managed">Device not secured, trust agent active.</string>
- <!-- Content description of the lock icon when face unlock is running (face icon) and trust managed (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_unlock_button_face_unlock_running">Face detection running, trust agent active.</string>
-
<!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_ime_switch_button">Switch input method button.</string>
<!-- Content description of the compatibility zoom button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -323,6 +314,15 @@
<!-- Content description of an item with full signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_signal_full">Signal full.</string>
+ <!-- Content description of an item that is turned on for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_desc_on">On.</string>
+ <!-- Content description of an item that is turned off for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_desc_off">Off.</string>
+ <!-- Content description of an item that is connected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_desc_connected">Connected.</string>
+ <!-- Content description of an item that is connecting for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_desc_connecting">Connecting.</string>
+
<!-- Content description of the data connection type GPRS for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_data_connection_gprs">GPRS</string>
@@ -894,6 +894,18 @@
<!-- Indication on the keyguard that appears when the user disables trust agents until the next time they unlock manually. [CHAR LIMIT=NONE] -->
<string name="keyguard_indication_trust_disabled">Device will stay locked until you manually unlock</string>
+ <!-- Title of notification educating the user about enabling notifications on the lockscreen. [CHAR LIMIT=40] -->
+ <string name="hidden_notifications_title">Get notifications faster</string>
+
+ <!-- Body of notification educating the user about enabling notifications on the lockscreen. [CHAR LIMIT=60] -->
+ <string name="hidden_notifications_text">See them before you unlock</string>
+
+ <!-- Cancel action for notification educating the user about enabling notifications on the lockscreen. [CHAR LIMIT=10] -->
+ <string name="hidden_notifications_cancel">No thanks</string>
+
+ <!-- continue action for notification educating the user about enabling notifications on the lockscreen. [CHAR LIMIT=10] -->
+ <string name="hidden_notifications_setup">Set up</string>
+
<!-- Indication that the current volume and other effects (vibration) are being suppressed by a third party, such as a notification listener. [CHAR LIMIT=30] -->
<string name="muted_by">Muted by <xliff:g id="third_party">%1$s</xliff:g></string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 1ac3bc3..0c6e7b6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -67,6 +67,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
ArrayList<TaskStack> mStacks;
View mSearchBar;
RecentsViewCallbacks mCb;
+ boolean mAlreadyLaunchingTask;
public RecentsView(Context context) {
super(context);
@@ -120,6 +121,9 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
}
addView(stackView);
}
+
+ // Reset the launched state
+ mAlreadyLaunchingTask = false;
}
/** Removes all the task stack views from this recents view. */
@@ -381,6 +385,11 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
if (mCb != null) {
mCb.onTaskViewClicked();
}
+ // Skip if we are already launching tasks
+ if (mAlreadyLaunchingTask) {
+ return;
+ }
+ mAlreadyLaunchingTask = true;
// Upfront the processing of the thumbnail
TaskViewTransform transform = new TaskViewTransform();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index c8adf61..f04c8c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -22,6 +22,7 @@ import android.animation.TimeInterpolator;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.Notification;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.app.admin.DevicePolicyManager;
@@ -35,7 +36,11 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.database.ContentObserver;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
@@ -78,6 +83,7 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
import com.android.internal.util.NotificationColorUtil;
+import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SearchPanelView;
@@ -126,6 +132,12 @@ public abstract class BaseStatusBar extends SystemUI implements
public static final int EXPANDED_LEAVE_ALONE = -10000;
public static final int EXPANDED_FULL_OPEN = -10001;
+ private static final int HIDDEN_NOTIFICATION_ID = 10000;
+ private static final String BANNER_ACTION_CANCEL =
+ "com.android.systemui.statusbar.banner_action_cancel";
+ private static final String BANNER_ACTION_SETUP =
+ "com.android.systemui.statusbar.banner_action_setup";
+
protected CommandQueue mCommandQueue;
protected IStatusBarService mBarService;
protected H mHandler = createHandler();
@@ -308,6 +320,20 @@ public abstract class BaseStatusBar extends SystemUI implements
mUsersAllowingPrivateNotifications.clear();
updateLockscreenNotificationSetting();
updateNotifications();
+ } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
+ NotificationManager noMan = (NotificationManager)
+ mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ noMan.cancel(HIDDEN_NOTIFICATION_ID);
+
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
+ if (BANNER_ACTION_SETUP.equals(action)) {
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
+ mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ );
+ }
}
}
};
@@ -490,12 +516,61 @@ public abstract class BaseStatusBar extends SystemUI implements
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
+ filter.addAction(BANNER_ACTION_CANCEL);
+ filter.addAction(BANNER_ACTION_SETUP);
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
mContext.registerReceiver(mBroadcastReceiver, filter);
updateCurrentProfilesCache();
}
+ protected void notifyUserAboutHiddenNotifications() {
+ if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
+ Log.d(TAG, "user hasn't seen notification about hidden notifications");
+ final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
+ if (!lockPatternUtils.isSecure()) {
+ Log.d(TAG, "insecure lockscreen, skipping notification");
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
+ return;
+ }
+ Log.d(TAG, "disabling lockecreen notifications and alerting the user");
+ // disable lockscreen notifications until user acts on the banner.
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
+
+ final String packageName = mContext.getPackageName();
+ PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0,
+ new Intent(BANNER_ACTION_CANCEL).setPackage(packageName),
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ PendingIntent setupIntent = PendingIntent.getBroadcast(mContext, 0,
+ new Intent(BANNER_ACTION_SETUP).setPackage(packageName),
+ PendingIntent.FLAG_CANCEL_CURRENT);
+
+ final Resources res = mContext.getResources();
+ final int colorRes = com.android.internal.R.color.system_notification_accent_color;
+ Notification.Builder note = new Notification.Builder(mContext)
+ .setSmallIcon(R.drawable.ic_android)
+ .setContentTitle(mContext.getString(R.string.hidden_notifications_title))
+ .setContentText(mContext.getString(R.string.hidden_notifications_text))
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setOngoing(true)
+ .setColor(res.getColor(colorRes))
+ .setContentIntent(setupIntent)
+ .addAction(R.drawable.ic_close,
+ mContext.getString(R.string.hidden_notifications_cancel),
+ cancelIntent)
+ .addAction(R.drawable.ic_settings,
+ mContext.getString(R.string.hidden_notifications_setup),
+ setupIntent);
+
+ NotificationManager noMan =
+ (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ noMan.notify(HIDDEN_NOTIFICATION_ID, note.build());
+ }
+ }
+
public void userSwitched(int newUserId) {
// should be overridden
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 62552b2..f9da30f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -380,21 +380,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mLockIcon.setImageResource(iconRes);
boolean trustManaged = mUnlockMethodCache.isTrustManaged();
mTrustDrawable.setTrustManaged(trustManaged);
-
updateLockIconClickability();
- updateLockIconContentDescription(mUnlockMethodCache.isFaceUnlockRunning(),
- mUnlockMethodCache.isMethodInsecure(), trustManaged);
}
- private void updateLockIconContentDescription(boolean faceUnlockRunning, boolean insecure,
- boolean trustManaged) {
- mLockIcon.setContentDescription(getResources().getString(
- faceUnlockRunning ? R.string.accessibility_unlock_button_face_unlock_running
- : insecure && !trustManaged ? R.string.accessibility_unlock_button_not_secured
- : insecure ? R.string.accessibility_unlock_button_not_secured_trust_managed
- : !trustManaged ? R.string.accessibility_unlock_button_secured
- : R.string.accessibility_unlock_button_secured_trust_managed));
- }
+
public KeyguardAffordanceView getPhoneView() {
return mPhoneImageView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 9fd3d9c..1a0d2d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -582,6 +582,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
putComponent(PhoneStatusBar.class, this);
setControllerUsers();
+
+ notifyUserAboutHiddenNotifications();
}
// ================================================================================
@@ -3612,7 +3614,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
public boolean onSpacePressed() {
- if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
+ if (mScreenOn != null && mScreenOn
+ && (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
animateCollapsePanels(0 /* flags */, true /* force */);
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index f03c5eb..12c887e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -26,7 +26,6 @@ import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -46,7 +45,6 @@ import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
-import android.provider.Settings.Global;
import android.util.Log;
import android.util.SparseArray;
import android.view.KeyEvent;
@@ -58,6 +56,7 @@ import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
+import android.view.accessibility.AccessibilityManager;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
@@ -97,6 +96,7 @@ public class VolumePanel extends Handler {
private static final int TIMEOUT_DELAY_SHORT = 1500;
private static final int TIMEOUT_DELAY_COLLAPSED = 4500;
private static final int TIMEOUT_DELAY_SAFETY_WARNING = 5000;
+ private static final int TIMEOUT_DELAY_SAFETY_WARNING_TALKBACK = 25000;
private static final int TIMEOUT_DELAY_EXPANDED = 10000;
private static final int MSG_VOLUME_CHANGED = 0;
@@ -161,6 +161,7 @@ public class VolumePanel extends Handler {
private int mActiveStreamType = -1;
/** All the slider controls mapped by stream type */
private SparseArray<StreamControl> mStreamControls;
+ private final AccessibilityManager mAccessibilityManager;
private enum StreamResources {
BluetoothSCOStream(AudioManager.STREAM_BLUETOOTH_SCO,
@@ -332,6 +333,8 @@ public class VolumePanel extends Handler {
mContext = context;
mZenController = zenController;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mAccessibilityManager = (AccessibilityManager) context.getSystemService(
+ Context.ACCESSIBILITY_SERVICE);
// For now, only show master volume if master volume is supported
final Resources res = context.getResources();
@@ -791,7 +794,8 @@ public class VolumePanel extends Handler {
}
private void updateTimeoutDelay() {
- mTimeoutDelay = sSafetyWarning != null ? TIMEOUT_DELAY_SAFETY_WARNING
+ mTimeoutDelay = sSafetyWarning != null ? mAccessibilityManager.isEnabled() ?
+ TIMEOUT_DELAY_SAFETY_WARNING_TALKBACK : TIMEOUT_DELAY_SAFETY_WARNING
: mActiveStreamType == AudioManager.STREAM_MUSIC ? TIMEOUT_DELAY_SHORT
: mZenPanelExpanded ? TIMEOUT_DELAY_EXPANDED
: isZenPanelVisible() ? TIMEOUT_DELAY_COLLAPSED
@@ -1214,6 +1218,7 @@ public class VolumePanel extends Handler {
}
updateStates();
}
+ updateTimeoutDelay();
resetTimeout();
}
diff --git a/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java b/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java
index 71b0d53..6f79f58 100644
--- a/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java
+++ b/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java
@@ -83,6 +83,7 @@ public class EnableAccessibilityController {
private final Context mContext;
+ private final Runnable mOnAccessibilityEnabledCallback;
private final UserManager mUserManager;
private final TextToSpeech mTts;
private final Ringtone mTone;
@@ -97,8 +98,9 @@ public class EnableAccessibilityController {
private float mSecondPointerDownX;
private float mSecondPointerDownY;
- public EnableAccessibilityController(Context context) {
+ public EnableAccessibilityController(Context context, Runnable onAccessibilityEnabledCallback) {
mContext = context;
+ mOnAccessibilityEnabledCallback = onAccessibilityEnabledCallback;
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mTts = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
@Override
@@ -275,5 +277,7 @@ public class EnableAccessibilityController {
/* ignore */
}
}
+
+ mOnAccessibilityEnabledCallback.run();
}
}
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index ae94654..41695c1 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -1073,7 +1073,13 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
// is dismissed on the first down while the global gesture is a long press
// with two fingers anywhere on the screen.
if (EnableAccessibilityController.canEnableAccessibilityViaGesture(mContext)) {
- mEnableAccessibilityController = new EnableAccessibilityController(mContext);
+ mEnableAccessibilityController = new EnableAccessibilityController(mContext,
+ new Runnable() {
+ @Override
+ public void run() {
+ dismiss();
+ }
+ });
super.setCanceledOnTouchOutside(false);
} else {
mEnableAccessibilityController = null;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index a13da609..93591a9 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -2754,11 +2754,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mStatusColorView = updateColorViewInt(mStatusColorView,
SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
mStatusBarColor, mLastTopInset, Gravity.TOP,
- STATUS_BAR_BACKGROUND_TRANSITION_NAME);
+ STATUS_BAR_BACKGROUND_TRANSITION_NAME,
+ com.android.internal.R.id.statusBarBackground);
mNavigationColorView = updateColorViewInt(mNavigationColorView,
SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
mNavigationBarColor, mLastBottomInset, Gravity.BOTTOM,
- NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME);
+ NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
+ com.android.internal.R.id.navigationBarBackground);
}
if (insets != null) {
insets = insets.consumeStableInsets();
@@ -2767,7 +2769,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
private View updateColorViewInt(View view, int systemUiHideFlag, int translucentFlag,
- int color, int height, int verticalGravity, String transitionName) {
+ int color, int height, int verticalGravity, String transitionName, int id) {
boolean show = height > 0 && (mLastSystemUiVisibility & systemUiHideFlag) == 0
&& (getAttributes().flags & translucentFlag) == 0
&& (color & Color.BLACK) != 0
@@ -2778,6 +2780,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
view = new View(mContext);
view.setBackgroundColor(color);
view.setTransitionName(transitionName);
+ view.setId(id);
addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, height,
Gravity.START | verticalGravity));
}
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index ac0ca0a..af5c13d 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -708,6 +708,7 @@ class TouchExplorer implements EventStreamTransformation {
// Send an event to the end of the drag gesture.
sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
}
+ mCurrentState = STATE_TOUCH_EXPLORING;
} break;
case MotionEvent.ACTION_UP: {
mAms.onTouchInteractionEnd();
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 86ce961..92f5170 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -16,9 +16,12 @@
package com.android.server;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
@@ -31,6 +34,7 @@ import android.database.sqlite.SQLiteStatement;
import android.os.Binder;
import android.os.Environment;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.storage.IMountService;
import android.os.ServiceManager;
@@ -41,11 +45,14 @@ import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.provider.Settings.SettingNotFoundException;
+import android.security.KeyChain;
+import android.security.KeyChain.KeyChainConnection;
import android.security.KeyStore;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.ILockSettingsObserver;
import com.android.internal.widget.LockPatternUtils;
@@ -99,8 +106,30 @@ public class LockSettingsService extends ILockSettings.Stub {
mLockPatternUtils = new LockPatternUtils(context);
mFirstCallToVold = true;
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_ADDED);
+ mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
}
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Update keystore settings for profiles which use the same password as their parent
+ if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
+ final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+ final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+ final UserInfo parentInfo = um.getProfileParent(userHandle);
+ if (parentInfo != null) {
+ final KeyStore ks = KeyStore.getInstance();
+ final int profileUid = UserHandle.getUid(userHandle, Process.SYSTEM_UID);
+ final int parentUid = UserHandle.getUid(parentInfo.id, Process.SYSTEM_UID);
+ ks.syncUid(parentUid, profileUid);
+ }
+ }
+ }
+ };
+
public void systemReady() {
migrateOldData();
}
@@ -275,6 +304,17 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
+ private int getUserParentOrSelfId(int userId) {
+ if (userId != 0) {
+ final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+ final UserInfo pi = um.getProfileParent(userId);
+ if (pi != null) {
+ return pi.id;
+ }
+ }
+ return userId;
+ }
+
private String getLockPatternFilename(int userId) {
String dataSystemDirectory =
android.os.Environment.getDataDirectory().getAbsolutePath() +
@@ -283,6 +323,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// Leave it in the same place for user 0
return dataSystemDirectory + LOCK_PATTERN_FILE;
} else {
+ userId = getUserParentOrSelfId(userId);
return new File(Environment.getUserSystemDirectory(userId), LOCK_PATTERN_FILE)
.getAbsolutePath();
}
@@ -296,7 +337,8 @@ public class LockSettingsService extends ILockSettings.Stub {
// Leave it in the same place for user 0
return dataSystemDirectory + LOCK_PASSWORD_FILE;
} else {
- return new File(Environment.getUserSystemDirectory(userId), LOCK_PASSWORD_FILE)
+ userId = getUserParentOrSelfId(userId);
+ return new File(Environment.getUserSystemDirectory(userId), LOCK_PASSWORD_FILE)
.getAbsolutePath();
}
}
@@ -315,16 +357,27 @@ public class LockSettingsService extends ILockSettings.Stub {
return new File(getLockPatternFilename(userId)).length() > 0;
}
- private void maybeUpdateKeystore(String password, int userId) {
- if (userId == UserHandle.USER_OWNER) {
- final KeyStore keyStore = KeyStore.getInstance();
- // Conditionally reset the keystore if empty. If non-empty, we are just
- // switching key guard type
- if (TextUtils.isEmpty(password) && keyStore.isEmpty()) {
- keyStore.reset();
+ private void maybeUpdateKeystore(String password, int userHandle) {
+ final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+ final KeyStore ks = KeyStore.getInstance();
+
+ final List<UserInfo> profiles = um.getProfiles(userHandle);
+ boolean shouldReset = TextUtils.isEmpty(password);
+
+ // For historical reasons, don't wipe a non-empty keystore if we have a single user with a
+ // single profile.
+ if (userHandle == UserHandle.USER_OWNER && profiles.size() == 1) {
+ if (!ks.isEmpty()) {
+ shouldReset = false;
+ }
+ }
+
+ for (UserInfo pi : profiles) {
+ final int profileUid = UserHandle.getUid(pi.id, Process.SYSTEM_UID);
+ if (shouldReset) {
+ ks.resetUid(profileUid);
} else {
- // Update the keystore password
- keyStore.password(password);
+ ks.passwordUid(password, profileUid);
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6310764..c2c86ff 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9087,9 +9087,11 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean singleton;
if (!providerRunning) {
try {
+ checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
+ checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
} catch (RemoteException ex) {
}
if (cpi == null) {
@@ -9106,12 +9108,15 @@ public final class ActivityManagerService extends ActivityManagerNative
userId = UserHandle.USER_OWNER;
}
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
+ checkTime(startTime, "getContentProviderImpl: got app info for user");
String msg;
+ checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
!= null) {
throw new SecurityException(msg);
}
+ checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate
&& !cpi.processName.equals("system")) {
@@ -9133,15 +9138,19 @@ public final class ActivityManagerService extends ActivityManagerNative
}
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
+ checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
cpr = mProviderMap.getProviderByClass(comp, userId);
+ checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
final boolean firstClass = cpr == null;
if (firstClass) {
try {
+ checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
ApplicationInfo ai =
AppGlobals.getPackageManager().
getApplicationInfo(
cpi.applicationInfo.packageName,
STOCK_PM_FLAGS, userId);
+ checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
if (ai == null) {
Slog.w(TAG, "No package info for content provider "
+ cpi.name);
@@ -9154,6 +9163,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
+
if (r != null && cpr.canRunHere(r)) {
// If this is a multiprocess provider, then just return its
// info and allow the caller to instantiate it. Only do
@@ -9187,8 +9198,10 @@ public final class ActivityManagerService extends ActivityManagerNative
try {
// Content provider is now in use, its package can't be stopped.
try {
+ checkTime(startTime, "getContentProviderImpl: before set stopped state");
AppGlobals.getPackageManager().setPackageStoppedState(
cpr.appInfo.packageName, false, userId);
+ checkTime(startTime, "getContentProviderImpl: after set stopped state");
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
@@ -9196,22 +9209,26 @@ public final class ActivityManagerService extends ActivityManagerNative
}
// Use existing process if already started
+ checkTime(startTime, "getContentProviderImpl: looking for process record");
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null) {
if (DEBUG_PROVIDER) {
Slog.d(TAG, "Installing in existing process " + proc);
}
+ checkTime(startTime, "getContentProviderImpl: scheduling install");
proc.pubProviders.put(cpi.name, cpr);
try {
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
} else {
+ checkTime(startTime, "getContentProviderImpl: before start process");
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
+ checkTime(startTime, "getContentProviderImpl: after start process");
if (proc == null) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
@@ -9227,6 +9244,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ checkTime(startTime, "getContentProviderImpl: updating data structures");
+
// Make sure the provider is published (the same provider class
// may be published under multiple names).
if (firstClass) {
@@ -9239,6 +9258,7 @@ public final class ActivityManagerService extends ActivityManagerNative
conn.waiting = true;
}
}
+ checkTime(startTime, "getContentProviderImpl: done!");
}
// Wait for the provider to be published...
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 1d2f7a9..6545134 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2072,7 +2072,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
targetStack = inTask.stack;
targetStack.moveTaskToFrontLocked(inTask, r, options);
- mWindowManager.moveTaskToTop(targetStack.topTask().taskId);
+ mWindowManager.moveTaskToTop(inTask.taskId);
// Check whether we should actually launch the new activity in to the task,
// or just reuse the current activity on top.
diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java
index ff22764..a37249d 100644
--- a/services/core/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/core/java/com/android/server/am/ContentProviderRecord.java
@@ -166,8 +166,16 @@ final class ContentProviderRecord {
}
if (full) {
if (hasExternalProcessHandles()) {
- pw.print(prefix); pw.print("externals=");
- pw.println(externalProcessTokenToHandle.size());
+ pw.print(prefix); pw.print("externals:");
+ if (externalProcessTokenToHandle != null) {
+ pw.print(" w/token=");
+ pw.print(externalProcessTokenToHandle.size());
+ }
+ if (externalProcessNoHandleCount > 0) {
+ pw.print(" notoken=");
+ pw.print(externalProcessNoHandleCount);
+ }
+ pw.println();
}
} else {
if (connections.size() > 0 || externalProcessNoHandleCount > 0) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 38077eb..8c342dd 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1009,7 +1009,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
y[i] = normalizeAbsoluteBrightness(brightness[i]);
}
- Spline spline = Spline.createMonotoneCubicSpline(x, y);
+ Spline spline = Spline.createSpline(x, y);
if (DEBUG) {
Slog.d(TAG, "Auto-brightness spline: " + spline);
for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 379ec94..c3bc306 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -819,6 +819,7 @@ public class JobSchedulerService extends com.android.server.SystemService
};
void dumpInternal(PrintWriter pw) {
+ final long now = SystemClock.elapsedRealtime();
synchronized (mJobs) {
pw.print("Started users: ");
for (int i=0; i<mStartedUsers.size(); i++) {
@@ -833,15 +834,14 @@ public class JobSchedulerService extends com.android.server.SystemService
job.dump(pw, " ");
}
} else {
- pw.println();
- pw.println("No jobs scheduled.");
+ pw.println(" None.");
}
for (int i=0; i<mControllers.size(); i++) {
pw.println();
mControllers.get(i).dumpControllerState(pw);
}
pw.println();
- pw.println("Pending");
+ pw.println("Pending:");
for (int i=0; i<mPendingJobs.size(); i++) {
pw.println(mPendingJobs.get(i).hashCode());
}
@@ -852,10 +852,14 @@ public class JobSchedulerService extends com.android.server.SystemService
if (jsc.isAvailable()) {
continue;
} else {
- pw.println(jsc.getRunningJob().hashCode() + " for: " +
- (SystemClock.elapsedRealtime()
- - jsc.getExecutionStartTimeElapsed())/1000 + "s " +
- "timeout: " + jsc.getTimeoutElapsed());
+ final long timeout = jsc.getTimeoutElapsed();
+ pw.print("Running for: ");
+ pw.print((now - jsc.getExecutionStartTimeElapsed())/1000);
+ pw.print("s timeout=");
+ pw.print(timeout);
+ pw.print(" fromnow=");
+ pw.println(timeout-now);
+ jsc.getRunningJob().dump(pw, " ");
}
}
pw.println();
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 6f5d3c2..f562721 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -251,6 +251,7 @@ public class JobStatus {
// Dumpsys infrastructure
public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix);
pw.println(this.toString());
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index fc1b746..d0f4054 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -17,6 +17,8 @@
package com.android.server.notification;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
+import static android.service.notification.NotificationListenerService.TRIM_FULL;
+import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -50,6 +52,7 @@ import android.media.AudioManager;
import android.media.IRingtonePlayer;
import android.net.Uri;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
@@ -1290,24 +1293,23 @@ public class NotificationManagerService extends SystemService {
*/
@Override
public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
- INotificationListener token, String[] keys) {
+ INotificationListener token, String[] keys, int trim) {
synchronized (mNotificationList) {
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
- final ArrayList<StatusBarNotification> list
- = new ArrayList<StatusBarNotification>();
final boolean getKeys = keys != null;
final int N = getKeys ? keys.length : mNotificationList.size();
- list.ensureCapacity(N);
+ final ArrayList<StatusBarNotification> list
+ = new ArrayList<StatusBarNotification>(N);
for (int i=0; i<N; i++) {
final NotificationRecord r = getKeys
? mNotificationsByKey.get(keys[i])
: mNotificationList.get(i);
- if (r != null) {
- StatusBarNotification sbn = r.sbn;
- if (isVisibleToListener(sbn, info)) {
- list.add(sbn);
- }
- }
+ if (r == null) continue;
+ StatusBarNotification sbn = r.sbn;
+ if (!isVisibleToListener(sbn, info)) continue;
+ StatusBarNotification sbnToSend =
+ (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
+ list.add(sbnToSend);
}
return new ParceledListSlice<StatusBarNotification>(list);
}
@@ -1364,6 +1366,16 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
+ throws RemoteException {
+ synchronized (mNotificationList) {
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+ if (info == null) return;
+ mListeners.setOnNotificationPostedTrimLocked(info, trim);
+ }
+ }
+
+ @Override
public ZenModeConfig getZenModeConfig() {
enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
return mZenModeHelper.getConfig();
@@ -1427,7 +1439,7 @@ public class NotificationManagerService extends SystemService {
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump NotificationManager from from pid="
+ pw.println("Permission Denial: can't dump NotificationManager from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
return;
@@ -1441,6 +1453,13 @@ public class NotificationManagerService extends SystemService {
enforceSystemOrSystemUI("INotificationManager.getEffectsSuppressor");
return mEffectsSuppressor;
}
+
+ @Override
+ public boolean matchesCallFilter(Bundle extras) {
+ enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
+ return mZenModeHelper.matchesCallFilter(extras,
+ mRankingHelper.findExtractor(ValidateNotificationPeople.class));
+ }
};
private String[] getActiveNotificationKeys(INotificationListener token) {
@@ -2611,6 +2630,8 @@ public class NotificationManagerService extends SystemService {
public class NotificationListeners extends ManagedServices {
+ private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
+
public NotificationListeners() {
super(getContext(), mHandler, mNotificationList, mUserProfiles);
}
@@ -2651,6 +2672,20 @@ public class NotificationManagerService extends SystemService {
if (mListenersDisablingEffects.remove(removed)) {
updateListenerHintsLocked();
}
+ mLightTrimListeners.remove(removed);
+ }
+
+ public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
+ if (trim == TRIM_LIGHT) {
+ mLightTrimListeners.add(info);
+ } else {
+ mLightTrimListeners.remove(info);
+ }
+ }
+
+ public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
+ return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
+
}
/**
@@ -2661,8 +2696,10 @@ public class NotificationManagerService extends SystemService {
* but isn't anymore.
*/
public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
- // make a copy in case changes are made to the underlying Notification object
- final StatusBarNotification sbnClone = sbn.clone();
+ // Lazily initialized snapshots of the notification.
+ StatusBarNotification sbnClone = null;
+ StatusBarNotification sbnCloneLight = null;
+
for (final ManagedServiceInfo info : mServices) {
boolean sbnVisible = isVisibleToListener(sbn, info);
boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
@@ -2684,10 +2721,20 @@ public class NotificationManagerService extends SystemService {
continue;
}
+ final int trim = mListeners.getOnNotificationPostedTrim(info);
+
+ if (trim == TRIM_LIGHT && sbnCloneLight == null) {
+ sbnCloneLight = sbn.cloneLight();
+ } else if (trim == TRIM_FULL && sbnClone == null) {
+ sbnClone = sbn.clone();
+ }
+ final StatusBarNotification sbnToPost =
+ (trim == TRIM_FULL) ? sbnClone : sbnCloneLight;
+
mHandler.post(new Runnable() {
@Override
public void run() {
- notifyPosted(info, sbnClone, update);
+ notifyPosted(info, sbnToPost, update);
}
});
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 01188af..435177b 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -87,6 +87,17 @@ public class RankingHelper implements RankingConfig {
mProxyByGroupTmp = new ArrayMap<String, NotificationRecord>();
}
+ public <T extends NotificationSignalExtractor> T findExtractor(Class<T> extractorClass) {
+ final int N = mSignalExtractors.length;
+ for (int i = 0; i < N; i++) {
+ final NotificationSignalExtractor extractor = mSignalExtractors[i];
+ if (extractorClass.equals(extractor.getClass())) {
+ return (T) extractor;
+ }
+ }
+ return null;
+ }
+
public void extractSignals(NotificationRecord r) {
final int N = mSignalExtractors.length;
for (int i = 0; i < N; i++) {
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index bdc364c..aa47858 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -71,8 +71,17 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
private LruCache<String, LookupResult> mPeopleCache;
private RankingReconsideration validatePeople(final NotificationRecord record) {
+ final String key = record.getKey();
+ final Bundle extras = record.getNotification().extras;
+ final float[] affinityOut = new float[1];
+ final RankingReconsideration rr = validatePeople(key, extras, affinityOut);
+ record.setContactAffinity(affinityOut[0]);
+ return rr;
+ }
+
+ private PeopleRankingReconsideration validatePeople(String key, Bundle extras,
+ float[] affinityOut) {
float affinity = NONE;
- Bundle extras = record.getNotification().extras;
if (extras == null) {
return null;
}
@@ -82,7 +91,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
return null;
}
- if (INFO) Slog.i(TAG, "Validating: " + record.sbn.getKey());
+ if (INFO) Slog.i(TAG, "Validating: " + key);
final LinkedList<String> pendingLookups = new LinkedList<String>();
for (int personIdx = 0; personIdx < people.length && personIdx < MAX_PEOPLE; personIdx++) {
final String handle = people[personIdx];
@@ -102,51 +111,15 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
}
// record the best available data, so far:
- record.setContactAffinity(affinity);
+ affinityOut[0] = affinity;
if (pendingLookups.isEmpty()) {
if (INFO) Slog.i(TAG, "final affinity: " + affinity);
return null;
}
- if (DEBUG) Slog.d(TAG, "Pending: future work scheduled for: " + record.sbn.getKey());
- return new RankingReconsideration(record.getKey()) {
- float mContactAffinity = NONE;
- @Override
- public void work() {
- if (INFO) Slog.i(TAG, "Executing: validation for: " + record.getKey());
- for (final String handle: pendingLookups) {
- LookupResult lookupResult = null;
- final Uri uri = Uri.parse(handle);
- if ("tel".equals(uri.getScheme())) {
- if (DEBUG) Slog.d(TAG, "checking telephone URI: " + handle);
- lookupResult = resolvePhoneContact(uri.getSchemeSpecificPart());
- } else if ("mailto".equals(uri.getScheme())) {
- if (DEBUG) Slog.d(TAG, "checking mailto URI: " + handle);
- lookupResult = resolveEmailContact(uri.getSchemeSpecificPart());
- } else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {
- if (DEBUG) Slog.d(TAG, "checking lookup URI: " + handle);
- lookupResult = searchContacts(uri);
- } else {
- lookupResult = new LookupResult(); // invalid person for the cache
- Slog.w(TAG, "unsupported URI " + handle);
- }
- if (lookupResult != null) {
- synchronized (mPeopleCache) {
- mPeopleCache.put(handle, lookupResult);
- }
- mContactAffinity = Math.max(mContactAffinity, lookupResult.getAffinity());
- }
- }
- }
-
- @Override
- public void applyChangesLocked(NotificationRecord operand) {
- float affinityBound = operand.getContactAffinity();
- operand.setContactAffinity(Math.max(mContactAffinity, affinityBound));
- if (INFO) Slog.i(TAG, "final affinity: " + operand.getContactAffinity());
- }
- };
+ if (DEBUG) Slog.d(TAG, "Pending: future work scheduled for: " + key);
+ return new PeopleRankingReconsideration(key, pendingLookups);
}
// VisibleForTesting
@@ -269,6 +242,19 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
// ignore: config has no relevant information yet.
}
+ public float getContactAffinity(Bundle extras) {
+ if (extras == null) return NONE;
+ final String key = Long.toString(System.nanoTime());
+ final float[] affinityOut = new float[1];
+ final PeopleRankingReconsideration prr = validatePeople(key, extras, affinityOut);
+ float affinity = affinityOut[0];
+ if (prr != null) {
+ prr.work();
+ affinity = Math.max(prr.getContactAffinity(), affinity);
+ }
+ return affinity;
+ }
+
private static class LookupResult {
private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000; // 1hr
public static final int INVALID_ID = -1;
@@ -328,5 +314,55 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
return this;
}
}
+
+ private class PeopleRankingReconsideration extends RankingReconsideration {
+ private final LinkedList<String> mPendingLookups;
+
+ private float mContactAffinity = NONE;
+
+ private PeopleRankingReconsideration(String key, LinkedList<String> pendingLookups) {
+ super(key);
+ mPendingLookups = pendingLookups;
+ }
+
+ @Override
+ public void work() {
+ if (INFO) Slog.i(TAG, "Executing: validation for: " + mKey);
+ for (final String handle: mPendingLookups) {
+ LookupResult lookupResult = null;
+ final Uri uri = Uri.parse(handle);
+ if ("tel".equals(uri.getScheme())) {
+ if (DEBUG) Slog.d(TAG, "checking telephone URI: " + handle);
+ lookupResult = resolvePhoneContact(uri.getSchemeSpecificPart());
+ } else if ("mailto".equals(uri.getScheme())) {
+ if (DEBUG) Slog.d(TAG, "checking mailto URI: " + handle);
+ lookupResult = resolveEmailContact(uri.getSchemeSpecificPart());
+ } else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {
+ if (DEBUG) Slog.d(TAG, "checking lookup URI: " + handle);
+ lookupResult = searchContacts(uri);
+ } else {
+ lookupResult = new LookupResult(); // invalid person for the cache
+ Slog.w(TAG, "unsupported URI " + handle);
+ }
+ if (lookupResult != null) {
+ synchronized (mPeopleCache) {
+ mPeopleCache.put(handle, lookupResult);
+ }
+ mContactAffinity = Math.max(mContactAffinity, lookupResult.getAffinity());
+ }
+ }
+ }
+
+ @Override
+ public void applyChangesLocked(NotificationRecord operand) {
+ float affinityBound = operand.getContactAffinity();
+ operand.setContactAffinity(Math.max(mContactAffinity, affinityBound));
+ if (INFO) Slog.i(TAG, "final affinity: " + operand.getContactAffinity());
+ }
+
+ public float getContactAffinity() {
+ return mContactAffinity;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 7a5336b..fd35ede 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -34,6 +34,7 @@ import android.database.ContentObserver;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings.Global;
@@ -189,7 +190,7 @@ public class ZenModeHelper {
}
private boolean shouldInterceptAudience(NotificationRecord record) {
- if (!audienceMatches(record)) {
+ if (!audienceMatches(record.getContactAffinity())) {
ZenLog.traceIntercepted(record, "!audienceMatches");
return true;
}
@@ -372,14 +373,27 @@ public class ZenModeHelper {
return record.isCategory(Notification.CATEGORY_MESSAGE) || isDefaultMessagingApp(record);
}
- private boolean audienceMatches(NotificationRecord record) {
+ public boolean matchesCallFilter(Bundle extras, ValidateNotificationPeople validator) {
+ final int zen = mZenMode;
+ if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) return false; // nothing gets through
+ if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
+ if (!mConfig.allowCalls) return false; // no calls get through
+ if (validator != null) {
+ final float contactAffinity = validator.getContactAffinity(extras);
+ return audienceMatches(contactAffinity);
+ }
+ }
+ return true;
+ }
+
+ private boolean audienceMatches(float contactAffinity) {
switch (mConfig.allowFrom) {
case ZenModeConfig.SOURCE_ANYONE:
return true;
case ZenModeConfig.SOURCE_CONTACT:
- return record.getContactAffinity() >= ValidateNotificationPeople.VALID_CONTACT;
+ return contactAffinity >= ValidateNotificationPeople.VALID_CONTACT;
case ZenModeConfig.SOURCE_STAR:
- return record.getContactAffinity() >= ValidateNotificationPeople.STARRED_CONTACT;
+ return contactAffinity >= ValidateNotificationPeople.STARRED_CONTACT;
default:
Slog.w(TAG, "Encountered unknown source: " + mConfig.allowFrom);
return true;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2cb9077..5aa0294 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -104,6 +104,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
+import android.content.pm.KeySet;
import android.content.pm.ManifestDigest;
import android.content.pm.PackageCleanItem;
import android.content.pm.PackageInfo;
@@ -7698,8 +7699,21 @@ public class PackageManagerService extends IPackageManager.Stub {
public void installPackage(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, VerificationParams verificationParams,
String packageAbiOverride) {
+ installPackageAsUser(originPath, observer, installFlags, installerPackageName, verificationParams,
+ packageAbiOverride, UserHandle.getCallingUserId());
+ }
+
+ @Override
+ public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
+ int installFlags, String installerPackageName, VerificationParams verificationParams,
+ String packageAbiOverride, int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
null);
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "installPackage " + userId);
+ }
final File originFile = new File(originPath);
final int uid = Binder.getCallingUid();
@@ -7717,7 +7731,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
} else {
- user = new UserHandle(UserHandle.getUserId(uid));
+ user = new UserHandle(userId);
}
final int filteredInstallFlags;
@@ -12965,7 +12979,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
/** Called by UserManagerService */
- void cleanUpUserLILPw(int userHandle) {
+ void cleanUpUserLILPw(UserManagerService userManager, int userHandle) {
mDirtyUsers.remove(userHandle);
mSettings.removeUserLPw(userHandle);
mPendingBroadcasts.remove(userHandle);
@@ -12976,6 +12990,50 @@ public class PackageManagerService extends IPackageManager.Stub {
mInstaller.removeUserDataDirs(userHandle);
}
mUserNeedsBadging.delete(userHandle);
+ removeUnusedPackagesLILPw(userManager, userHandle);
+ }
+
+ /**
+ * We're removing userHandle and would like to remove any downloaded packages
+ * that are no longer in use by any other user.
+ * @param userHandle the user being removed
+ */
+ private void removeUnusedPackagesLILPw(UserManagerService userManager, final int userHandle) {
+ final boolean DEBUG_CLEAN_APKS = false;
+ int [] users = userManager.getUserIdsLPr();
+ Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
+ while (psit.hasNext()) {
+ PackageSetting ps = psit.next();
+ final String packageName = ps.pkg.packageName;
+ // Skip over if system app
+ if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ continue;
+ }
+ if (DEBUG_CLEAN_APKS) {
+ Slog.i(TAG, "Checking package " + packageName);
+ }
+ boolean keep = false;
+ for (int i = 0; i < users.length; i++) {
+ if (users[i] != userHandle && ps.getInstalled(users[i])) {
+ keep = true;
+ if (DEBUG_CLEAN_APKS) {
+ Slog.i(TAG, " Keeping package " + packageName + " for user "
+ + users[i]);
+ }
+ break;
+ }
+ }
+ if (!keep) {
+ if (DEBUG_CLEAN_APKS) {
+ Slog.i(TAG, " Removing package " + packageName);
+ }
+ mHandler.post(new Runnable() {
+ public void run() {
+ deletePackageX(packageName, userHandle, 0);
+ } //end run
+ });
+ }
+ }
}
/** Called by UserManagerService */
@@ -13075,7 +13133,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
- public KeySetHandle getKeySetByAlias(String packageName, String alias) {
+ public KeySet getKeySetByAlias(String packageName, String alias) {
if (packageName == null || alias == null) {
return null;
}
@@ -13085,18 +13143,13 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- if (pkg.applicationInfo.uid != Binder.getCallingUid()
- && Process.SYSTEM_UID != Binder.getCallingUid()) {
- throw new SecurityException("May not access KeySets defined by"
- + " aliases in other applications.");
- }
KeySetManagerService ksms = mSettings.mKeySetManagerService;
- return ksms.getKeySetByAliasAndPackageNameLPr(packageName, alias);
+ return new KeySet(ksms.getKeySetByAliasAndPackageNameLPr(packageName, alias));
}
}
@Override
- public KeySetHandle getSigningKeySet(String packageName) {
+ public KeySet getSigningKeySet(String packageName) {
if (packageName == null) {
return null;
}
@@ -13111,12 +13164,12 @@ public class PackageManagerService extends IPackageManager.Stub {
throw new SecurityException("May not access signing KeySet of other apps.");
}
KeySetManagerService ksms = mSettings.mKeySetManagerService;
- return ksms.getSigningKeySetByPackageNameLPr(packageName);
+ return new KeySet(ksms.getSigningKeySetByPackageNameLPr(packageName));
}
}
@Override
- public boolean isPackageSignedByKeySet(String packageName, IBinder ks) {
+ public boolean isPackageSignedByKeySet(String packageName, KeySet ks) {
if (packageName == null || ks == null) {
return false;
}
@@ -13126,16 +13179,17 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- if (ks instanceof KeySetHandle) {
+ IBinder ksh = ks.getToken();
+ if (ksh instanceof KeySetHandle) {
KeySetManagerService ksms = mSettings.mKeySetManagerService;
- return ksms.packageIsSignedByLPr(packageName, (KeySetHandle) ks);
+ return ksms.packageIsSignedByLPr(packageName, (KeySetHandle) ksh);
}
return false;
}
}
@Override
- public boolean isPackageSignedByKeySetExactly(String packageName, IBinder ks) {
+ public boolean isPackageSignedByKeySetExactly(String packageName, KeySet ks) {
if (packageName == null || ks == null) {
return false;
}
@@ -13145,9 +13199,10 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- if (ks instanceof KeySetHandle) {
+ IBinder ksh = ks.getToken();
+ if (ksh instanceof KeySetHandle) {
KeySetManagerService ksms = mSettings.mKeySetManagerService;
- return ksms.packageIsSignedByExactlyLPr(packageName, (KeySetHandle) ks);
+ return ksms.packageIsSignedByExactlyLPr(packageName, (KeySetHandle) ksh);
}
return false;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 8ded7ca..2929939 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -293,6 +293,10 @@ public class UserManagerService extends IUserManager.Stub {
private List<UserInfo> getProfilesLocked(int userId, boolean enabledOnly) {
UserInfo user = getUserInfoLocked(userId);
ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
+ if (user == null) {
+ // Probably a dying user
+ return users;
+ }
for (int i = 0; i < mUsers.size(); i++) {
UserInfo profile = mUsers.valueAt(i);
if (!isProfileOf(user, profile)) {
@@ -1280,7 +1284,7 @@ public class UserManagerService extends IUserManager.Stub {
private void removeUserStateLocked(final int userHandle) {
// Cleanup package manager settings
- mPm.cleanUpUserLILPw(userHandle);
+ mPm.cleanUpUserLILPw(this, userHandle);
// Remove this user from the list
mUsers.remove(userHandle);
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index ef74205..69c9144 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -114,6 +114,10 @@ public class AppWindowAnimator {
transformation.clear();
transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
hasTransformation = true;
+
+ if (!mAppToken.appFullscreen) {
+ anim.setBackgroundColor(0);
+ }
}
public void setDummyAnimation() {
diff --git a/telecomm/java/android/telecomm/PhoneAccount.java b/telecomm/java/android/telecomm/PhoneAccount.java
index e8e6467..5b46409 100644
--- a/telecomm/java/android/telecomm/PhoneAccount.java
+++ b/telecomm/java/android/telecomm/PhoneAccount.java
@@ -94,7 +94,7 @@ public class PhoneAccount implements Parcelable {
private CharSequence mLabel;
private CharSequence mShortDescription;
- private Builder() {}
+ public Builder() {}
public Builder withAccountHandle(PhoneAccountHandle value) {
this.mAccountHandle = value;
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
index 868282f..2243288 100644
--- a/telecomm/java/android/telecomm/TelecommManager.java
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -285,6 +285,20 @@ public class TelecommManager {
}
/**
+ * Sets the default account for making outgoing phone calls.
+ * @hide
+ */
+ public void setDefaultOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
+ try {
+ if (isServiceConnected()) {
+ getTelecommService().setDefaultOutgoingPhoneAccount(accountHandle);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecommService#setDefaultOutgoingPhoneAccount");
+ }
+ }
+
+ /**
* Return a list of {@link PhoneAccountHandle}s which can be used to make and receive phone
* calls.
*
@@ -303,6 +317,55 @@ public class TelecommManager {
}
/**
+ * Returns the current SIM call manager. Apps must be prepared for this method to return
+ * {@code null}, indicating that there currently exists no user-chosen default
+ * {@code PhoneAccount}.
+ * @return The phone account handle of the current sim call manager.
+ * @hide
+ */
+ public PhoneAccountHandle getSimCallManager() {
+ try {
+ if (isServiceConnected()) {
+ return getTelecommService().getSimCallManager();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecommService#getSimCallManager");
+ }
+ return null;
+ }
+
+ /**
+ * Sets the SIM call manager to the specified phone account.
+ * @param accountHandle The phone account handle of the account to set as the sim call manager.
+ * @hide
+ */
+ public void setSimCallManager(PhoneAccountHandle accountHandle) {
+ try {
+ if (isServiceConnected()) {
+ getTelecommService().setSimCallManager(accountHandle);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecommService#setSimCallManager");
+ }
+ }
+
+ /**
+ * Returns the list of registered SIM call managers.
+ * @return List of registered SIM call managers.
+ * @hide
+ */
+ public List<PhoneAccountHandle> getSimCallManagers() {
+ try {
+ if (isServiceConnected()) {
+ return getTelecommService().getSimCallManagers();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecommService#getSimCallManagers");
+ }
+ return new ArrayList<>();
+ }
+
+ /**
* Determine whether the device has more than one account registered and enabled.
*
* @return {@code true} if the device has more than one account registered and enabled and
@@ -614,4 +677,4 @@ public class TelecommManager {
}
return isConnected;
}
-}
+} \ No newline at end of file
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
index 0ac5078..131307a 100644
--- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -35,37 +35,57 @@ interface ITelecommService {
void showInCallScreen(boolean showDialpad);
/**
- * @see TelecommManager#getDefaultOutgoingPhoneAccount
+ * @see TelecommServiceImpl#getDefaultOutgoingPhoneAccount
*/
PhoneAccountHandle getDefaultOutgoingPhoneAccount();
/**
- * @see TelecommManager#getOutgoingPhoneAccounts
+ * @see TelecommServiceImpl#setDefaultOutgoingPhoneAccount
+ */
+ void setDefaultOutgoingPhoneAccount(in PhoneAccountHandle account);
+
+ /**
+ * @see TelecommServiceImpl#getOutgoingPhoneAccounts
*/
List<PhoneAccountHandle> getOutgoingPhoneAccounts();
/**
- * @see TelecommManager#getPhoneAccount
+ * @see TelecommServiceImpl#getPhoneAccount
*/
PhoneAccount getPhoneAccount(in PhoneAccountHandle account);
/**
- * @see TelecommManager#registerPhoneAccount
+ * @see TelecommServiceImpl#getSimCallManager
+ */
+ PhoneAccountHandle getSimCallManager();
+
+ /**
+ * @see TelecommServiceImpl#setSimCallManager
+ */
+ void setSimCallManager(in PhoneAccountHandle account);
+
+ /**
+ * @see TelecommServiceImpl#getSimCallManagers
+ */
+ List<PhoneAccountHandle> getSimCallManagers();
+
+ /**
+ * @see TelecommServiceImpl#registerPhoneAccount
*/
void registerPhoneAccount(in PhoneAccount metadata);
/**
- * @see TelecommManager#unregisterPhoneAccount
+ * @see TelecommServiceImpl#unregisterPhoneAccount
*/
void unregisterPhoneAccount(in PhoneAccountHandle account);
/**
- * @see TelecommManager#clearAccounts
+ * @see TelecommServiceImpl#clearAccounts
*/
void clearAccounts(String packageName);
/**
- * @see TelecommManager#getDefaultPhoneApp
+ * @see TelecommServiceImpl#getDefaultPhoneApp
*/
ComponentName getDefaultPhoneApp();
@@ -74,52 +94,52 @@ interface ITelecommService {
//
/**
- * @see TelecommManager#silenceRinger
+ * @see TelecommServiceImpl#silenceRinger
*/
void silenceRinger();
/**
- * @see TelecommManager#isInCall
+ * @see TelecommServiceImpl#isInCall
*/
boolean isInCall();
/**
- * @see TelecomManager#isRinging
+ * @see TelecommServiceImpl#isRinging
*/
boolean isRinging();
/**
- * @see TelecommManager#endCall
+ * @see TelecommServiceImpl#endCall
*/
boolean endCall();
/**
- * @see TelecommManager#acceptRingingCall
+ * @see TelecommServiceImpl#acceptRingingCall
*/
void acceptRingingCall();
/**
- * @see TelecommManager#cancelMissedCallsNotification
+ * @see TelecommServiceImpl#cancelMissedCallsNotification
*/
void cancelMissedCallsNotification();
/**
- * @see TelecommManager#handleMmi
+ * @see TelecommServiceImpl#handleMmi
*/
boolean handlePinMmi(String dialString);
/**
- * @see TelecomManager#isTtySupported
+ * @see TelecommServiceImpl#isTtySupported
*/
boolean isTtySupported();
/**
- * @see TelecomManager#getCurrentTtyMode
+ * @see TelecommServiceImpl#getCurrentTtyMode
*/
int getCurrentTtyMode();
/**
- * @see TelecommManager#addNewIncomingCall
+ * @see TelecommServiceImpl#addNewIncomingCall
*/
void addNewIncomingCall(in PhoneAccountHandle phoneAccount, in Bundle extras);
}
diff --git a/telecomm/java/com/android/internal/telecomm/RemoteServiceCallback.aidl b/telecomm/java/com/android/internal/telecomm/RemoteServiceCallback.aidl
index 42c77d7..0ab7564 100644
--- a/telecomm/java/com/android/internal/telecomm/RemoteServiceCallback.aidl
+++ b/telecomm/java/com/android/internal/telecomm/RemoteServiceCallback.aidl
@@ -20,6 +20,8 @@ import android.content.ComponentName;
/**
* Simple response callback object.
+ *
+ * {@hide}
*/
oneway interface RemoteServiceCallback {
void onError();
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index c84f40e..cd7d178 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -617,21 +617,25 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
+ /** @hide */
@Override
public KeySet getKeySetByAlias(String packageName, String alias) {
throw new UnsupportedOperationException();
}
+ /** @hide */
@Override
public KeySet getSigningKeySet(String packageName) {
throw new UnsupportedOperationException();
}
+ /** @hide */
@Override
public boolean isSignedBy(String packageName, KeySet ks) {
throw new UnsupportedOperationException();
}
+ /** @hide */
@Override
public boolean isSignedByExactly(String packageName, KeySet ks) {
throw new UnsupportedOperationException();
diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
index b6591bd..c08c1a3 100644
--- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
+++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
@@ -23,7 +23,6 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.format.DateUtils;
-import android.util.ArrayMap;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -36,6 +35,7 @@ import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Map;
public class UsageStatsActivity extends ListActivity {
private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
@@ -84,7 +84,7 @@ public class UsageStatsActivity extends ListActivity {
private void updateAdapter() {
long now = System.currentTimeMillis();
long beginTime = now - USAGE_STATS_PERIOD;
- ArrayMap<String, UsageStats> stats = mUsageStatsManager.queryAndAggregateUsageStats(
+ Map<String, UsageStats> stats = mUsageStatsManager.queryAndAggregateUsageStats(
beginTime, now);
mAdapter.update(stats);
}
@@ -92,17 +92,13 @@ public class UsageStatsActivity extends ListActivity {
private class Adapter extends BaseAdapter {
private ArrayList<UsageStats> mStats = new ArrayList<>();
- public void update(ArrayMap<String, UsageStats> stats) {
+ public void update(Map<String, UsageStats> stats) {
mStats.clear();
if (stats == null) {
return;
}
- final int packageCount = stats.size();
- for (int i = 0; i < packageCount; i++) {
- mStats.add(stats.valueAt(i));
- }
-
+ mStats.addAll(stats.values());
Collections.sort(mStats, mComparator);
notifyDataSetChanged();
}
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index fd660bb..27e60f3 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -1038,9 +1038,9 @@ int doDump(Bundle* bundle)
splitName.string()).string());
}
- int32_t platformVersionCode = AaptXml::getIntegerAttribute(tree, NULL,
- "platformBuildVersionCode");
- printf(" platformBuildVersionCode='%d'", platformVersionCode);
+ String8 platformVersionName = AaptXml::getAttribute(tree, NULL,
+ "platformBuildVersionName");
+ printf(" platformBuildVersionName='%s'", platformVersionName.string());
printf("\n");
int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree,
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index fce4323..6bb28e1 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -22,7 +22,7 @@ Usage: apilint.py current.txt
Usage: apilint.py current.txt previous.txt
"""
-import re, sys
+import re, sys, collections
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
@@ -149,6 +149,9 @@ def parse_api(fn):
failures = []
+def filter_dupe(s):
+ return s.replace(" deprecated ", " ")
+
def _fail(clazz, detail, msg):
"""Records an API failure to be processed later."""
global failures
@@ -158,7 +161,7 @@ def _fail(clazz, detail, msg):
res += "\n in " + repr(detail)
res += "\n in " + repr(clazz)
res += "\n in " + repr(clazz.pkg)
- failures.append(res)
+ failures.append(filter_dupe(res))
def warn(clazz, detail, msg):
_fail(clazz, detail, "%sWarning:%s %s" % (format(fg=YELLOW, bg=BLACK), format(reset=True), msg))
@@ -393,16 +396,31 @@ def verify_intent_builder(clazz):
def verify_helper_classes(clazz):
- """Verify that helper classes are named consistently with what they extend."""
+ """Verify that helper classes are named consistently with what they extend.
+ All developer extendable methods should be named onFoo()."""
+ test_methods = False
if "extends android.app.Service" in clazz.raw:
+ test_methods = True
if not clazz.name.endswith("Service"):
error(clazz, None, "Inconsistent class name")
if "extends android.content.ContentProvider" in clazz.raw:
+ test_methods = True
if not clazz.name.endswith("Provider"):
error(clazz, None, "Inconsistent class name")
if "extends android.content.BroadcastReceiver" in clazz.raw:
+ test_methods = True
if not clazz.name.endswith("Receiver"):
error(clazz, None, "Inconsistent class name")
+ if "extends android.app.Activity" in clazz.raw:
+ test_methods = True
+ if not clazz.name.endswith("Activity"):
+ error(clazz, None, "Inconsistent class name")
+
+ if test_methods:
+ for m in clazz.methods:
+ if "final" in m.split: continue
+ if not re.match("on[A-Z]", m.name):
+ error(clazz, m, "Extendable methods should be onFoo() style, otherwise final")
def verify_builder(clazz):
@@ -423,8 +441,12 @@ def verify_builder(clazz):
if m.name.startswith("get"): continue
if m.name.startswith("clear"): continue
- if not m.typ.endswith(clazz.fullname):
- warn(clazz, m, "Should return the builder")
+ if m.name.startswith("with"):
+ error(clazz, m, "Builder methods must be setFoo()")
+
+ if m.name.startswith("set"):
+ if not m.typ.endswith(clazz.fullname):
+ warn(clazz, m, "Should return the builder")
if not has_build:
warn(clazz, None, "Missing build() method")
@@ -486,6 +508,47 @@ def verify_layering(clazz):
warn(clazz, m, "Method argument type violates package layering")
+def verify_boolean(clazz):
+ """Catches people returning boolean from getFoo() style methods.
+ Ignores when matching setFoo() is present."""
+ methods = [ m.name for m in clazz.methods ]
+ for m in clazz.methods:
+ if m.typ == "boolean" and m.name.startswith("get") and m.name != "get" and len(m.args) == 0:
+ setter = "set" + m.name[3:]
+ if setter not in methods:
+ error(clazz, m, "Methods returning boolean should be isFoo or hasFoo")
+
+
+def verify_collections(clazz):
+ """Verifies that collection types are interfaces."""
+ bad = ["java.util.Vector", "java.util.LinkedList", "java.util.ArrayList", "java.util.Stack",
+ "java.util.HashMap", "java.util.HashSet", "android.util.ArraySet", "android.util.ArrayMap"]
+ for m in clazz.methods:
+ filt = re.sub("<.+>", "", m.typ)
+ if filt in bad:
+ error(clazz, m, "Return type is concrete collection")
+ for arg in m.args:
+ filt = re.sub("<.+>", "", arg)
+ if filt in bad:
+ error(clazz, m, "Argument is concrete collection")
+
+
+def verify_flags(clazz):
+ """Verifies that flags are non-overlapping."""
+ known = collections.defaultdict(int)
+ for f in clazz.fields:
+ if "FLAG_" in f.name:
+ try:
+ val = int(f.value)
+ except:
+ continue
+
+ scope = f.name[0:f.name.index("FLAG_")]
+ if val & known[scope]:
+ warn(clazz, f, "Found overlapping flag")
+ known[scope] |= val
+
+
def verify_all(api):
global failures
@@ -518,6 +581,9 @@ def verify_all(api):
verify_aidl(clazz)
verify_internal(clazz)
verify_layering(clazz)
+ verify_boolean(clazz)
+ verify_collections(clazz)
+ verify_flags(clazz)
return failures