Merge "Add extra logging for media button events"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index bd3227f..c35f332 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -227,6 +227,7 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/widget/ILockSettingsObserver.java)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/SystemUI_intermediates/)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/Keyguard_intermediates/)
+$(call add-clean-step, rm -f $(OUT_DIR)/target/product/*/system/framework/android.policy.jar)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/api/current.txt b/api/current.txt
index 3f15b2f..cd4f73a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12791,6 +12791,7 @@
field public static final android.hardware.camera2.CameraCharacteristics.Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_INFO_COLOR_FILTER_ARRANGEMENT;
field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Long>> SENSOR_INFO_EXPOSURE_TIME_RANGE;
+ field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> SENSOR_INFO_LENS_SHADING_APPLIED;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Long> SENSOR_INFO_MAX_FRAME_DURATION;
field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.SizeF> SENSOR_INFO_PHYSICAL_SIZE;
field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE;
@@ -12801,8 +12802,10 @@
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_ORIENTATION;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_REFERENCE_ILLUMINANT1;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Byte> SENSOR_REFERENCE_ILLUMINANT2;
+ field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SHADING_AVAILABLE_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key<boolean[]> STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES;
+ field public static final android.hardware.camera2.CameraCharacteristics.Key<byte[]> STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> STATISTICS_INFO_MAX_FACE_COUNT;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SYNC_MAX_LATENCY;
field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> TONEMAP_AVAILABLE_TONE_MAP_MODES;
diff --git a/api/system-current.txt b/api/system-current.txt
index f89c069..ce68ca9 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6502,6 +6502,8 @@
method public java.lang.String getName();
method public int getType();
method public android.os.ParcelUuid[] getUuids();
+ method public boolean isConnected();
+ method public boolean isEncrypted();
method public boolean setPairingConfirmation(boolean);
method public boolean setPin(byte[]);
method public void writeToParcel(android.os.Parcel, int);
@@ -8003,6 +8005,7 @@
field public static final java.lang.String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
field public static final java.lang.String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
field public static final java.lang.String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
+ field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
field public static final java.lang.String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
field public static final java.lang.String ACTION_REBOOT = "android.intent.action.REBOOT";
field public static final java.lang.String ACTION_RUN = "android.intent.action.RUN";
@@ -8101,6 +8104,7 @@
field public static final java.lang.String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
+ field public static final java.lang.String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
@@ -12815,6 +12819,7 @@
field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
+ field public static final java.lang.String STRING_TYPE_WRIST_TILT_GESTURE = "android.sensor.wrist_tilt_gesture";
field public static final int TYPE_ACCELEROMETER = 1; // 0x1
field public static final int TYPE_ALL = -1; // 0xffffffff
field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
@@ -12837,6 +12842,7 @@
field public static final int TYPE_STEP_COUNTER = 19; // 0x13
field public static final int TYPE_STEP_DETECTOR = 18; // 0x12
field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
+ field public static final int TYPE_WRIST_TILT_GESTURE = 26; // 0x1a
}
public class SensorEvent {
@@ -13061,6 +13067,7 @@
field public static final android.hardware.camera2.CameraCharacteristics.Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_INFO_COLOR_FILTER_ARRANGEMENT;
field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Long>> SENSOR_INFO_EXPOSURE_TIME_RANGE;
+ field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> SENSOR_INFO_LENS_SHADING_APPLIED;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Long> SENSOR_INFO_MAX_FRAME_DURATION;
field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.SizeF> SENSOR_INFO_PHYSICAL_SIZE;
field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE;
@@ -13071,8 +13078,10 @@
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_ORIENTATION;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_REFERENCE_ILLUMINANT1;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Byte> SENSOR_REFERENCE_ILLUMINANT2;
+ field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SHADING_AVAILABLE_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key<boolean[]> STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES;
+ field public static final android.hardware.camera2.CameraCharacteristics.Key<byte[]> STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> STATISTICS_INFO_MAX_FACE_COUNT;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SYNC_MAX_LATENCY;
field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> TONEMAP_AVAILABLE_TONE_MAP_MODES;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8b4b292..e95fbfc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -27,7 +27,6 @@
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.WindowDecorActionBar;
import com.android.internal.app.ToolbarActionBar;
-import com.android.internal.policy.PolicyManager;
import android.annotation.IntDef;
import android.annotation.Nullable;
@@ -84,6 +83,7 @@
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
+import android.view.PhoneWindow;
import android.view.View;
import android.view.View.OnCreateContextMenuListener;
import android.view.ViewGroup;
@@ -5929,7 +5929,7 @@
mFragments.attachActivity(this, mContainer, null);
- mWindow = PolicyManager.makeNewWindow(this);
+ mWindow = new PhoneWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index de3c95c..d781863 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -294,6 +294,8 @@
Configuration newConfig;
Configuration createdConfig;
Configuration overrideConfig;
+ // Used for consolidating configs before sending on to Activity.
+ private Configuration tmpConfig = new Configuration();
ActivityClientRecord nextIdle;
ProfilerInfo profilerInfo;
@@ -557,6 +559,15 @@
int requestType;
}
+ static final class ActivityConfigChangeData {
+ final IBinder activityToken;
+ final Configuration overrideConfig;
+ public ActivityConfigChangeData(IBinder token, Configuration config) {
+ activityToken = token;
+ overrideConfig = config;
+ }
+ }
+
private native void dumpGraphicsInfo(FileDescriptor fd);
private class ApplicationThread extends ApplicationThreadNative {
@@ -888,15 +899,19 @@
sticky, sendingUser);
}
+ @Override
public void scheduleLowMemory() {
sendMessage(H.LOW_MEMORY, null);
}
@Override
- public void scheduleActivityConfigurationChanged(IBinder token) {
- sendMessage(H.ACTIVITY_CONFIGURATION_CHANGED, token);
+ public void scheduleActivityConfigurationChanged(
+ IBinder token, Configuration overrideConfig) {
+ sendMessage(H.ACTIVITY_CONFIGURATION_CHANGED,
+ new ActivityConfigChangeData(token, overrideConfig));
}
+ @Override
public void profilerControl(boolean start, ProfilerInfo profilerInfo, int profileType) {
sendMessage(H.PROFILER_CONTROL, profilerInfo, start ? 1 : 0, profileType);
}
@@ -1456,7 +1471,7 @@
break;
case ACTIVITY_CONFIGURATION_CHANGED:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");
- handleActivityConfigurationChanged((IBinder)msg.obj);
+ handleActivityConfigurationChanged((ActivityConfigChangeData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case PROFILER_CONTROL:
@@ -3099,10 +3114,14 @@
if (!r.activity.mFinished && willBeVisible
&& r.activity.mDecor != null && !r.hideForNow) {
if (r.newConfig != null) {
+ r.tmpConfig.setTo(r.newConfig);
+ if (r.overrideConfig != null) {
+ r.tmpConfig.updateFrom(r.overrideConfig);
+ }
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity "
- + r.activityInfo.name + " with newConfig " + r.newConfig);
- performConfigurationChanged(r.activity, r.newConfig);
- freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.newConfig));
+ + r.activityInfo.name + " with newConfig " + r.tmpConfig);
+ performConfigurationChanged(r.activity, r.tmpConfig);
+ freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
r.newConfig = null;
}
if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward="
@@ -3431,10 +3450,14 @@
}
}
if (r.newConfig != null) {
+ r.tmpConfig.setTo(r.newConfig);
+ if (r.overrideConfig != null) {
+ r.tmpConfig.updateFrom(r.overrideConfig);
+ }
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Updating activity vis "
- + r.activityInfo.name + " with new config " + r.newConfig);
- performConfigurationChanged(r.activity, r.newConfig);
- freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.newConfig));
+ + r.activityInfo.name + " with new config " + r.tmpConfig);
+ performConfigurationChanged(r.activity, r.tmpConfig);
+ freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
r.newConfig = null;
}
} else {
@@ -4164,16 +4187,21 @@
}
}
- final void handleActivityConfigurationChanged(IBinder token) {
- ActivityClientRecord r = mActivities.get(token);
+ final void handleActivityConfigurationChanged(ActivityConfigChangeData data) {
+ ActivityClientRecord r = mActivities.get(data.activityToken);
if (r == null || r.activity == null) {
return;
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
+ r.activityInfo.name);
-
- performConfigurationChanged(r.activity, mCompatConfiguration);
+
+ r.tmpConfig.setTo(mCompatConfiguration);
+ if (data.overrideConfig != null) {
+ r.overrideConfig = data.overrideConfig;
+ r.tmpConfig.updateFrom(data.overrideConfig);
+ }
+ performConfigurationChanged(r.activity, r.tmpConfig);
freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(mCompatConfiguration));
@@ -4404,10 +4432,16 @@
if (cacheDir != null) {
// Provide a usable directory for temporary files
System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
-
- setupGraphicsSupport(data.info, cacheDir);
} else {
- Log.e(TAG, "Unable to setupGraphicsSupport due to missing cache directory");
+ Log.v(TAG, "Unable to initialize \"java.io.tmpdir\" property due to missing cache directory");
+ }
+
+ // Use codeCacheDir to store generated/compiled graphics code
+ final File codeCacheDir = appContext.getCodeCacheDir();
+ if (codeCacheDir != null) {
+ setupGraphicsSupport(data.info, codeCacheDir);
+ } else {
+ Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory");
}
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 967e97e..d808c8b 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -63,6 +63,7 @@
import android.util.ArrayMap;
import android.util.Log;
import android.view.Display;
+import android.os.SystemProperties;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
@@ -287,7 +288,12 @@
// depending on what the current runtime's instruction set is.
if (info.primaryCpuAbi != null && info.secondaryCpuAbi != null) {
final String runtimeIsa = VMRuntime.getRuntime().vmInstructionSet();
- final String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
+
+ // Get the instruction set that the libraries of secondary Abi is supported.
+ // In presence of a native bridge this might be different than the one secondary Abi used.
+ String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
+ final String secondaryDexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + secondaryIsa);
+ secondaryIsa = secondaryDexCodeIsa.isEmpty() ? secondaryIsa : secondaryDexCodeIsa;
// If the runtimeIsa is the same as the primary isa, then we do nothing.
// Everything will be set up correctly because info.nativeLibraryDir will
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 349b66d..b6989ab 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -409,7 +409,11 @@
{
data.enforceInterface(IApplicationThread.descriptor);
IBinder b = data.readStrongBinder();
- scheduleActivityConfigurationChanged(b);
+ Configuration overrideConfig = null;
+ if (data.readInt() != 0) {
+ overrideConfig = Configuration.CREATOR.createFromParcel(data);
+ }
+ scheduleActivityConfigurationChanged(b, overrideConfig);
return true;
}
@@ -1116,6 +1120,7 @@
data.recycle();
}
+ @Override
public final void scheduleLowMemory() throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -1124,15 +1129,24 @@
data.recycle();
}
- public final void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException {
+ @Override
+ public final void scheduleActivityConfigurationChanged(
+ IBinder token, Configuration overrideConfig) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
+ if (overrideConfig != null) {
+ data.writeInt(1);
+ overrideConfig.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
mRemote.transact(SCHEDULE_ACTIVITY_CONFIGURATION_CHANGED_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
+ @Override
public void profilerControl(boolean start, ProfilerInfo profilerInfo, int profileType)
throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 39caf0b..6c78cab 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -24,7 +24,6 @@
import android.service.persistentdata.PersistentDataBlockManager;
import com.android.internal.appwidget.IAppWidgetService;
-import com.android.internal.policy.PolicyManager;
import com.android.internal.util.Preconditions;
import android.bluetooth.BluetoothManager;
@@ -139,6 +138,7 @@
import android.view.DisplayAdjustments;
import android.view.ContextThemeWrapper;
import android.view.Display;
+import android.view.PhoneLayoutInflater;
import android.view.WindowManagerImpl;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.CaptioningManager;
@@ -235,7 +235,6 @@
private final Resources mResources;
private final Display mDisplay; // may be null if default display
private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
- private final Configuration mOverrideConfiguration;
private final boolean mRestricted;
@@ -480,7 +479,7 @@
registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
- return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
+ return new PhoneLayoutInflater(ctx.getOuterContext());
}});
registerService(LOCATION_SERVICE, new ServiceFetcher() {
@@ -2149,7 +2148,7 @@
final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
new UserHandle(UserHandle.getUserId(application.uid)), restricted,
- mDisplay, mOverrideConfiguration);
+ mDisplay, null);
if (c.mResources != null) {
return c;
}
@@ -2172,14 +2171,14 @@
final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
if (packageName.equals("system") || packageName.equals("android")) {
return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
- user, restricted, mDisplay, mOverrideConfiguration);
+ user, restricted, mDisplay, null);
}
LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
if (pi != null) {
ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
- user, restricted, mDisplay, mOverrideConfiguration);
+ user, restricted, mDisplay, null);
if (c.mResources != null) {
return c;
}
@@ -2207,7 +2206,7 @@
}
return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
- mUser, mRestricted, display, mOverrideConfiguration);
+ mUser, mRestricted, display, null);
}
private int getDisplayId() {
@@ -2287,7 +2286,6 @@
mPackageInfo = packageInfo;
mResourcesManager = ResourcesManager.getInstance();
mDisplay = display;
- mOverrideConfiguration = overrideConfiguration;
final int displayId = getDisplayId();
CompatibilityInfo compatInfo = null;
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 067073a..70e6e5a 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -16,14 +16,13 @@
package android.app;
-import android.content.pm.ApplicationInfo;
import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.policy.PolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.DialogInterface;
+import android.content.pm.ApplicationInfo;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
@@ -42,6 +41,7 @@
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
+import android.view.PhoneWindow;
import android.view.View;
import android.view.View.OnCreateContextMenuListener;
import android.view.ViewGroup;
@@ -134,14 +134,14 @@
/**
* Create a Dialog window that uses a custom dialog style.
- *
+ *
* @param context The Context in which the Dialog should run. In particular, it
* uses the window manager and theme from this context to
* present its UI.
- * @param theme A style resource describing the theme to use for the
- * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style
- * and Theme Resources</a> for more information about defining and using
- * styles. This theme is applied on top of the current theme in
+ * @param theme A style resource describing the theme to use for the
+ * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style
+ * and Theme Resources</a> for more information about defining and using
+ * styles. This theme is applied on top of the current theme in
* <var>context</var>. If 0, the default dialog theme will be used.
*/
public Dialog(Context context, int theme) {
@@ -162,7 +162,7 @@
}
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
- Window w = PolicyManager.makeNewWindow(mContext);
+ Window w = new PhoneWindow(mContext);
mWindow = w;
w.setCallback(this);
w.setOnWindowDismissedCallback(this);
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index f2c912e..3fb82f6 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -114,7 +114,8 @@
int resultCode, String data, Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState) throws RemoteException;
void scheduleLowMemory() throws RemoteException;
- void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
+ void scheduleActivityConfigurationChanged(IBinder token, Configuration overrideConfig)
+ throws RemoteException;
void profilerControl(boolean start, ProfilerInfo profilerInfo, int profileType)
throws RemoteException;
void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index b01f87e..83c6c2b 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -45,6 +45,7 @@
import android.util.SparseArray;
import android.view.DisplayAdjustments;
import android.view.Display;
+import android.os.SystemProperties;
import dalvik.system.VMRuntime;
import java.io.File;
@@ -156,7 +157,12 @@
// depending on what the current runtime's instruction set is.
if (info.primaryCpuAbi != null && info.secondaryCpuAbi != null) {
final String runtimeIsa = VMRuntime.getRuntime().vmInstructionSet();
- final String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
+
+ // Get the instruction set that the libraries of secondary Abi is supported.
+ // In presence of a native bridge this might be different than the one secondary Abi used.
+ String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
+ final String secondaryDexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + secondaryIsa);
+ secondaryIsa = secondaryDexCodeIsa.isEmpty() ? secondaryIsa : secondaryDexCodeIsa;
// If the runtimeIsa is the same as the primary isa, then we do nothing.
// Everything will be set up correctly because info.nativeLibraryDir will
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index af48909..318a314 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1518,8 +1518,8 @@
public static final int WIPE_RESET_PROTECTION_DATA = 0x0002;
/**
- * Ask the user data be wiped. This will cause the device to reboot,
- * erasing all user data while next booting up.
+ * Ask the user data be wiped. Wiping the primary user will cause the
+ * device to reboot, erasing all user data while next booting up.
*
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to be able to call
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index c262bae..b8f4bf8 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1429,14 +1429,16 @@
if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
synchronized (mManagerCallback) {
mService = bluetoothService;
- for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
- try {
- if (cb != null) {
- cb.onBluetoothServiceUp(bluetoothService);
- } else {
- Log.d(TAG, "onBluetoothServiceUp: cb is null!!!");
- }
- } catch (Exception e) { Log.e(TAG,"",e);}
+ synchronized (mProxyServiceStateCallbacks) {
+ for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
+ try {
+ if (cb != null) {
+ cb.onBluetoothServiceUp(bluetoothService);
+ } else {
+ Log.d(TAG, "onBluetoothServiceUp: cb is null!!!");
+ }
+ } catch (Exception e) { Log.e(TAG,"",e);}
+ }
}
}
}
@@ -1448,14 +1450,16 @@
if (mLeScanClients != null) mLeScanClients.clear();
if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup();
if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup();
- for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
- try {
- if (cb != null) {
- cb.onBluetoothServiceDown();
- } else {
- Log.d(TAG, "onBluetoothServiceDown: cb is null!!!");
- }
- } catch (Exception e) { Log.e(TAG,"",e);}
+ synchronized (mProxyServiceStateCallbacks) {
+ for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
+ try {
+ if (cb != null) {
+ cb.onBluetoothServiceDown();
+ } else {
+ Log.d(TAG, "onBluetoothServiceDown: cb is null!!!");
+ }
+ } catch (Exception e) { Log.e(TAG,"",e);}
+ }
}
}
}
@@ -1596,10 +1600,10 @@
return mManagerService;
}
- private ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks = new ArrayList<IBluetoothManagerCallback>();
+ final private ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks = new ArrayList<IBluetoothManagerCallback>();
/*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
- synchronized (mManagerCallback) {
+ synchronized (mProxyServiceStateCallbacks) {
if (cb == null) {
Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback");
} else if (!mProxyServiceStateCallbacks.contains(cb)) {
@@ -1610,7 +1614,7 @@
}
/*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
- synchronized (mManagerCallback) {
+ synchronized (mProxyServiceStateCallbacks) {
mProxyServiceStateCallbacks.remove(cb);
}
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 5e50b69..bb0d0a3 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -18,6 +18,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
@@ -67,6 +68,14 @@
private static final boolean DBG = false;
/**
+ * Connection state bitmask as returned by getConnectionState.
+ */
+ private static final int CONNECTION_STATE_DISCONNECTED = 0;
+ private static final int CONNECTION_STATE_CONNECTED = 1;
+ private static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2;
+ private static final int CONNECTION_STATE_ENCRYPTED_LE = 4;
+
+ /**
* Sentinel error value for this class. Guaranteed to not equal any other
* integer constant in this class. Provided as a convenience for functions
* that require a sentinel error value, for example:
@@ -940,13 +949,36 @@
* @return True if there is at least one open connection to this device.
* @hide
*/
+ @SystemApi
public boolean isConnected() {
if (sService == null) {
// BT is not enabled, we cannot be connected.
return false;
}
try {
- return sService.isConnected(this);
+ return sService.getConnectionState(this) != CONNECTION_STATE_DISCONNECTED;
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ return false;
+ }
+ }
+
+ /**
+ * Returns whether there is an open connection to this device
+ * that has been encrypted.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
+ *
+ * @return True if there is at least one encrypted connection to this device.
+ * @hide
+ */
+ @SystemApi
+ public boolean isEncrypted() {
+ if (sService == null) {
+ // BT is not enabled, we cannot be connected.
+ return false;
+ }
+ try {
+ return sService.getConnectionState(this) > CONNECTION_STATE_CONNECTED;
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index cd4535a..dabb1ce 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -59,7 +59,7 @@
boolean cancelBondProcess(in BluetoothDevice device);
boolean removeBond(in BluetoothDevice device);
int getBondState(in BluetoothDevice device);
- boolean isConnected(in BluetoothDevice device);
+ int getConnectionState(in BluetoothDevice device);
String getRemoteName(in BluetoothDevice device);
int getRemoteType(in BluetoothDevice device);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 37a46be..582802b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1760,6 +1760,7 @@
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
+ @SystemApi
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
/**
@@ -3252,6 +3253,7 @@
/**
* @hide String array of package names.
*/
+ @SystemApi
public static final String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
/**
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index e07edba..e822708 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -334,44 +334,6 @@
public static final int FLAG_FULL_BACKUP_ONLY = 1<<26;
/**
- * Value for {@link #flags}: true if the application is hidden via restrictions and for
- * most purposes is considered as not installed.
- * {@hide}
- */
- public static final int FLAG_HIDDEN = 1<<27;
-
- /**
- * Value for {@link #flags}: set to <code>true</code> if the application
- * has reported that it is heavy-weight, and thus can not participate in
- * the normal application lifecycle.
- *
- * <p>Comes from the
- * android.R.styleable#AndroidManifestApplication_cantSaveState
- * attribute of the <application> tag.
- *
- * {@hide}
- */
- public static final int FLAG_CANT_SAVE_STATE = 1<<28;
-
- /**
- * Value for {@link #flags}: Set to true if the application has been
- * installed using the forward lock option.
- *
- * NOTE: DO NOT CHANGE THIS VALUE! It is saved in packages.xml.
- *
- * {@hide}
- */
- public static final int FLAG_FORWARD_LOCK = 1<<29;
-
- /**
- * Value for {@link #flags}: set to {@code true} if the application
- * is permitted to hold privileged permissions.
- *
- * {@hide}
- */
- public static final int FLAG_PRIVILEGED = 1<<30;
-
- /**
* Value for {@link #flags}: true if code from this application will need to be
* loaded into other applications' processes. On devices that support multiple
* instruction sets, this implies the code might be loaded into a process that's
@@ -395,11 +357,60 @@
* {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_SUPPORTS_XLARGE_SCREENS},
* {@link #FLAG_RESIZEABLE_FOR_SCREENS},
* {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE},
- * {@link #FLAG_INSTALLED}, {@link #FLAG_IS_GAME}.
+ * {@link #FLAG_ALLOW_BACKUP}, {@link #FLAG_KILL_AFTER_RESTORE},
+ * {@link #FLAG_RESTORE_ANY_VERSION}, {@link #FLAG_EXTERNAL_STORAGE},
+ * {@link #FLAG_LARGE_HEAP}, {@link #FLAG_STOPPED},
+ * {@link #FLAG_SUPPORTS_RTL}, {@link #FLAG_INSTALLED},
+ * {@link #FLAG_IS_DATA_ONLY}, {@link #FLAG_IS_GAME},
+ * {@link #FLAG_FULL_BACKUP_ONLY}, {@link #FLAG_MULTIARCH}.
*/
public int flags = 0;
/**
+ * Value for {@link #privateFlags}: true if the application is hidden via restrictions and for
+ * most purposes is considered as not installed.
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_HIDDEN = 1<<0;
+
+ /**
+ * Value for {@link #privateFlags}: set to <code>true</code> if the application
+ * has reported that it is heavy-weight, and thus can not participate in
+ * the normal application lifecycle.
+ *
+ * <p>Comes from the
+ * android.R.styleable#AndroidManifestApplication_cantSaveState
+ * attribute of the <application> tag.
+ *
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_CANT_SAVE_STATE = 1<<1;
+
+ /**
+ * Value for {@link #privateFlags}: Set to true if the application has been
+ * installed using the forward lock option.
+ *
+ * NOTE: DO NOT CHANGE THIS VALUE! It is saved in packages.xml.
+ *
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_FORWARD_LOCK = 1<<2;
+
+ /**
+ * Value for {@link #privateFlags}: set to {@code true} if the application
+ * is permitted to hold privileged permissions.
+ *
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_PRIVILEGED = 1<<3;
+
+ /**
+ * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
+ * {@hide}
+ */
+ public int privateFlags;
+
+ /**
* The required smallest screen width the application can run on. If 0,
* nothing has been specified. Comes from
* {@link android.R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp
@@ -598,6 +609,7 @@
pw.println(prefix + "processName=" + processName);
pw.println(prefix + "taskAffinity=" + taskAffinity);
pw.println(prefix + "uid=" + uid + " flags=0x" + Integer.toHexString(flags)
+ + " privateFlags=0x" + Integer.toHexString(privateFlags)
+ " theme=0x" + Integer.toHexString(theme));
pw.println(prefix + "requiresSmallestWidthDp=" + requiresSmallestWidthDp
+ " compatibleWidthLimitDp=" + compatibleWidthLimitDp
@@ -680,6 +692,7 @@
className = orig.className;
theme = orig.theme;
flags = orig.flags;
+ privateFlags = orig.privateFlags;
requiresSmallestWidthDp = orig.requiresSmallestWidthDp;
compatibleWidthLimitDp = orig.compatibleWidthLimitDp;
largestWidthLimitDp = orig.largestWidthLimitDp;
@@ -730,6 +743,7 @@
dest.writeString(className);
dest.writeInt(theme);
dest.writeInt(flags);
+ dest.writeInt(privateFlags);
dest.writeInt(requiresSmallestWidthDp);
dest.writeInt(compatibleWidthLimitDp);
dest.writeInt(largestWidthLimitDp);
@@ -779,6 +793,7 @@
className = source.readString();
theme = source.readInt();
flags = source.readInt();
+ privateFlags = source.readInt();
requiresSmallestWidthDp = source.readInt();
compatibleWidthLimitDp = source.readInt();
largestWidthLimitDp = source.readInt();
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0dc86ad..b518498 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -111,6 +111,8 @@
int getFlagsForUid(int uid);
+ int getPrivateFlagsForUid(int uid);
+
boolean isUidPrivileged(int uid);
String[] getAppOpPermissionPackages(String permissionName);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 04777ba..b0e0300 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -800,6 +800,7 @@
pkg.splitCodePaths = lite.splitCodePaths;
pkg.splitRevisionCodes = lite.splitRevisionCodes;
pkg.splitFlags = new int[num];
+ pkg.splitPrivateFlags = new int[num];
for (int i = 0; i < num; i++) {
parseSplitApk(pkg, i, assets, flags);
@@ -1405,7 +1406,7 @@
/* Set the global "forward lock" flag */
if ((flags & PARSE_FORWARD_LOCK) != 0) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK;
+ pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
}
/* Set the global "on SD card" flag */
@@ -2608,7 +2609,7 @@
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
false)) {
- ai.flags |= ApplicationInfo.FLAG_CANT_SAVE_STATE;
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
// A heavy-weight application can not be in a custom process.
// We can do direct compare because we intern all strings.
@@ -3083,9 +3084,6 @@
a.info.maxRecents = sa.getInt(
R.styleable.AndroidManifestActivity_maxRecents,
ActivityManager.getDefaultAppRecentsLimitStatic());
- a.info.screenOrientation = sa.getInt(
- R.styleable.AndroidManifestActivity_screenOrientation,
- ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
a.info.configChanges = sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0);
a.info.softInputMode = sa.getInt(
R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
@@ -3113,6 +3111,14 @@
a.info.resizeable = sa.getBoolean(
R.styleable.AndroidManifestActivity_resizeableActivity,
owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.MNC);
+ if (a.info.resizeable) {
+ // Fixed screen orientation isn't supported with resizeable activities.
+ a.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ } else {
+ a.info.screenOrientation = sa.getInt(
+ R.styleable.AndroidManifestActivity_screenOrientation,
+ ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ }
} else {
a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
a.info.configChanges = 0;
@@ -3131,7 +3137,8 @@
sa.recycle();
- if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+ if (receiver && (owner.applicationInfo.privateFlags
+ &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
// A heavy-weight application can not have receives in its main process
// We can do direct compare because we intern all strings.
if (a.info.processName == owner.packageName) {
@@ -3484,7 +3491,8 @@
sa.recycle();
- if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+ if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+ != 0) {
// A heavy-weight application can not have providers in its main process
// We can do direct compare because we intern all strings.
if (p.info.processName == owner.packageName) {
@@ -3763,7 +3771,8 @@
sa.recycle();
- if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+ if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+ != 0) {
// A heavy-weight application can not have services in its main process
// We can do direct compare because we intern all strings.
if (s.info.processName == owner.packageName) {
@@ -4181,6 +4190,13 @@
/** Flags of any split APKs; ordered by parsed splitName */
public int[] splitFlags;
+ /**
+ * Private flags of any split APKs; ordered by parsed splitName.
+ *
+ * {@hide}
+ */
+ public int[] splitPrivateFlags;
+
public boolean baseHardwareAccelerated;
// For now we only support one application per package.
@@ -4616,9 +4632,9 @@
ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
}
if (state.hidden) {
- ai.flags |= ApplicationInfo.FLAG_HIDDEN;
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
} else {
- ai.flags &= ~ApplicationInfo.FLAG_HIDDEN;
+ ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
}
if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
ai.enabled = true;
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 391ef22..a386097 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -35,6 +35,7 @@
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.google.android.collect.Lists;
@@ -56,6 +57,8 @@
import java.util.List;
import java.util.Map;
+import libcore.io.IoUtils;
+
/**
* Cache of registered services. This cache is lazily built by interrogating
* {@link PackageManager} on a per-user basis. It's updated as packages are
@@ -113,13 +116,19 @@
public RegisteredServicesCache(Context context, String interfaceName, String metaDataName,
String attributeName, XmlSerializerAndParser<V> serializerAndParser) {
+ this(context, interfaceName, metaDataName, attributeName, serializerAndParser,
+ Environment.getDataDirectory());
+ }
+
+ @VisibleForTesting
+ protected RegisteredServicesCache(Context context, String interfaceName, String metaDataName,
+ String attributeName, XmlSerializerAndParser<V> serializerAndParser, File dataDir) {
mContext = context;
mInterfaceName = interfaceName;
mMetaDataName = metaDataName;
mAttributesName = attributeName;
mSerializerAndParser = serializerAndParser;
- File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
File syncDir = new File(systemDir, "registered_services");
mPersistentServicesFile = new AtomicFile(new File(syncDir, interfaceName + ".xml"));
@@ -303,7 +312,8 @@
}
}
- private boolean inSystemImage(int callerUid) {
+ @VisibleForTesting
+ protected boolean inSystemImage(int callerUid) {
String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
for (String name : packages) {
try {
@@ -319,6 +329,13 @@
return false;
}
+ @VisibleForTesting
+ protected List<ResolveInfo> queryIntentServices(int userId) {
+ final PackageManager pm = mContext.getPackageManager();
+ return pm.queryIntentServicesAsUser(
+ new Intent(mInterfaceName), PackageManager.GET_META_DATA, userId);
+ }
+
/**
* Populate {@link UserServices#services} by scanning installed packages for
* given {@link UserHandle}.
@@ -331,10 +348,8 @@
Slog.d(TAG, "generateServicesMap() for " + userId + ", changed UIDs = " + changedUids);
}
- final PackageManager pm = mContext.getPackageManager();
final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<ServiceInfo<V>>();
- final List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(
- new Intent(mInterfaceName), PackageManager.GET_META_DATA, userId);
+ final List<ResolveInfo> resolveInfos = queryIntentServices(userId);
for (ResolveInfo resolveInfo : resolveInfos) {
try {
ServiceInfo<V> info = parseServiceInfo(resolveInfo);
@@ -343,9 +358,7 @@
continue;
}
serviceInfos.add(info);
- } catch (XmlPullParserException e) {
- Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e);
- } catch (IOException e) {
+ } catch (XmlPullParserException|IOException e) {
Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e);
}
}
@@ -481,7 +494,8 @@
return false;
}
- private ServiceInfo<V> parseServiceInfo(ResolveInfo service)
+ @VisibleForTesting
+ protected ServiceInfo<V> parseServiceInfo(ResolveInfo service)
throws XmlPullParserException, IOException {
android.content.pm.ServiceInfo si = service.serviceInfo;
ComponentName componentName = new ComponentName(si.packageName, si.name);
@@ -571,12 +585,7 @@
} catch (Exception e) {
Log.w(TAG, "Error reading persistent services, starting from scratch", e);
} finally {
- if (fis != null) {
- try {
- fis.close();
- } catch (java.io.IOException e1) {
- }
- }
+ IoUtils.closeQuietly(fis);
}
}
@@ -607,7 +616,7 @@
out.endTag(null, "services");
out.endDocument();
mPersistentServicesFile.finishWrite(fos);
- } catch (java.io.IOException e1) {
+ } catch (IOException e1) {
Log.w(TAG, "Error writing accounts", e1);
if (fos != null) {
mPersistentServicesFile.failWrite(fos);
@@ -615,6 +624,11 @@
}
}
+ @VisibleForTesting
+ protected Map<V, Integer> getPersistentServices(int userId) {
+ return findOrCreateUserLocked(userId).persistentServices;
+ }
+
public abstract V parseServiceAttributes(Resources res,
String packageName, AttributeSet attrs);
}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index cf6a779..fa5e9d2 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -18,6 +18,7 @@
package android.hardware;
import android.os.Build;
+import android.annotation.SystemApi;
/**
* Class representing a sensor. Use {@link SensorManager#getSensorList} to get
@@ -511,6 +512,27 @@
*/
public static final String STRING_TYPE_PICK_UP_GESTURE = "android.sensor.pick_up_gesture";
+ /**
+ * A constant describing a wrist tilt gesture sensor.
+ *
+ * A sensor of this type triggers when the device face is tilted towards the user.
+ * The only allowed return value is 1.0.
+ * This sensor remains active until disabled.
+ *
+ * @hide This sensor is expected to only be used by the system ui
+ */
+ @SystemApi
+ public static final int TYPE_WRIST_TILT_GESTURE = 26;
+
+ /**
+ * A constant string describing a wrist tilt gesture sensor.
+ *
+ * @hide This sensor is expected to only be used by the system ui
+ * @see #TYPE_WRIST_TILT_GESTURE
+ */
+ @SystemApi
+ public static final String STRING_TYPE_WRIST_TILT_GESTURE = "android.sensor.wrist_tilt_gesture";
+
/**
* A constant describing all sensor types.
*/
@@ -591,6 +613,7 @@
1, // SENSOR_TYPE_WAKE_GESTURE
1, // SENSOR_TYPE_GLANCE_GESTURE
1, // SENSOR_TYPE_PICK_UP_GESTURE
+ 1, // SENSOR_TYPE_WRIST_TILT_GESTURE
};
/**
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index e4e5a8c..34b895b 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -451,7 +451,8 @@
// non_wake-up version.
if (type == Sensor.TYPE_PROXIMITY || type == Sensor.TYPE_SIGNIFICANT_MOTION ||
type == Sensor.TYPE_TILT_DETECTOR || type == Sensor.TYPE_WAKE_GESTURE ||
- type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE) {
+ type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE ||
+ type == Sensor.TYPE_WRIST_TILT_GESTURE) {
wakeUpSensor = true;
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 4c3a4a6..60ff32c 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1943,6 +1943,23 @@
new Key<Integer>("android.sensor.info.timestampSource", int.class);
/**
+ * <p>Whether the RAW images output from this camera device are subject to
+ * lens shading correction.</p>
+ * <p>If TRUE, all images produced by the camera device in the RAW image formats will
+ * have lens shading correction already applied to it. If FALSE, the images will
+ * not be adjusted for lens shading correction.
+ * See {@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW android.request.maxNumOutputRaw} for a list of RAW image formats.</p>
+ * <p>This key will be <code>null</code> for all devices do not report this information.
+ * Devices with RAW capability will always report this information in this key.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW
+ */
+ @PublicKey
+ public static final Key<Boolean> SENSOR_INFO_LENS_SHADING_APPLIED =
+ new Key<Boolean>("android.sensor.info.lensShadingApplied", boolean.class);
+
+ /**
* <p>The standard reference illuminant used as the scene light source when
* calculating the {@link CameraCharacteristics#SENSOR_COLOR_TRANSFORM1 android.sensor.colorTransform1},
* {@link CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM1 android.sensor.calibrationTransform1}, and
@@ -2233,6 +2250,22 @@
new Key<int[]>("android.sensor.availableTestPatternModes", int[].class);
/**
+ * <p>List of lens shading modes for {@link CaptureRequest#SHADING_MODE android.shading.mode} that are supported by this camera device.</p>
+ * <p>This list contains lens shading modes that can be set for the camera device.
+ * Camera devices that support the MANUAL_POST_PROCESSING capability will always
+ * list OFF and FAST mode. This includes all FULL level devices.
+ * LEGACY devices will always only support FAST mode.</p>
+ * <p><b>Range of valid values:</b><br>
+ * Any value listed in {@link CaptureRequest#SHADING_MODE android.shading.mode}</p>
+ * <p>This key is available on all devices.</p>
+ *
+ * @see CaptureRequest#SHADING_MODE
+ */
+ @PublicKey
+ public static final Key<int[]> SHADING_AVAILABLE_MODES =
+ new Key<int[]>("android.shading.availableModes", int[].class);
+
+ /**
* <p>List of face detection modes for {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} that are
* supported by this camera device.</p>
* <p>OFF is always supported.</p>
@@ -2276,6 +2309,23 @@
new Key<boolean[]>("android.statistics.info.availableHotPixelMapModes", boolean[].class);
/**
+ * <p>List of lens shading map output modes for {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode} that
+ * are supported by this camera device.</p>
+ * <p>If no lens shading map output is available for this camera device, this key will
+ * contain only OFF.</p>
+ * <p>ON is always supported on devices with the RAW capability.
+ * LEGACY mode devices will always only support OFF.</p>
+ * <p><b>Range of valid values:</b><br>
+ * Any value listed in {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode}</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
+ */
+ @PublicKey
+ public static final Key<byte[]> STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES =
+ new Key<byte[]>("android.statistics.info.availableLensShadingMapModes", byte[].class);
+
+ /**
* <p>Maximum number of supported points in the
* tonemap curve that can be used for {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}.</p>
* <p>If the actual number of points provided by the application (in {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}*) is
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index a6a93a2..7569ea5 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2118,6 +2118,8 @@
* <li>{@link #SHADING_MODE_FAST FAST}</li>
* <li>{@link #SHADING_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
* </ul></p>
+ * <p><b>Available values for this device:</b><br>
+ * {@link CameraCharacteristics#SHADING_AVAILABLE_MODES android.shading.availableModes}</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Full capability</b> -
* Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -2126,6 +2128,7 @@
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_AWB_MODE
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ * @see CameraCharacteristics#SHADING_AVAILABLE_MODES
* @see CaptureResult#STATISTICS_LENS_SHADING_CORRECTION_MAP
* @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
* @see #SHADING_MODE_OFF
@@ -2188,12 +2191,15 @@
* <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_OFF OFF}</li>
* <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_ON ON}</li>
* </ul></p>
+ * <p><b>Available values for this device:</b><br>
+ * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES android.statistics.info.availableLensShadingMapModes}</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Full capability</b> -
* Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ * @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES
* @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
* @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
*/
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 96dcede..b84dc2e 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3054,6 +3054,8 @@
* <li>{@link #SHADING_MODE_FAST FAST}</li>
* <li>{@link #SHADING_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
* </ul></p>
+ * <p><b>Available values for this device:</b><br>
+ * {@link CameraCharacteristics#SHADING_AVAILABLE_MODES android.shading.availableModes}</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Full capability</b> -
* Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -3062,6 +3064,7 @@
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_AWB_MODE
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ * @see CameraCharacteristics#SHADING_AVAILABLE_MODES
* @see CaptureResult#STATISTICS_LENS_SHADING_CORRECTION_MAP
* @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
* @see #SHADING_MODE_OFF
@@ -3225,7 +3228,7 @@
/**
* <p>The shading map is a low-resolution floating-point map
* that lists the coefficients used to correct for vignetting, for each
- * Bayer color channel.</p>
+ * Bayer color channel of RAW image data.</p>
* <p>The least shaded section of the image should have a gain factor
* of 1; all other sections should have gains above 1.</p>
* <p>When {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} = TRANSFORM_MATRIX, the map
@@ -3261,8 +3264,20 @@
* <img alt="Green (odd rows) lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png" />
* <img alt="Blue lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png" /></p>
* <p>As a visualization only, inverting the full-color map to recover an
- * image of a gray wall (using bicubic interpolation for visual quality) as captured by the sensor gives:</p>
+ * image of a gray wall (using bicubic interpolation for visual quality)
+ * as captured by the sensor gives:</p>
* <p><img alt="Image of a uniform white wall (inverse shading map)" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
+ * <p>Note that the RAW image data might be subject to lens shading
+ * correction not reported on this map. Query
+ * {@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied} to see if RAW image data has subject
+ * to lens shading correction. If {@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied}
+ * is TRUE, the RAW image data is subject to partial or full lens shading
+ * correction. In the case full lens shading correction is applied to RAW
+ * images, the gain factor map reported in this key will contain all 1.0 gains.
+ * In other words, the map reported in this key is the remaining lens shading
+ * that needs to be applied on the RAW image to get images without lens shading
+ * artifacts. See {@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW android.request.maxNumOutputRaw} for a list of RAW image
+ * formats.</p>
* <p><b>Range of valid values:</b><br>
* Each gain factor is >= 1</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -3272,6 +3287,8 @@
*
* @see CaptureRequest#COLOR_CORRECTION_MODE
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ * @see CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW
+ * @see CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED
* @hide
*/
public static final Key<float[]> STATISTICS_LENS_SHADING_MAP =
@@ -3409,12 +3426,15 @@
* <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_OFF OFF}</li>
* <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_ON ON}</li>
* </ul></p>
+ * <p><b>Available values for this device:</b><br>
+ * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES android.statistics.info.availableLensShadingMapModes}</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Full capability</b> -
* Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ * @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES
* @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
* @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
*/
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index f1f2f0c..cf3510d 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -85,7 +85,7 @@
private static final int PREVIEW_FRAME_TIMEOUT = 1000; // ms
private static final int JPEG_FRAME_TIMEOUT = 4000; // ms (same as CTS for API2)
- private static final int REQUEST_COMPLETE_TIMEOUT = JPEG_FRAME_TIMEOUT; // ms (same as JPEG timeout)
+ private static final int REQUEST_COMPLETE_TIMEOUT = JPEG_FRAME_TIMEOUT;
private static final float ASPECT_RATIO_TOLERANCE = 0.01f;
private boolean mPreviewRunning = false;
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
index 518a874..cc018e9 100644
--- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
+++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
@@ -104,7 +104,7 @@
try {
ai = pm.getApplicationInfo(
ri.activityInfo.packageName, PackageManager.GET_META_DATA);
- if ((ai.flags & ApplicationInfo.FLAG_PRIVILEGED) == 0) {
+ if ((ai.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) == 0) {
// The application isn't privileged (/system/priv-app).
// The enrollment application needs to be a privileged system app.
Slog.w(TAG, ai.packageName + "is not a privileged system app");
diff --git a/core/java/android/net/PacProxySelector.java b/core/java/android/net/PacProxySelector.java
index 8626d08..9bdf4f6 100644
--- a/core/java/android/net/PacProxySelector.java
+++ b/core/java/android/net/PacProxySelector.java
@@ -16,7 +16,6 @@
package android.net;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
@@ -74,8 +73,8 @@
}
try {
response = mProxyService.resolvePacFile(uri.getHost(), urlString);
- } catch (RemoteException e) {
- e.printStackTrace();
+ } catch (Exception e) {
+ Log.e(TAG, "Error resolving PAC File", e);
}
if (response == null) {
return mDefaultList;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index e4b594a..eb86e7e 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -650,15 +650,22 @@
}
/**
- * Check that device fingerprint is defined and that it matches across
- * various partitions.
+ * Verifies the the current flash of the device is consistent with what
+ * was expected at build time.
+ * 1) Checks that device fingerprint is defined and that it matches across
+ * various partitions.
+ * 2) Verifies radio and bootloader partitions are those expected in the build.
*
* @hide
*/
- public static boolean isFingerprintConsistent() {
+ public static boolean isBuildConsistent() {
final String system = SystemProperties.get("ro.build.fingerprint");
final String vendor = SystemProperties.get("ro.vendor.build.fingerprint");
final String bootimage = SystemProperties.get("ro.bootimage.build.fingerprint");
+ final String requiredBootloader = SystemProperties.get("ro.build.expect.bootloader");
+ final String currentBootloader = SystemProperties.get("ro.bootloader");
+ final String requiredRadio = SystemProperties.get("ro.build.expect.baseband");
+ final String currentRadio = SystemProperties.get("gsm.version.baseband");
if (TextUtils.isEmpty(system)) {
Slog.e(TAG, "Required ro.build.fingerprint is empty!");
@@ -681,6 +688,22 @@
}
}
+ if (!TextUtils.isEmpty(requiredBootloader)) {
+ if (!Objects.equals(currentBootloader, requiredBootloader)) {
+ Slog.e(TAG, "Mismatched bootloader version: build requires " + requiredBootloader
+ + " but runtime reports " + currentBootloader);
+ return false;
+ }
+ }
+
+ if (!TextUtils.isEmpty(requiredRadio)) {
+ if (!Objects.equals(currentRadio, requiredRadio)) {
+ Slog.e(TAG, "Mismatched radio version: build requires " + requiredRadio
+ + " but runtime reports " + currentRadio);
+ return false;
+ }
+ }
+
return true;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index dddbe78..250e80f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2473,7 +2473,7 @@
/**
* Log raw orientation data from
- * {@link com.android.internal.policy.impl.WindowOrientationListener} for use with the
+ * {@link com.android.server.policy.WindowOrientationListener} for use with the
* orientationplot.py tool.
* 0 = no
* 1 = yes
@@ -6545,7 +6545,7 @@
/**
* Defines global runtime overrides to window policy.
*
- * See {@link com.android.internal.policy.impl.PolicyControl} for value format.
+ * See {@link com.android.server.policy.PolicyControl} for value format.
*
* @hide
*/
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 38b043971..3c57dda 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -37,6 +37,7 @@
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
+import android.view.PhoneWindow;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
@@ -46,7 +47,6 @@
import android.view.accessibility.AccessibilityEvent;
import android.util.MathUtils;
-import com.android.internal.policy.PolicyManager;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.DumpUtils.Dump;
@@ -945,7 +945,7 @@
throw new IllegalStateException("Only doze dreams can be windowless");
}
if (!mWindowless) {
- mWindow = PolicyManager.makeNewWindow(this);
+ mWindow = new PhoneWindow(this);
mWindow.setCallback(this);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/core/java/android/view/PhoneFallbackEventHandler.java
similarity index 96%
rename from policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
rename to core/java/android/view/PhoneFallbackEventHandler.java
index f291e89..fbf5732 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
+++ b/core/java/android/view/PhoneFallbackEventHandler.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package android.view;
import android.app.KeyguardManager;
import android.app.SearchManager;
@@ -23,19 +23,14 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.media.AudioManager;
-import android.media.IAudioService;
import android.media.session.MediaSessionLegacyHelper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
-import android.util.Log;
import android.util.Slog;
-import android.view.View;
-import android.view.HapticFeedbackConstants;
-import android.view.FallbackEventHandler;
-import android.view.KeyEvent;
+/**
+ * @hide
+ */
public class PhoneFallbackEventHandler implements FallbackEventHandler {
private static String TAG = "PhoneFallbackEventHandler";
private static final boolean DEBUG = false;
@@ -283,7 +278,7 @@
}
void sendCloseSystemWindows() {
- PhoneWindowManager.sendCloseSystemWindows(mContext, null);
+ PhoneWindow.sendCloseSystemWindows(mContext, null);
}
private void handleMediaKeyEvent(KeyEvent keyEvent) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java b/core/java/android/view/PhoneLayoutInflater.java
similarity index 93%
rename from policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java
rename to core/java/android/view/PhoneLayoutInflater.java
index df6fca4c..7d89a0b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java
+++ b/core/java/android/view/PhoneLayoutInflater.java
@@ -14,37 +14,38 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package android.view;
import android.content.Context;
import android.util.AttributeSet;
-import android.view.View;
-import android.view.LayoutInflater;
+/**
+ * @hide
+ */
public class PhoneLayoutInflater extends LayoutInflater {
private static final String[] sClassPrefixList = {
"android.widget.",
"android.webkit.",
"android.app."
};
-
+
/**
* Instead of instantiating directly, you should retrieve an instance
* through {@link Context#getSystemService}
- *
+ *
* @param context The Context in which in which to find resources and other
* application-specific things.
- *
+ *
* @see Context#getSystemService
*/
public PhoneLayoutInflater(Context context) {
super(context);
}
-
+
protected PhoneLayoutInflater(LayoutInflater original, Context newContext) {
super(original, newContext);
}
-
+
/** Override onCreateView to instantiate names that correspond to the
widgets known to the Widget factory. If we don't find a match,
call through to our super class.
@@ -64,7 +65,7 @@
return super.onCreateView(name, attrs);
}
-
+
public LayoutInflater cloneInContext(Context newContext) {
return new PhoneLayoutInflater(this, newContext);
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/PhoneWindow.java
rename to core/java/android/view/PhoneWindow.java
index ab51f57..5f4d201 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/core/java/android/view/PhoneWindow.java
@@ -13,7 +13,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package android.view;
import static android.view.View.MeasureSpec.AT_MOST;
import static android.view.View.MeasureSpec.EXACTLY;
@@ -22,6 +22,7 @@
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.*;
+import android.app.ActivityManagerNative;
import android.app.SearchManager;
import android.os.UserHandle;
import com.android.internal.R;
@@ -72,31 +73,6 @@
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
-import android.view.ActionMode;
-import android.view.ContextThemeWrapper;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.IRotationWatcher;
-import android.view.IWindowManager;
-import android.view.InputEvent;
-import android.view.InputQueue;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewManager;
-import android.view.ViewParent;
-import android.view.ViewRootImpl;
-import android.view.ViewStub;
-import android.view.Window;
-import android.view.WindowInsets;
-import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Animation;
@@ -116,6 +92,8 @@
* <p>
* todo: need to pull the generic functionality out into a base class
* in android.widget.
+ *
+ * @hide
*/
public class PhoneWindow extends Window implements MenuBuilder.Callback {
@@ -4754,11 +4732,20 @@
}
void sendCloseSystemWindows() {
- PhoneWindowManager.sendCloseSystemWindows(getContext(), null);
+ sendCloseSystemWindows(getContext(), null);
}
void sendCloseSystemWindows(String reason) {
- PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
+ sendCloseSystemWindows(getContext(), reason);
+ }
+
+ public static void sendCloseSystemWindows(Context context, String reason) {
+ if (ActivityManagerNative.isSystemReady()) {
+ try {
+ ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ }
+ }
}
@Override
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f60e2f8..04aafc1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3582,7 +3582,7 @@
* @param attrs The attributes of the XML tag that is inflating the view.
* @see #View(Context, AttributeSet, int)
*/
- public View(Context context, AttributeSet attrs) {
+ public View(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -3603,7 +3603,7 @@
* the view. Can be 0 to not look for defaults.
* @see #View(Context, AttributeSet)
*/
- public View(Context context, AttributeSet attrs, int defStyleAttr) {
+ public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
@@ -3640,7 +3640,7 @@
* to not look for defaults.
* @see #View(Context, AttributeSet, int)
*/
- public View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
this(context);
final TypedArray a = context.obtainStyledAttributes(
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0e114ef..e1cee1e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1933,12 +1933,9 @@
mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
}
- // Whether this event should be handled by the accessibility focus first.
- final boolean targetAccessibilityFocus = ev.isTargetAccessibilityFocus();
-
// If the event targets the accessibility focused view and this is it, start
// normal event dispatch. Maybe a descendant is what will handle the click.
- if (targetAccessibilityFocus && isAccessibilityFocusedViewOrHost()) {
+ if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
ev.setTargetAccessibilityFocus(false);
}
@@ -1958,24 +1955,25 @@
// Check for interception.
final boolean intercepted;
- if (!targetAccessibilityFocus) {
- if (actionMasked == MotionEvent.ACTION_DOWN
- || mFirstTouchTarget != null) {
- final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
- if (!disallowIntercept) {
- intercepted = onInterceptTouchEvent(ev);
- ev.setAction(action); // restore action in case it was changed
- } else {
- intercepted = false;
- }
+ if (actionMasked == MotionEvent.ACTION_DOWN
+ || mFirstTouchTarget != null) {
+ final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
+ if (!disallowIntercept) {
+ intercepted = onInterceptTouchEvent(ev);
+ ev.setAction(action); // restore action in case it was changed
} else {
- // There are no touch targets and this action is not an initial down
- // so this view group continues to intercept touches.
- intercepted = true;
+ intercepted = false;
}
} else {
- // If event should reach the accessibility focus first, do not intercept it.
- intercepted = false;
+ // There are no touch targets and this action is not an initial down
+ // so this view group continues to intercept touches.
+ intercepted = true;
+ }
+
+ // If intercepted, start normal event dispatch. Also if there is already
+ // a view that is handling the gesture, do normal event dispatch.
+ if (intercepted || mFirstTouchTarget != null) {
+ ev.setTargetAccessibilityFocus(false);
}
// Check for cancelation.
@@ -1987,10 +1985,18 @@
TouchTarget newTouchTarget = null;
boolean alreadyDispatchedToNewTouchTarget = false;
if (!canceled && !intercepted) {
+
+ // If the event is targeting accessiiblity focus we give it to the
+ // view that has accessibility focus and if it does not handle it
+ // we clear the flag and dispatch the event to all children as usual.
+ // We are looking up the accessibility focused host to avoid keeping
+ // state since these events are very rare.
+ View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
+ ? findChildWithAccessibilityFocus() : null;
+
if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
- || actionMasked == MotionEvent.ACTION_HOVER_MOVE
- || targetAccessibilityFocus) {
+ || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
final int actionIndex = ev.getActionIndex(); // always 0 for down
final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
: TouchTarget.ALL_POINTER_IDS;
@@ -2014,8 +2020,22 @@
? getChildDrawingOrder(childrenCount, i) : i;
final View child = (preorderedList == null)
? children[childIndex] : preorderedList.get(childIndex);
+
+ // If there is a view that has accessibility focus we want it
+ // to get the event first and if not handled we will perform a
+ // normal dispatch. We may do a double iteration but this is
+ // safer given the timeframe.
+ if (childWithAccessibilityFocus != null) {
+ if (childWithAccessibilityFocus != child) {
+ continue;
+ }
+ childWithAccessibilityFocus = null;
+ i = childrenCount - 1;
+ }
+
if (!canViewReceivePointerEvents(child)
|| !isTransformedTouchPointInView(x, y, child, null)) {
+ ev.setTargetAccessibilityFocus(false);
continue;
}
@@ -2048,6 +2068,10 @@
alreadyDispatchedToNewTouchTarget = true;
break;
}
+
+ // The accessibility focus didn't handle the event, so clear
+ // the flag and do a normal dispatch to all children.
+ ev.setTargetAccessibilityFocus(false);
}
if (preorderedList != null) preorderedList.clear();
}
@@ -2120,6 +2144,34 @@
}
/**
+ * Finds the child which has accessibility focus.
+ *
+ * @return The child that has focus.
+ */
+ private View findChildWithAccessibilityFocus() {
+ ViewRootImpl viewRoot = getViewRootImpl();
+ if (viewRoot == null) {
+ return null;
+ }
+
+ View current = viewRoot.getAccessibilityFocusedHost();
+ if (current == null) {
+ return null;
+ }
+
+ ViewParent parent = current.getParent();
+ while (parent instanceof View) {
+ if (parent == this) {
+ return current;
+ }
+ current = (View) parent;
+ parent = current.getParent();
+ }
+
+ return null;
+ }
+
+ /**
* Resets all touch state in preparation for a new cycle.
*/
private void resetTouchState() {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 570cb72..fb2a8d8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -76,7 +76,6 @@
import com.android.internal.R;
import com.android.internal.os.SomeArgs;
-import com.android.internal.policy.PolicyManager;
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.RootViewSurfaceTaker;
@@ -386,7 +385,7 @@
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
- mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
+ mFallbackEventHandler = new PhoneFallbackEventHandler(context);
mChoreographer = Choreographer.getInstance();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
loadSystemProperties();
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 8704356..1456b52 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -42,10 +42,8 @@
* area, default key processing, etc.
*
* <p>The only existing implementation of this abstract class is
- * android.policy.PhoneWindow, which you should instantiate when needing a
- * Window. Eventually that class will be refactored and a factory method
- * added for creating Window instances without knowing about a particular
- * implementation.
+ * android.view.PhoneWindow, which you should instantiate when needing a
+ * Window.
*/
public abstract class Window {
/** Flag for the "options panel" feature. This is enabled by default. */
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 757038c..dd9bdb66 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -127,15 +127,16 @@
initImageView();
}
- public ImageView(Context context, AttributeSet attrs) {
+ public ImageView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public ImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
- public ImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initImageView();
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 380b328..0b63843 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -28,6 +28,7 @@
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.PhoneWindow;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
@@ -36,8 +37,6 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.SeekBar.OnSeekBarChangeListener;
-import com.android.internal.policy.PolicyManager;
-
import java.util.Formatter;
import java.util.Locale;
@@ -128,7 +127,7 @@
private void initFloatingWindow() {
mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
- mWindow = PolicyManager.makeNewWindow(mContext);
+ mWindow = new PhoneWindow(mContext);
mWindow.setWindowManager(mWindowManager, null, null);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mDecor = mWindow.getDecorView();
diff --git a/core/java/com/android/internal/policy/IPolicy.java b/core/java/com/android/internal/policy/IPolicy.java
deleted file mode 100644
index d08b3b4..0000000
--- a/core/java/com/android/internal/policy/IPolicy.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.internal.policy;
-
-import android.content.Context;
-import android.view.FallbackEventHandler;
-import android.view.LayoutInflater;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-/**
- * {@hide}
- */
-
-/* The implementation of this interface must be called Policy and contained
- * within the com.android.internal.policy.impl package */
-public interface IPolicy {
- public Window makeNewWindow(Context context);
-
- public LayoutInflater makeNewLayoutInflater(Context context);
-
- public WindowManagerPolicy makeNewWindowManager();
-
- public FallbackEventHandler makeNewFallbackEventHandler(Context context);
-}
diff --git a/core/java/com/android/internal/policy/PolicyManager.java b/core/java/com/android/internal/policy/PolicyManager.java
deleted file mode 100644
index 462b3a9..0000000
--- a/core/java/com/android/internal/policy/PolicyManager.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.internal.policy;
-
-import android.content.Context;
-import android.view.FallbackEventHandler;
-import android.view.LayoutInflater;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-/**
- * {@hide}
- */
-
-public final class PolicyManager {
- private static final String POLICY_IMPL_CLASS_NAME =
- "com.android.internal.policy.impl.Policy";
-
- private static final IPolicy sPolicy;
-
- static {
- // Pull in the actual implementation of the policy at run-time
- try {
- Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
- sPolicy = (IPolicy)policyClass.newInstance();
- } catch (ClassNotFoundException ex) {
- throw new RuntimeException(
- POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);
- } catch (InstantiationException ex) {
- throw new RuntimeException(
- POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
- } catch (IllegalAccessException ex) {
- throw new RuntimeException(
- POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
- }
- }
-
- // Cannot instantiate this class
- private PolicyManager() {}
-
- // The static methods to spawn new policy-specific objects
- public static Window makeNewWindow(Context context) {
- return sPolicy.makeNewWindow(context);
- }
-
- public static LayoutInflater makeNewLayoutInflater(Context context) {
- return sPolicy.makeNewLayoutInflater(context);
- }
-
- public static WindowManagerPolicy makeNewWindowManager() {
- return sPolicy.makeNewWindowManager();
- }
-
- public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
- return sPolicy.makeNewFallbackEventHandler(context);
- }
-}
diff --git a/core/res/res/color/btn_default_material_dark.xml b/core/res/res/color/btn_default_material_dark.xml
index 9be1417..e77af37 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_dark"
+ android:alpha="?attr/disabledAlpha"
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 af5afe6..9fe5766 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_light"
+ android:alpha="?attr/disabledAlpha"
android:color="@color/button_material_light"/>
<item android:color="@color/button_material_light"/>
</selector>
diff --git a/core/res/res/color/control_checkable_material.xml b/core/res/res/color/control_checkable_material.xml
new file mode 100644
index 0000000..c8ef909
--- /dev/null
+++ b/core/res/res/color/control_checkable_material.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:alpha="?attr/disabledAlpha"
+ android:color="?attr/colorControlNormal" />
+ <item android:state_checked="true"
+ android:color="?attr/colorControlActivated" />
+ <item android:color="?attr/colorControlNormal" />
+</selector>
diff --git a/core/res/res/color/control_default_material.xml b/core/res/res/color/control_default_material.xml
new file mode 100644
index 0000000..901c680
--- /dev/null
+++ b/core/res/res/color/control_default_material.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_enabled="false"
+ android:alpha="?attr/disabledAlpha"
+ android:color="?attr/colorControlNormal" />
+ <item android:color="?attr/colorControlActivated" />
+</selector>
diff --git a/core/res/res/color/switch_track_material.xml b/core/res/res/color/switch_track_material.xml
new file mode 100644
index 0000000..0c8caa9
--- /dev/null
+++ b/core/res/res/color/switch_track_material.xml
@@ -0,0 +1,24 @@
+<?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_enabled="false"
+ android:color="?attr/colorForeground"
+ android:alpha="?attr/disabledAlpha" />
+ <item android:state_checked="true"
+ android:color="?attr/colorControlActivated" />
+ <item android:color="?attr/colorForeground" />
+</selector>
diff --git a/core/res/res/color/tab_indicator_material.xml b/core/res/res/color/tab_indicator_material.xml
new file mode 100644
index 0000000..9602e92
--- /dev/null
+++ b/core/res/res/color/tab_indicator_material.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_selected="true"
+ android:color="@color/white" />
+ <item android:color="@color/transparent" />
+</selector>
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/btn_cab_done_mtrl_alpha.9.png
deleted file mode 100644
index 992a8ff..0000000
--- a/core/res/res/drawable-hdpi/btn_cab_done_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100644
index 68e17ad..0000000
--- a/core/res/res/drawable-hdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-hdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index de7ac29..0000000
--- a/core/res/res/drawable-hdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index 9415bc0..0000000
--- a/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/btn_cab_done_mtrl_alpha.9.png
deleted file mode 100644
index 5903856d..0000000
--- a/core/res/res/drawable-mdpi/btn_cab_done_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100644
index e5bface..0000000
--- a/core/res/res/drawable-mdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-mdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index bbf5928..0000000
--- a/core/res/res/drawable-mdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index 4918d33..0000000
--- a/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_mtrl_alpha.9.png
deleted file mode 100644
index d0d0b1e..0000000
--- a/core/res/res/drawable-xhdpi/btn_cab_done_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100644
index dff391f..0000000
--- a/core/res/res/drawable-xhdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-xhdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index d4bd169..0000000
--- a/core/res/res/drawable-xhdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index fd47f15..0000000
--- a/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_cab_done_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_cab_done_mtrl_alpha.9.png
deleted file mode 100644
index e1c55ad..0000000
--- a/core/res/res/drawable-xxhdpi/btn_cab_done_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100644
index 0d6a39a..0000000
--- a/core/res/res/drawable-xxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-xxhdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index 2e7bc12..0000000
--- a/core/res/res/drawable-xxhdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index 3e3174d..0000000
--- a/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100755
index c06740b..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-xxxhdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index 1086e9d..0000000
--- a/core/res/res/drawable-xxxhdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index 1e4a74c..0000000
--- a/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/btn_cab_done_material.xml b/core/res/res/drawable/btn_cab_done_material.xml
deleted file mode 100644
index 36cc196..0000000
--- a/core/res/res/drawable/btn_cab_done_material.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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:autoMirrored="true">
- <item android:state_pressed="true">
- <color android:color="?attr/colorControlHighlight" />
- </item>
- <item android:state_focused="true" android:state_enabled="true">
- <nine-patch android:src="@drawable/btn_cab_done_mtrl_alpha"
- android:tint="?attr/colorControlHighlight" />
- </item>
- <item android:state_enabled="true">
- <nine-patch android:src="@drawable/btn_cab_done_mtrl_alpha"
- android:tint="?attr/colorButtonNormal" />
- </item>
-</selector>
diff --git a/core/res/res/drawable/btn_check_material_anim.xml b/core/res/res/drawable/btn_check_material_anim.xml
index 1e05e84..24df879 100644
--- a/core/res/res/drawable/btn_check_material_anim.xml
+++ b/core/res/res/drawable/btn_check_material_anim.xml
@@ -16,118 +16,156 @@
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:state_checked="true">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_015" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_015"
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_enabled="false">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_000" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_checked="true" android:id="@+id/on">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_015" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_015"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:id="@+id/off">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_000" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
+ android:tint="?attr/colorControlNormal" />
</item>
<transition android:fromId="@+id/off" android:toId="@+id/on">
<animation-list>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_000" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_001" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_001"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_002" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_002"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_003" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_003"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_004" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_004"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_005" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_005"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_006" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_006"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_007" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_007"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_008" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_008"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_009" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_009"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_010" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_010"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_011" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_011"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_012" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_012"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_013" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_013"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_014" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_014"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_015" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_015"
+ android:tint="?attr/colorControlActivated" />
</item>
</animation-list>
</transition>
<transition android:fromId="@+id/on" android:toId="@+id/off">
<animation-list>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_000" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_000"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_001" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_001"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_002" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_002"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_003" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_003"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_004" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_004"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_005" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_005"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_006" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_006"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_007" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_007"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_008" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_008"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_009" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_009"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_010" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_010"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_011" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_011"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_012" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_012"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_013" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_013"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_014" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_014"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_015" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_015"
+ android:tint="?attr/colorControlNormal" />
</item>
</animation-list>
</transition>
diff --git a/core/res/res/drawable/btn_radio_material_anim.xml b/core/res/res/drawable/btn_radio_material_anim.xml
index 121e544..bce579e 100644
--- a/core/res/res/drawable/btn_radio_material_anim.xml
+++ b/core/res/res/drawable/btn_radio_material_anim.xml
@@ -16,128 +16,156 @@
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:state_checked="true">
- <bitmap
- android:src="@drawable/btn_radio_to_on_mtrl_015"
- android:tint="?attr/colorControlActivated"
- android:alpha="?attr/disabledAlpha" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015"
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_enabled="false">
- <bitmap
- android:src="@drawable/btn_radio_to_on_mtrl_000"
- android:tint="?attr/colorControlNormal"
- android:alpha="?attr/disabledAlpha" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000"
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_checked="true" android:id="@+id/on">
- <bitmap
- android:src="@drawable/btn_radio_to_on_mtrl_015"
- android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:id="@+id/off">
- <bitmap
- android:src="@drawable/btn_radio_to_on_mtrl_000"
- android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000"
+ android:tint="?attr/colorControlNormal" />
</item>
<transition android:fromId="@+id/off" android:toId="@+id/on">
<animation-list>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_001" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_001"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_002" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_002"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_003" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_003"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_004" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_004"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_005" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_005"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_006" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_006"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_007" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_007"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_008" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_008"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_009" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_009"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_010" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_010"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_011" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_011"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_012" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_012"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_013" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_013"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_014" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_014"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015"
+ android:tint="?attr/colorControlActivated" />
</item>
</animation-list>
</transition>
<transition android:fromId="@+id/on" android:toId="@+id/off">
<animation-list>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_000" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_000"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_001" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_001"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_002" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_002"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_003" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_003"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_004" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_004"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_005" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_005"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_006" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_006"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_007" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_007"
+ android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_008" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_008"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_009" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_009"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_010" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_010"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_011" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_011"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_012" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_012"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_013" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_013"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_014" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_014"
+ android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_mtrl_015" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_015"
+ android:tint="?attr/colorControlNormal" />
</item>
</animation-list>
</transition>
diff --git a/core/res/res/drawable/btn_star_material.xml b/core/res/res/drawable/btn_star_material.xml
index 29862d2..cbea471 100644
--- a/core/res/res/drawable/btn_star_material.xml
+++ b/core/res/res/drawable/btn_star_material.xml
@@ -14,17 +14,6 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_checked="true">
- <bitmap android:src="@drawable/btn_star_mtrl_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:state_pressed="true">
- <bitmap android:src="@drawable/btn_star_mtrl_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item>
- <bitmap android:src="@drawable/btn_star_mtrl_alpha"
- android:tint="?attr/colorControlNormal" />
- </item>
-</selector>
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/btn_star_mtrl_alpha"
+ android:tint="@color/control_checkable_material" />
diff --git a/core/res/res/drawable/btn_toggle_material.xml b/core/res/res/drawable/btn_toggle_material.xml
index f91d4cc..8b19e4a 100644
--- a/core/res/res/drawable/btn_toggle_material.xml
+++ b/core/res/res/drawable/btn_toggle_material.xml
@@ -23,11 +23,11 @@
<item>
<ripple android:color="?attr/colorControlHighlight">
<item>
- <shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
+ <shape android:shape="rectangle"
+ android:tint="?attr/colorButtonNormal">
<corners android:topLeftRadius="@dimen/control_corner_material"
android:topRightRadius="@dimen/control_corner_material"/>
- <solid android:color="?attr/colorButtonNormal" />
+ <solid android:color="@color/white" />
<padding android:left="@dimen/button_padding_horizontal_material"
android:top="@dimen/button_padding_vertical_material"
android:right="@dimen/button_padding_horizontal_material"
@@ -36,17 +36,11 @@
</item>
</ripple>
</item>
- <item>
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_checked="false">
- <nine-patch android:src="@drawable/btn_toggle_indicator_mtrl_alpha"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:state_checked="true">
- <nine-patch android:src="@drawable/btn_toggle_indicator_mtrl_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
- </selector>
+ <item android:gravity="bottom|fill_horizontal">
+ <shape android:shape="rectangle">
+ <size android:height="2dp" />
+ <solid android:color="@color/control_checkable_material" />
+ </shape>
</item>
</layer-list>
</inset>
diff --git a/core/res/res/drawable/spinner_background_material.xml b/core/res/res/drawable/spinner_background_material.xml
index d99e367..d5b509f 100644
--- a/core/res/res/drawable/spinner_background_material.xml
+++ b/core/res/res/drawable/spinner_background_material.xml
@@ -14,19 +14,22 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true">
- <item android:state_enabled="false">
- <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
- android:tint="?attr/colorControlNormal"
- android:alpha="?attr/disabledAlpha" />
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+ android:paddingMode="stack">
+ <item android:drawable="@drawable/item_background_borderless_material"
+ android:gravity="end|center_vertical"
+ android:width="24dp"
+ android:height="24dp" />
+ <item android:gravity="end|center_vertical">
+ <vector android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?attr/colorControlNormal">
+ <path android:pathData="M7,10l5,5,5-5z"
+ android:fillColor="@color/white"/>
+ </vector>
</item>
- <item android:state_pressed="false" android:state_focused="false">
- <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item>
- <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
-</selector>
+ <item android:end="48dp"
+ android:drawable="@color/transparent" />
+</layer-list>
diff --git a/core/res/res/drawable/spinner_textfield_background_material.xml b/core/res/res/drawable/spinner_textfield_background_material.xml
index fab3dc9..69c2f30 100644
--- a/core/res/res/drawable/spinner_textfield_background_material.xml
+++ b/core/res/res/drawable/spinner_textfield_background_material.xml
@@ -14,46 +14,8 @@
limitations under the License.
-->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:inset="@dimen/control_inset_material">
- <selector android:autoMirrored="true">
- <item android:state_enabled="false">
- <layer-list android:paddingMode="stack">
- <item>
- <nine-patch android:src="@drawable/textfield_activated_mtrl_alpha"
- android:tint="?attr/colorControlActivated"
- android:alpha="?attr/disabledAlpha" />
- </item>
- <item>
- <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
- android:tint="?attr/colorControlActivated"
- android:alpha="?attr/disabledAlpha" />
- </item>
- </layer-list>
- </item>
- <item android:state_pressed="false" android:state_focused="false">
- <layer-list android:paddingMode="stack">
- <item>
- <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item>
- <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
- android:tint="?attr/colorControlNormal" />
- </item>
- </layer-list>
- </item>
- <item>
- <layer-list android:paddingMode="stack">
- <item>
- <nine-patch android:src="@drawable/textfield_activated_mtrl_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item>
- <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
- </layer-list>
- </item>
- </selector>
-</inset>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+ android:paddingMode="stack">
+ <item android:drawable="@drawable/edit_text_material" />
+ <item android:drawable="@drawable/spinner_background_material" />
+</layer-list>
diff --git a/core/res/res/drawable/switch_track_material.xml b/core/res/res/drawable/switch_track_material.xml
index 1ec2f88..a825fe4 100644
--- a/core/res/res/drawable/switch_track_material.xml
+++ b/core/res/res/drawable/switch_track_material.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,20 +14,15 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false">
- <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
- android:tint="?attr/colorForeground"
- android:alpha="0.1" />
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:gravity="center_vertical|fill_horizontal"
+ android:start="2dp"
+ android:end="2dp">
+ <shape android:shape="rectangle"
+ android:tint="@color/switch_track_material">
+ <corners android:radius="7dp" />
+ <solid android:color="#4dffffff" />
+ <size android:height="14dp" />
+ </shape>
</item>
- <item android:state_checked="true">
- <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
- android:tint="?attr/colorControlActivated"
- android:alpha="0.3" />
- </item>
- <item>
- <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
- android:tint="?attr/colorForeground"
- android:alpha="0.3" />
- </item>
-</selector>
+</layer-list>
diff --git a/core/res/res/drawable/tab_indicator_material.xml b/core/res/res/drawable/tab_indicator_material.xml
index 16362c0..fc52305 100644
--- a/core/res/res/drawable/tab_indicator_material.xml
+++ b/core/res/res/drawable/tab_indicator_material.xml
@@ -14,10 +14,14 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_selected="true">
- <nine-patch android:src="@drawable/tab_indicator_mtrl_alpha"
- android:tint="?attr/colorControlActivated" />
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:gravity="bottom">
+ <shape android:shape="rectangle"
+ android:tint="?attr/colorControlActivated">
+ <size android:height="2dp" />
+ <solid android:color="@color/tab_indicator_material" />
+ </shape>
</item>
- <item android:drawable="@color/transparent" />
-</selector>
+ <item android:bottom="2dp"
+ android:drawable="@color/transparent" />
+</layer-list>
diff --git a/core/res/res/drawable/textfield_search_material.xml b/core/res/res/drawable/textfield_search_material.xml
index 1c0f5eb..fcd0579 100644
--- a/core/res/res/drawable/textfield_search_material.xml
+++ b/core/res/res/drawable/textfield_search_material.xml
@@ -15,28 +15,20 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_window_focused="false" android:state_enabled="true">
- <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:state_window_focused="false" android:state_enabled="false">
- <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:state_enabled="true" android:state_focused="true">
+ <item android:state_window_focused="true"
+ android:state_enabled="true"
+ android:state_focused="true">
<nine-patch android:src="@drawable/textfield_search_activated_mtrl_alpha"
- android:tint="?attr/colorControlActivated" />
+ android:tint="?attr/colorControlActivated" />
</item>
- <item android:state_enabled="true" android:state_activated="true">
+ <item android:state_window_focused="true"
+ android:state_enabled="true"
+ android:state_activated="true">
<nine-patch android:src="@drawable/textfield_search_activated_mtrl_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:state_enabled="true">
- <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
- android:tint="?attr/colorControlNormal" />
+ android:tint="?attr/colorControlActivated" />
</item>
<item>
<nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
- android:tint="?attr/colorControlNormal" />
+ android:tint="?attr/colorControlNormal" />
</item>
</selector>
diff --git a/core/res/res/drawable/time_picker_header_material.xml b/core/res/res/drawable/time_picker_header_material.xml
index cdb92b6..ef2068a 100644
--- a/core/res/res/drawable/time_picker_header_material.xml
+++ b/core/res/res/drawable/time_picker_header_material.xml
@@ -15,8 +15,6 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?attr/colorControlHighlight">
- <item>
- <color android:color="?attr/colorAccent" />
- </item>
+ android:color="?attr/colorControlHighlight">
+ <item android:drawable="?attr/colorAccent" />
</ripple>
diff --git a/core/res/res/values-af/donottranslate-cldr.xml b/core/res/res/values-af/donottranslate-cldr.xml
index 7da5a72..c7f41b4 100755
--- a/core/res/res/values-af/donottranslate-cldr.xml
+++ b/core/res/res/values-af/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%d %B %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%-l:%M:%S %p %d %b %Y</string>
diff --git a/core/res/res/values-am/donottranslate-cldr.xml b/core/res/res/values-am/donottranslate-cldr.xml
index ea1975c..6afe07fb 100755
--- a/core/res/res/values-am/donottranslate-cldr.xml
+++ b/core/res/res/values-am/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%d %B %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%-l:%M:%S %p %b %-e %Y</string>
diff --git a/core/res/res/values-ar-rEG/donottranslate-cldr.xml b/core/res/res/values-ar-rEG/donottranslate-cldr.xml
index d625752..1be9ed8 100755
--- a/core/res/res/values-ar-rEG/donottranslate-cldr.xml
+++ b/core/res/res/values-ar-rEG/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e %B، %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%-l:%M:%S %p %d/%m/%Y</string>
diff --git a/core/res/res/values-ar/donottranslate-cldr.xml b/core/res/res/values-ar/donottranslate-cldr.xml
index d625752..1be9ed8 100755
--- a/core/res/res/values-ar/donottranslate-cldr.xml
+++ b/core/res/res/values-ar/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e %B، %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%-l:%M:%S %p %d/%m/%Y</string>
diff --git a/core/res/res/values-bg/donottranslate-cldr.xml b/core/res/res/values-bg/donottranslate-cldr.xml
index 1943517..7c5ba7c 100755
--- a/core/res/res/values-bg/donottranslate-cldr.xml
+++ b/core/res/res/values-bg/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%d %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %d.%m.%Y</string>
diff --git a/core/res/res/values-ca/donottranslate-cldr.xml b/core/res/res/values-ca/donottranslate-cldr.xml
index 13f623b..db2d1ec 100755
--- a/core/res/res/values-ca/donottranslate-cldr.xml
+++ b/core/res/res/values-ca/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e %B de %Y</string>
<string name="time_of_day">%-k:%M:%S</string>
<string name="date_and_time">%-k:%M:%S %d/%m/%Y</string>
diff --git a/core/res/res/values-cs/donottranslate-cldr.xml b/core/res/res/values-cs/donottranslate-cldr.xml
index 765c51e..51f7e38 100755
--- a/core/res/res/values-cs/donottranslate-cldr.xml
+++ b/core/res/res/values-cs/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s. %s. %s"</string>
<string name="month_day_year">%-e. %B %Y</string>
<string name="time_of_day">%-k:%M:%S</string>
<string name="date_and_time">%-k:%M:%S %-e. %-m. %Y</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 00913d26..5cd6802 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim Letadlo je ZAPNUTÝ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim Letadlo je VYPNUTÝ"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Nastavení"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Hlas. asistence"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zamknout"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
diff --git a/core/res/res/values-da/donottranslate-cldr.xml b/core/res/res/values-da/donottranslate-cldr.xml
index 4c7a781..af35257 100755
--- a/core/res/res/values-da/donottranslate-cldr.xml
+++ b/core/res/res/values-da/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e. %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S, %-e. %b %Y</string>
diff --git a/core/res/res/values-de/donottranslate-cldr.xml b/core/res/res/values-de/donottranslate-cldr.xml
index 1fa067f..d641e10e 100755
--- a/core/res/res/values-de/donottranslate-cldr.xml
+++ b/core/res/res/values-de/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%-e. %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%d.%m.%Y, %H:%M:%S</string>
diff --git a/core/res/res/values-el/donottranslate-cldr.xml b/core/res/res/values-el/donottranslate-cldr.xml
index 7da5a72..c7f41b4 100755
--- a/core/res/res/values-el/donottranslate-cldr.xml
+++ b/core/res/res/values-el/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%d %B %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%-l:%M:%S %p %d %b %Y</string>
diff --git a/core/res/res/values-en-rAU/donottranslate-cldr.xml b/core/res/res/values-en-rAU/donottranslate-cldr.xml
index a7c07d3..69c3aea 100755
--- a/core/res/res/values-en-rAU/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rAU/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%d/%m/%Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rCA/donottranslate-cldr.xml b/core/res/res/values-en-rCA/donottranslate-cldr.xml
index b632f81..57b80df 100755
--- a/core/res/res/values-en-rCA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rCA/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s-%s-%s"</string>
<string name="month_day_year">%B %-e, %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%Y-%m-%d, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rGB/donottranslate-cldr.xml b/core/res/res/values-en-rGB/donottranslate-cldr.xml
index d099376..db438f2 100755
--- a/core/res/res/values-en-rGB/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rGB/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%-e %b %Y, %H:%M:%S</string>
diff --git a/core/res/res/values-en-rIE/donottranslate-cldr.xml b/core/res/res/values-en-rIE/donottranslate-cldr.xml
index d099376..db438f2 100755
--- a/core/res/res/values-en-rIE/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIE/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%-e %b %Y, %H:%M:%S</string>
diff --git a/core/res/res/values-en-rIN/donottranslate-cldr.xml b/core/res/res/values-en-rIN/donottranslate-cldr.xml
index 1d9470c..84157fe 100755
--- a/core/res/res/values-en-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIN/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%d-%b-%Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rNZ/donottranslate-cldr.xml b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
index a4ff357..4e9bec6 100755
--- a/core/res/res/values-en-rNZ/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%-e/%m/%Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rUS/donottranslate-cldr.xml b/core/res/res/values-en-rUS/donottranslate-cldr.xml
index 80db6e4..a8e2b2b 100755
--- a/core/res/res/values-en-rUS/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rUS/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%B %-e, %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%b %-e, %Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rZA/donottranslate-cldr.xml b/core/res/res/values-en-rZA/donottranslate-cldr.xml
index 7c27604..a4a5308 100755
--- a/core/res/res/values-en-rZA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rZA/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%d %B %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%d %b %Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-es-rUS/donottranslate-cldr.xml b/core/res/res/values-es-rUS/donottranslate-cldr.xml
index 878b48f..8adac31 100755
--- a/core/res/res/values-es-rUS/donottranslate-cldr.xml
+++ b/core/res/res/values-es-rUS/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e de %B de %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%-l:%M:%S %p %b %-e, %Y</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 5c8e65c..19c731f 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"El modo avión está Activado"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"El modo avión está Desactivado"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Configuración"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
diff --git a/core/res/res/values-es/donottranslate-cldr.xml b/core/res/res/values-es/donottranslate-cldr.xml
index d73a715..ca16aa0 100755
--- a/core/res/res/values-es/donottranslate-cldr.xml
+++ b/core/res/res/values-es/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e de %B de %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%d/%m/%Y, %H:%M:%S</string>
diff --git a/core/res/res/values-fa/donottranslate-cldr.xml b/core/res/res/values-fa/donottranslate-cldr.xml
index bb77b31..2821cd5 100755
--- a/core/res/res/values-fa/donottranslate-cldr.xml
+++ b/core/res/res/values-fa/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%-k:%M:%S</string>
<string name="date_and_time">%-k:%M:%S، %Y/%-m/%-e</string>
diff --git a/core/res/res/values-fi-rFI/donottranslate-cldr.xml b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
index 8e8c640..eab4957 100755
--- a/core/res/res/values-fi-rFI/donottranslate-cldr.xml
+++ b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%-e. %B %Y</string>
<string name="time_of_day">%-k.%M.%S</string>
<string name="date_and_time">%-k.%M.%S %-e.%-m.%Y</string>
diff --git a/core/res/res/values-fi/donottranslate-cldr.xml b/core/res/res/values-fi/donottranslate-cldr.xml
index 8e8c640..eab4957 100755
--- a/core/res/res/values-fi/donottranslate-cldr.xml
+++ b/core/res/res/values-fi/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%-e. %B %Y</string>
<string name="time_of_day">%-k.%M.%S</string>
<string name="date_and_time">%-k.%M.%S %-e.%-m.%Y</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index f5ef513c..e262015 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lentokonetila on KÄYTÖSSÄ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lentokonetila on POIS KÄYTÖSTÄ"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Asetukset"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Ääniapuri"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lukitse nyt"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
diff --git a/core/res/res/values-fr/donottranslate-cldr.xml b/core/res/res/values-fr/donottranslate-cldr.xml
index 5fc3539..2d6a109 100755
--- a/core/res/res/values-fr/donottranslate-cldr.xml
+++ b/core/res/res/values-fr/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%-e %b %Y à %H:%M:%S</string>
diff --git a/core/res/res/values-hi-rIN/donottranslate-cldr.xml b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
index 8f30750..b1dc879 100755
--- a/core/res/res/values-hi-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s-%s-%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%-l:%M:%S %p %d-%m-%Y</string>
diff --git a/core/res/res/values-hi/donottranslate-cldr.xml b/core/res/res/values-hi/donottranslate-cldr.xml
index 8f30750..b1dc879 100755
--- a/core/res/res/values-hi/donottranslate-cldr.xml
+++ b/core/res/res/values-hi/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s-%s-%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%-l:%M:%S %p %d-%m-%Y</string>
diff --git a/core/res/res/values-hr-rHR/donottranslate-cldr.xml b/core/res/res/values-hr-rHR/donottranslate-cldr.xml
index 2eb6d87..ca21a47 100755
--- a/core/res/res/values-hr-rHR/donottranslate-cldr.xml
+++ b/core/res/res/values-hr-rHR/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s."</string>
<string name="month_day_year">%-e. %B %Y.</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %-e.%b.%Y.</string>
diff --git a/core/res/res/values-hr/donottranslate-cldr.xml b/core/res/res/values-hr/donottranslate-cldr.xml
index 2eb6d87..ca21a47 100755
--- a/core/res/res/values-hr/donottranslate-cldr.xml
+++ b/core/res/res/values-hr/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s."</string>
<string name="month_day_year">%-e. %B %Y.</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %-e.%b.%Y.</string>
diff --git a/core/res/res/values-hu-rHU/donottranslate-cldr.xml b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
index 81e3b12..fd2fe92 100755
--- a/core/res/res/values-hu-rHU/donottranslate-cldr.xml
+++ b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s."</string>
<string name="month_day_year">%Y. %B %-e.</string>
<string name="time_of_day">%-k:%M:%S</string>
<string name="date_and_time">%Y.%m.%d., %-k:%M:%S</string>
diff --git a/core/res/res/values-hu/donottranslate-cldr.xml b/core/res/res/values-hu/donottranslate-cldr.xml
index bafa25e..3f60be7 100755
--- a/core/res/res/values-hu/donottranslate-cldr.xml
+++ b/core/res/res/values-hu/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s."</string>
<string name="month_day_year">%Y. %B %-e.</string>
<string name="time_of_day">%-k:%M:%S</string>
<string name="date_and_time">%-k:%M:%S %Y.%m.%d.</string>
diff --git a/core/res/res/values-in-rID/donottranslate-cldr.xml b/core/res/res/values-in-rID/donottranslate-cldr.xml
index 1f8e542..823b41f 100755
--- a/core/res/res/values-in-rID/donottranslate-cldr.xml
+++ b/core/res/res/values-in-rID/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %-e %b %Y</string>
<string name="date_time">%2$s %1$s</string>
diff --git a/core/res/res/values-in/donottranslate-cldr.xml b/core/res/res/values-in/donottranslate-cldr.xml
index b57823a..35a84eb 100755
--- a/core/res/res/values-in/donottranslate-cldr.xml
+++ b/core/res/res/values-in/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %-e %b %Y</string>
diff --git a/core/res/res/values-it/donottranslate-cldr.xml b/core/res/res/values-it/donottranslate-cldr.xml
index 2aea9510..95ba6dc 100755
--- a/core/res/res/values-it/donottranslate-cldr.xml
+++ b/core/res/res/values-it/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%d %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %d/%b/%Y</string>
diff --git a/core/res/res/values-iw/donottranslate-cldr.xml b/core/res/res/values-iw/donottranslate-cldr.xml
index cf05c9d..a9015d0 100755
--- a/core/res/res/values-iw/donottranslate-cldr.xml
+++ b/core/res/res/values-iw/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e ב%B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %-e.%-m.%Y</string>
diff --git a/core/res/res/values-ja/donottranslate-cldr.xml b/core/res/res/values-ja/donottranslate-cldr.xml
index 21aa0e6..a3c1f64 100755
--- a/core/res/res/values-ja/donottranslate-cldr.xml
+++ b/core/res/res/values-ja/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%Y年%-m月%-e日</string>
<string name="time_of_day">%-k:%M:%S</string>
<string name="date_and_time">%Y/%m/%d %-k:%M:%S</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 8714dbb..27cce45 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"機内モードON"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"機内モードOFF"</string>
<string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"音声アシスト"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"今すぐロック"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
diff --git a/core/res/res/values-ko/donottranslate-cldr.xml b/core/res/res/values-ko/donottranslate-cldr.xml
index 083b176..626a480 100755
--- a/core/res/res/values-ko/donottranslate-cldr.xml
+++ b/core/res/res/values-ko/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s. %s. %s."</string>
<string name="month_day_year">%Y년 %-m월 %-e일</string>
<string name="time_of_day">%p %-l:%M:%S</string>
<string name="date_and_time">%Y년 %-m월 %-e일 %p %-l:%M:%S</string>
diff --git a/core/res/res/values-lt-rLT/donottranslate-cldr.xml b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
index 8a50344..ba4a326 100755
--- a/core/res/res/values-lt-rLT/donottranslate-cldr.xml
+++ b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s-%s-%s"</string>
<string name="month_day_year">%Y m. %B %-e d.</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S, %Y-%m-%d</string>
diff --git a/core/res/res/values-lt/donottranslate-cldr.xml b/core/res/res/values-lt/donottranslate-cldr.xml
index b2368dc..cdca7b6 100755
--- a/core/res/res/values-lt/donottranslate-cldr.xml
+++ b/core/res/res/values-lt/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s-%s-%s"</string>
<string name="month_day_year">%Y m. %B %-e d.</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %Y.%m.%d</string>
diff --git a/core/res/res/values-lv-rLV/donottranslate-cldr.xml b/core/res/res/values-lv-rLV/donottranslate-cldr.xml
index f565157..3bed6cd 100755
--- a/core/res/res/values-lv-rLV/donottranslate-cldr.xml
+++ b/core/res/res/values-lv-rLV/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%Y. gada %-e. %B</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%Y. gada %-e. %b, %H:%M:%S</string>
diff --git a/core/res/res/values-lv/donottranslate-cldr.xml b/core/res/res/values-lv/donottranslate-cldr.xml
index c21481a..7ecdc31 100755
--- a/core/res/res/values-lv/donottranslate-cldr.xml
+++ b/core/res/res/values-lv/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%Y. gada %-e. %B</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %Y. gada %-e. %b</string>
diff --git a/core/res/res/values-nb/donottranslate-cldr.xml b/core/res/res/values-nb/donottranslate-cldr.xml
index 3b2a6c6..17aea0e 100755
--- a/core/res/res/values-nb/donottranslate-cldr.xml
+++ b/core/res/res/values-nb/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%-e. %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %-e. %b %Y</string>
diff --git a/core/res/res/values-nl/donottranslate-cldr.xml b/core/res/res/values-nl/donottranslate-cldr.xml
index 29b120c..35a84eb 100755
--- a/core/res/res/values-nl/donottranslate-cldr.xml
+++ b/core/res/res/values-nl/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s-%s-%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %-e %b %Y</string>
diff --git a/core/res/res/values-pl/donottranslate-cldr.xml b/core/res/res/values-pl/donottranslate-cldr.xml
index f9431b2..3f341b8 100755
--- a/core/res/res/values-pl/donottranslate-cldr.xml
+++ b/core/res/res/values-pl/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%d.%m.%Y %H:%M:%S</string>
diff --git a/core/res/res/values-pt-rPT/donottranslate-cldr.xml b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
index 9c9f903..6355432 100755
--- a/core/res/res/values-pt-rPT/donottranslate-cldr.xml
+++ b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e de %B de %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %-e de %b de %Y</string>
diff --git a/core/res/res/values-pt/donottranslate-cldr.xml b/core/res/res/values-pt/donottranslate-cldr.xml
index 2da7599..c97b337 100755
--- a/core/res/res/values-pt/donottranslate-cldr.xml
+++ b/core/res/res/values-pt/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e de %B de %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %d/%m/%Y</string>
diff --git a/core/res/res/values-ro-rRO/donottranslate-cldr.xml b/core/res/res/values-ro-rRO/donottranslate-cldr.xml
index cfb79e8..c874dcf 100755
--- a/core/res/res/values-ro-rRO/donottranslate-cldr.xml
+++ b/core/res/res/values-ro-rRO/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S, %d.%m.%Y</string>
diff --git a/core/res/res/values-ro/donottranslate-cldr.xml b/core/res/res/values-ro/donottranslate-cldr.xml
index cfb79e8..c874dcf 100755
--- a/core/res/res/values-ro/donottranslate-cldr.xml
+++ b/core/res/res/values-ro/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S, %d.%m.%Y</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 031b983..29bd05e 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modul Avion este ACTIVAT"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modul avion este DEZACTIVAT"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Setări"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistent vocal"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Blocați acum"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
diff --git a/core/res/res/values-ru/donottranslate-cldr.xml b/core/res/res/values-ru/donottranslate-cldr.xml
index c22df99..a36f13d 100755
--- a/core/res/res/values-ru/donottranslate-cldr.xml
+++ b/core/res/res/values-ru/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%-e %B %Y г.</string>
<string name="time_of_day">%-k:%M:%S</string>
<string name="date_and_time">%-k:%M:%S, %d.%m.%Y</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 608407d..a7882b8 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Выключить"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Включить"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Настройки"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Аудиоподсказки"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Заблокировать"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
diff --git a/core/res/res/values-sk-rSK/donottranslate-cldr.xml b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
index 765c51e..51f7e38 100755
--- a/core/res/res/values-sk-rSK/donottranslate-cldr.xml
+++ b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s. %s. %s"</string>
<string name="month_day_year">%-e. %B %Y</string>
<string name="time_of_day">%-k:%M:%S</string>
<string name="date_and_time">%-k:%M:%S %-e. %-m. %Y</string>
diff --git a/core/res/res/values-sk/donottranslate-cldr.xml b/core/res/res/values-sk/donottranslate-cldr.xml
index d4953c3..b30fe97 100755
--- a/core/res/res/values-sk/donottranslate-cldr.xml
+++ b/core/res/res/values-sk/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%-e. %B %Y</string>
<string name="time_of_day">%-k:%M:%S</string>
<string name="date_and_time">%-k:%M:%S %-e.%-m.%Y</string>
diff --git a/core/res/res/values-sl-rSI/donottranslate-cldr.xml b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
index 17d8609..798f4c0 100755
--- a/core/res/res/values-sl-rSI/donottranslate-cldr.xml
+++ b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s. %s. %s"</string>
<string name="month_day_year">%d. %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S, %-e. %b %Y</string>
diff --git a/core/res/res/values-sl/donottranslate-cldr.xml b/core/res/res/values-sl/donottranslate-cldr.xml
index 83e4693..92cd963b 100755
--- a/core/res/res/values-sl/donottranslate-cldr.xml
+++ b/core/res/res/values-sl/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s. %s. %s"</string>
<string name="month_day_year">%d. %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %-e. %b. %Y</string>
diff --git a/core/res/res/values-sr-rRS/donottranslate-cldr.xml b/core/res/res/values-sr-rRS/donottranslate-cldr.xml
index 8bb5fa7f1..a0f4bc2 100755
--- a/core/res/res/values-sr-rRS/donottranslate-cldr.xml
+++ b/core/res/res/values-sr-rRS/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s."</string>
<string name="month_day_year">%d. %B %Y.</string>
<string name="time_of_day">%H.%M.%S</string>
<string name="date_and_time">%H.%M.%S %d.%m.%Y.</string>
diff --git a/core/res/res/values-sr/donottranslate-cldr.xml b/core/res/res/values-sr/donottranslate-cldr.xml
index 8bb5fa7f1..a0f4bc2 100755
--- a/core/res/res/values-sr/donottranslate-cldr.xml
+++ b/core/res/res/values-sr/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s."</string>
<string name="month_day_year">%d. %B %Y.</string>
<string name="time_of_day">%H.%M.%S</string>
<string name="date_and_time">%H.%M.%S %d.%m.%Y.</string>
diff --git a/core/res/res/values-sv/donottranslate-cldr.xml b/core/res/res/values-sv/donottranslate-cldr.xml
index 29b120c..35a84eb 100755
--- a/core/res/res/values-sv/donottranslate-cldr.xml
+++ b/core/res/res/values-sv/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s-%s-%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %-e %b %Y</string>
diff --git a/core/res/res/values-sw/donottranslate-cldr.xml b/core/res/res/values-sw/donottranslate-cldr.xml
index b6304e7..7313c71 100755
--- a/core/res/res/values-sw/donottranslate-cldr.xml
+++ b/core/res/res/values-sw/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%Y %B %-e</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %Y %b %-e</string>
diff --git a/core/res/res/values-th-rTH/donottranslate-cldr.xml b/core/res/res/values-th-rTH/donottranslate-cldr.xml
index 2f389f7..867a58e 100755
--- a/core/res/res/values-th-rTH/donottranslate-cldr.xml
+++ b/core/res/res/values-th-rTH/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%-k:%M:%S</string>
<string name="date_and_time">%-k:%M:%S, %-e %b %Y</string>
diff --git a/core/res/res/values-th/donottranslate-cldr.xml b/core/res/res/values-th/donottranslate-cldr.xml
index 2f389f7..867a58e 100755
--- a/core/res/res/values-th/donottranslate-cldr.xml
+++ b/core/res/res/values-th/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%-k:%M:%S</string>
<string name="date_and_time">%-k:%M:%S, %-e %b %Y</string>
diff --git a/core/res/res/values-tl/donottranslate-cldr.xml b/core/res/res/values-tl/donottranslate-cldr.xml
index 4f69833..7313c71 100755
--- a/core/res/res/values-tl/donottranslate-cldr.xml
+++ b/core/res/res/values-tl/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s-%s-%s"</string>
<string name="month_day_year">%Y %B %-e</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %Y %b %-e</string>
diff --git a/core/res/res/values-tr/donottranslate-cldr.xml b/core/res/res/values-tr/donottranslate-cldr.xml
index 8bdcf48..0577fab 100755
--- a/core/res/res/values-tr/donottranslate-cldr.xml
+++ b/core/res/res/values-tr/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s %s %s"</string>
<string name="month_day_year">%d %B %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%d %b %Y %H:%M:%S</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ebc10da..c0fd411 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uçak modu AÇIK"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Uçak modu KAPALI"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Ayarlar"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Ses Yardımı"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Şimdi kilitle"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
diff --git a/core/res/res/values-uk-rUA/donottranslate-cldr.xml b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
index c137df9..75025d8 100755
--- a/core/res/res/values-uk-rUA/donottranslate-cldr.xml
+++ b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%-e %B %Y р.</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%-e %b %Y р., %H:%M:%S</string>
diff --git a/core/res/res/values-uk/donottranslate-cldr.xml b/core/res/res/values-uk/donottranslate-cldr.xml
index b8c0d1e..1c25b4d 100755
--- a/core/res/res/values-uk/donottranslate-cldr.xml
+++ b/core/res/res/values-uk/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s.%s.%s"</string>
<string name="month_day_year">%-e %B %Y р.</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%H:%M:%S %-e %b %Y</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index edab739f..76cfe76 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -200,7 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ہوائی جہاز وضع آن ہے"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ہوائی جہاز وضع آف ہے"</string>
<string name="global_action_settings" msgid="1756531602592545966">"ترتیبات"</string>
- <string name="global_action_voice_assist" msgid="7751191495200504480">"صوتی مدد"</string>
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ابھی مقفل کریں"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"حفاظتی وضع"</string>
diff --git a/core/res/res/values-vi-rVN/donottranslate-cldr.xml b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
index 3a735bf..8f5cf3b 100755
--- a/core/res/res/values-vi-rVN/donottranslate-cldr.xml
+++ b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">Ngày %d tháng %-m năm %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%d-%m-%Y %H:%M:%S</string>
diff --git a/core/res/res/values-vi/donottranslate-cldr.xml b/core/res/res/values-vi/donottranslate-cldr.xml
index 3a735bf..8f5cf3b 100755
--- a/core/res/res/values-vi/donottranslate-cldr.xml
+++ b/core/res/res/values-vi/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">Ngày %d tháng %-m năm %Y</string>
<string name="time_of_day">%H:%M:%S</string>
<string name="date_and_time">%d-%m-%Y %H:%M:%S</string>
diff --git a/core/res/res/values-zh-rCN/donottranslate-cldr.xml b/core/res/res/values-zh-rCN/donottranslate-cldr.xml
index b83f412..b3f009e 100755
--- a/core/res/res/values-zh-rCN/donottranslate-cldr.xml
+++ b/core/res/res/values-zh-rCN/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s-%s-%s"</string>
<string name="month_day_year">%Y 年 %-m 月 %-e 日</string>
<string name="time_of_day">%p %I:%M:%S</string>
<string name="date_and_time">%Y 年 %-m 月 %-e 日%p %I:%M:%S</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index f1a4fb31..e280503 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -200,8 +200,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"已开启飞行模式"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"未开启飞行模式"</string>
<string name="global_action_settings" msgid="1756531602592545966">"设置"</string>
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"语音助理"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"立即锁定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
diff --git a/core/res/res/values-zh-rTW/donottranslate-cldr.xml b/core/res/res/values-zh-rTW/donottranslate-cldr.xml
index 0a19896..3e2b33d 100755
--- a/core/res/res/values-zh-rTW/donottranslate-cldr.xml
+++ b/core/res/res/values-zh-rTW/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%Y 年 %-m 月 %-e 日</string>
<string name="time_of_day">%p %I:%M:%S</string>
<string name="date_and_time">%Y/%-m/%-e %p %I:%M:%S</string>
diff --git a/core/res/res/values-zu/donottranslate-cldr.xml b/core/res/res/values-zu/donottranslate-cldr.xml
index 087ad833..e2cf516 100755
--- a/core/res/res/values-zu/donottranslate-cldr.xml
+++ b/core/res/res/values-zu/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s-%s-%s"</string>
<string name="month_day_year">%-e %B %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%-l:%M:%S %p %-e %b %Y</string>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index f6a5787..3312f4f 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -302,7 +302,6 @@
<item>@drawable/ab_solid_shadow_material</item>
<item>@drawable/activated_background_material</item>
<item>@drawable/btn_borderless_material</item>
- <item>@drawable/btn_cab_done_material</item>
<item>@drawable/btn_check_material_anim</item>
<item>@drawable/btn_default_material</item>
<item>@drawable/btn_radio_material_anim</item>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 84609ca..9678322 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1023,7 +1023,11 @@
<p>NOTE: A task's root activity value is applied to all additional activities launched in
the task. That is if the root activity of a task is resizeable then the system will treat
all other activities in the task as resizeable and will not if the root activity isn't
- resizeable. -->
+ resizeable.
+
+ <p>NOTE: The value of {@link android.R.attr#screenOrientation} will be ignored for
+ resizeable activities as the system doesn't support fixed orientation on a resizeable
+ activity. -->
<attr name="resizeableActivity" format="boolean" />
<!-- The <code>manifest</code> tag is the root of an
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index e1e1ffed..1975875 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -114,4 +114,6 @@
<!-- Padding above and below selection dialog lists. -->
<dimen name="dialog_list_padding_vertical_material">8dp</dimen>
+
+ <dimen name="progress_bar_height_material">4dp</dimen>
</resources>
diff --git a/core/res/res/values/donottranslate-cldr.xml b/core/res/res/values/donottranslate-cldr.xml
index 80db6e4..a8e2b2b 100755
--- a/core/res/res/values/donottranslate-cldr.xml
+++ b/core/res/res/values/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="numeric_date_template">"%s/%s/%s"</string>
<string name="month_day_year">%B %-e, %Y</string>
<string name="time_of_day">%-l:%M:%S %p</string>
<string name="date_and_time">%b %-e, %Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index fdaec80..813de7c 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -708,7 +708,6 @@
<java-symbol type="string" name="noon" />
<java-symbol type="string" name="number_picker_increment_scroll_action" />
<java-symbol type="string" name="number_picker_increment_scroll_mode" />
- <java-symbol type="string" name="numeric_date_template" />
<java-symbol type="string" name="old_app_action" />
<java-symbol type="string" name="old_app_description" />
<java-symbol type="string" name="older" />
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index dc43a2f..a59581b 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -425,7 +425,7 @@
if (rLoc == INSTALL_LOC_INT) {
if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
assertTrue("The application should be installed forward locked",
- (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+ (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
assertStartsWith("The APK path should point to the ASEC",
SECURE_CONTAINERS_PREFIX, srcPath);
assertStartsWith("The public APK path should point to the ASEC",
@@ -441,7 +441,8 @@
fail("compat check: Can't read " + info.dataDir + "/lib");
}
} else {
- assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+ assertFalse(
+ (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
assertEquals(appInstallPath, srcPath);
assertEquals(appInstallPath, publicSrcPath);
assertStartsWith("Native library should point to shared lib directory",
@@ -467,16 +468,16 @@
} else if (rLoc == INSTALL_LOC_SD) {
if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
assertTrue("The application should be installed forward locked",
- (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+ (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
} else {
assertFalse("The application should not be installed forward locked",
- (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+ (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
}
assertTrue("Application flags (" + info.flags
+ ") should contain FLAG_EXTERNAL_STORAGE",
(info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
// Might need to check:
- // ((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0)
+ // ((info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0)
assertStartsWith("The APK path should point to the ASEC",
SECURE_CONTAINERS_PREFIX, srcPath);
assertStartsWith("The public APK path should point to the ASEC",
diff --git a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
new file mode 100644
index 0000000..f9b69a0
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.content.pm;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.FileUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.test.AndroidTestCase;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Tests for {@link android.content.pm.RegisteredServicesCache}
+ */
+public class RegisteredServicesCacheTest extends AndroidTestCase {
+
+ private final ResolveInfo r1 = new ResolveInfo();
+ private final ResolveInfo r2 = new ResolveInfo();
+ private final TestServiceType t1 = new TestServiceType("t1", "value1");
+ private final TestServiceType t2 = new TestServiceType("t2", "value2");
+ private File mDataDir;
+ private File mSyncDir;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ File cacheDir = mContext.getCacheDir();
+ mDataDir = new File(cacheDir, "testServicesCache");
+ FileUtils.deleteContents(mDataDir);
+ mSyncDir = new File(mDataDir, "system/registered_services");
+ mSyncDir.mkdirs();
+ }
+
+ public void testGetAllServicesHappyPath() {
+ TestServicesCache cache = new TestServicesCache(mContext, mDataDir);
+ cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1));
+ cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 2));
+ assertEquals(2, cache.getAllServicesSize(0));
+ assertEquals(2, cache.getPersistentServicesSize(0));
+ File file = new File(mSyncDir, TestServicesCache.SERVICE_INTERFACE + ".xml");
+ assertTrue("File should be created at " + file, file.length() > 0);
+ // Make sure all services can be loaded from xml
+ cache = new TestServicesCache(mContext, mDataDir);
+ assertEquals(2, cache.getPersistentServicesSize(0));
+ }
+
+ public void testGetAllServicesReplaceUid() {
+ TestServicesCache cache = new TestServicesCache(mContext, mDataDir);
+ cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1));
+ cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 2));
+ cache.getAllServices(0);
+ // Invalidate cache and clear update query results
+ cache.invalidateCache(0);
+ cache.clearServicesForQuerying();
+ cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1));
+ cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null,
+ TestServicesCache.SYSTEM_IMAGE_UID));
+ Collection<RegisteredServicesCache.ServiceInfo<TestServiceType>> allServices = cache
+ .getAllServices(0);
+ assertEquals(2, allServices.size());
+ Set<Integer> uids = new HashSet<>();
+ for (RegisteredServicesCache.ServiceInfo<TestServiceType> srv : allServices) {
+ uids.add(srv.uid);
+ }
+ assertTrue("UID must be updated to the new value",
+ uids.contains(TestServicesCache.SYSTEM_IMAGE_UID));
+ assertFalse("UID must be updated to the new value", uids.contains(2));
+ }
+
+ public void testGetAllServicesServiceRemoved() {
+ TestServicesCache cache = new TestServicesCache(mContext, mDataDir);
+ cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1));
+ cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 2));
+ assertEquals(2, cache.getAllServicesSize(0));
+ assertEquals(2, cache.getPersistentServicesSize(0));
+ // Re-read data from disk and verify services were saved
+ cache = new TestServicesCache(mContext, mDataDir);
+ assertEquals(2, cache.getPersistentServicesSize(0));
+ // Now register only one service and verify that another one is removed
+ cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1));
+ assertEquals(1, cache.getAllServicesSize(0));
+ assertEquals(1, cache.getPersistentServicesSize(0));
+ }
+
+ public void testGetAllServicesMultiUser() {
+ TestServicesCache cache = new TestServicesCache(mContext, mDataDir);
+ int u0 = 0;
+ int u1 = 1;
+ int pid1 = 1;
+ cache.addServiceForQuerying(u0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null,
+ pid1));
+ int u1uid = UserHandle.getUid(u1, 0);
+ cache.addServiceForQuerying(u1, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null,
+ u1uid));
+ assertEquals(u1, cache.getAllServicesSize(u0));
+ assertEquals(u1, cache.getPersistentServicesSize(u0));
+ assertEquals(u1, cache.getAllServicesSize(u1));
+ assertEquals(u1, cache.getPersistentServicesSize(u1));
+ assertEquals("No services should be available for user 3", 0, cache.getAllServicesSize(3));
+ // Re-read data from disk and verify services were saved
+ cache = new TestServicesCache(mContext, mDataDir);
+ assertEquals(u1, cache.getPersistentServicesSize(u0));
+ assertEquals(u1, cache.getPersistentServicesSize(u1));
+ }
+
+ /**
+ * Mock implementation of {@link android.content.pm.RegisteredServicesCache} for testing
+ */
+ private static class TestServicesCache extends RegisteredServicesCache<TestServiceType> {
+ static final String SERVICE_INTERFACE = "RegisteredServicesCacheTest";
+ static final String SERVICE_META_DATA = "RegisteredServicesCacheTest";
+ static final String ATTRIBUTES_NAME = "test";
+ // Represents UID of a system image process
+ static final int SYSTEM_IMAGE_UID = 20;
+ private SparseArray<Map<ResolveInfo, ServiceInfo<TestServiceType>>> mServices
+ = new SparseArray<>();
+
+ public TestServicesCache(Context context, File dir) {
+ super(context, SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME,
+ new TestSerializer(), dir);
+ }
+
+ @Override
+ public TestServiceType parseServiceAttributes(Resources res, String packageName,
+ AttributeSet attrs) {
+ return null;
+ }
+
+ @Override
+ protected List<ResolveInfo> queryIntentServices(int userId) {
+ Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices
+ .get(userId, new HashMap<ResolveInfo, ServiceInfo<TestServiceType>>());
+ return new ArrayList<>(map.keySet());
+ }
+
+ void addServiceForQuerying(int userId, ResolveInfo resolveInfo,
+ ServiceInfo<TestServiceType> serviceInfo) {
+ Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices.get(userId);
+ if (map == null) {
+ map = new HashMap<>();
+ mServices.put(userId, map);
+ }
+ map.put(resolveInfo, serviceInfo);
+ }
+
+ void clearServicesForQuerying() {
+ mServices.clear();
+ }
+
+ int getPersistentServicesSize(int user) {
+ return getPersistentServices(user).size();
+ }
+
+ int getAllServicesSize(int user) {
+ return getAllServices(user).size();
+ }
+
+ @Override
+ protected boolean inSystemImage(int callerUid) {
+ return callerUid == SYSTEM_IMAGE_UID;
+ }
+
+ @Override
+ protected ServiceInfo<TestServiceType> parseServiceInfo(
+ ResolveInfo resolveInfo) throws XmlPullParserException, IOException {
+ int size = mServices.size();
+ for (int i = 0; i < size; i++) {
+ Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices.valueAt(i);
+ ServiceInfo<TestServiceType> serviceInfo = map.get(resolveInfo);
+ if (serviceInfo != null) {
+ return serviceInfo;
+ }
+ }
+ throw new IllegalArgumentException("Unexpected service " + resolveInfo);
+ }
+ }
+
+ static class TestSerializer implements XmlSerializerAndParser<TestServiceType> {
+
+ public void writeAsXml(TestServiceType item, XmlSerializer out) throws IOException {
+ out.attribute(null, "type", item.type);
+ out.attribute(null, "value", item.value);
+ }
+
+ public TestServiceType createFromXml(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ final String type = parser.getAttributeValue(null, "type");
+ final String value = parser.getAttributeValue(null, "value");
+ return new TestServiceType(type, value);
+ }
+ }
+
+ static class TestServiceType implements Parcelable {
+ final String type;
+ final String value;
+
+ public TestServiceType(String type, String value) {
+ this.type = type;
+ this.value = value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ TestServiceType that = (TestServiceType) o;
+
+ return type.equals(that.type) && value.equals(that.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * type.hashCode() + value.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "TestServiceType{" +
+ "type='" + type + '\'' +
+ ", value='" + value + '\'' +
+ '}';
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(type);
+ dest.writeString(value);
+ }
+
+ public TestServiceType(Parcel source) {
+ this(source.readString(), source.readString());
+ }
+
+ public static final Creator<TestServiceType> CREATOR = new Creator<TestServiceType>() {
+ public TestServiceType createFromParcel(Parcel source) {
+ return new TestServiceType(source);
+ }
+
+ public TestServiceType[] newArray(int size) {
+ return new TestServiceType[size];
+ }
+ };
+ }
+}
diff --git a/docs/html/about/versions/android-5.0-changes.jd b/docs/html/about/versions/android-5.0-changes.jd
index 3de5c3c..f51af40 100644
--- a/docs/html/about/versions/android-5.0-changes.jd
+++ b/docs/html/about/versions/android-5.0-changes.jd
@@ -24,13 +24,6 @@
<li><a href="#managed_profiles">Support for Managed Profiles</a></li>
</ol>
-<a class="notice-developers-video" href="https://www.youtube.com/watch?v=Uiq2kZ2JHVY">
-<div>
- <h3>Video</h3>
- <p>Notifications</p>
-</div>
-</a>
-
<h2>API Differences</h2>
<ol>
<li><a href="{@docRoot}sdk/api_diff/21/changes.html">API level 20 to 21 »</a> </li>
@@ -48,6 +41,20 @@
</div>
</div>
+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=um1S2u022HA">
+<div>
+ <h3>Video</h3>
+ <p>Dev Byte: What's New in Android 5.0</p>
+</div>
+</a>
+
+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=Uiq2kZ2JHVY">
+<div>
+ <h3>Video</h3>
+ <p>Dev Byte: Notifications</p>
+</div>
+</a>
+
<p>API Level: {@sdkPlatformApiLevel}</p>
<p>Along with new features and capabilities, Android 5.0 includes a variety of
system changes and API behavior changes. This document highlights
diff --git a/docs/html/google/gcm/adv.jd b/docs/html/google/gcm/adv.jd
deleted file mode 100644
index 95497e3..0000000
--- a/docs/html/google/gcm/adv.jd
+++ /dev/null
@@ -1,410 +0,0 @@
-page.title=GCM Advanced Topics
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<h2>Quickview</h2>
-
-<ul>
-<li>Learn more about GCM advanced features.</li>
-</ul>
-
-
-<h2>In this document</h2>
-
-<ol>
-<li><a href="#lifetime">Lifetime of a Message</a></li>
-<li><a href="#throttling">Throttling</a></li>
-<li><a href="#reg-state">Keeping the Registration State in Sync</a>
- <ol>
- <li><a href="#canonical">Canonical IDs</a></li>
- </ol>
-</li>
-<li><a href="#retry">Automatic Retry Using Exponential Back-Off</a></li>
-<li><a href="#unreg">Unregistration</a>
- <ol>
- <li><a href="#unreg-why">Why you should rarely unregister</a></li>
- <li><a href="#unreg-how">How unregistration works</a></li>
- </ol>
-</li>
-<li><a href="#collapsible">Send-to-Sync vs. Messages with Payload</a>
- <ol>
- <li><a href="#s2s">Send-to-sync messages</a></li>
- <li><a href="#payload">Messages with payload</a></li>
-<li><a href="#which">Which should I use?</a></li>
- </ol>
-</li>
-<li><a href="#ttl">Setting an Expiration Date for a Message</a> </li>
-<li><a href="#throttling"></a><a href="#multi-senders">Receiving Messages from
-Multiple Senders</a></li>
-</ol>
-
-</div>
-</div>
-<p>This document covers advanced topics for GCM.</p>
-
-
-
-
-<h2 id="msg-lifetime">Lifetime of a Message</h2>
-<p>When a 3rd-party server posts a message to GCM and receives a message ID back,
-it does not mean that the message was already delivered to the device. Rather, it
-means that it was accepted for delivery. What happens to the message after it is
-accepted depends on many factors.</p>
-
-<p>In the best-case scenario, if the device is connected to GCM, the screen is on,
-and there are no throttling restrictions (see <a href="#throttling">Throttling</a>),
-the message will be delivered right away.</p>
-
-<p>If the device is connected but idle, the message will still be
-delivered right away unless the <code>delay_while_idle</code> flag is set to true.
-Otherwise, it will be stored in the GCM servers until the device is awake. And
-that's where the <code>collapse_key</code> flag plays a role: if there is already
-a message with the same collapse key (and registration ID) stored and waiting for
-delivery, the old message will be discarded and the new message will take its place
-(that is, the old message will be collapsed by the new one). However, if the collapse
-key is not set, both the new and old messages are stored for future delivery.
-Collapsible messages are also called <a href="#s2s">send-to-sync messages</a>.</p>
-
-<p class="note"><strong>Note:</strong> There is a limit on how many messages can
-be stored without collapsing. That limit is currently 100. If the limit is reached,
-all stored messages are discarded. Then when the device is back online, it receives
-a special message indicating that the limit was reached. The application can then
-handle the situation properly, typically by requesting a full sync.
-<br><br>
-Likewise, there is a limit on how many <code>collapse_key</code>s you can have for
-a particular device. GCM allows a maximum of 4 different collapse keys to be used
-by the GCM server per device
-any given time. In other words, the GCM server can simultaneously store 4 different
-send-to-sync messages, each with a different collapse key. If you exceed this number
-GCM will only keep 4 collapse keys, with no guarantees about which ones they will be.
-See <a href="#s2s">Send-to-sync messages</a> for more information.
-</p>
-
-<p>If the device is not connected to GCM, the message will be stored until a
-connection is established (again respecting the collapse key rules). When a connection
-is established, GCM will deliver all pending messages to the device, regardless of
-the <code>delay_while_idle</code> flag. If the device never gets connected again
-(for instance, if it was factory reset), the message will eventually time out and
-be discarded from GCM storage. The default timeout is 4 weeks, unless the
-<code>time_to_live</code> flag is set.</p>
-
-<p>Finally, when GCM attempts to deliver a message to the device and the
-application was uninstalled, GCM will discard that message right away and
-invalidate the registration ID. Future attempts to send a message to that device
-will get a <code>NotRegistered</code> error. See <a href="#unreg">
-How Unregistration Works</a> for more information.</p>
-<p>Although is not possible to track the status of each individual message, the
-Google Cloud Console stats are broken down by messages sent to device, messages
-collapsed, and messages waiting for delivery.</p>
-
-<h2 id="throttling">Throttling</h2>
-<p>To prevent abuse (such as sending a flood of messages to a device) and
-to optimize for the overall network efficiency and battery life of
-devices, GCM implements throttling of messages using a token bucket
-scheme. Messages are throttled on a per application and per <a href="#collapsible">collapse
-key</a> basis (including non-collapsible messages). Each application
-collapse key is granted some initial tokens, and new tokens are granted
-periodically therefter. Each token is valid for a single message sent to
-the device. If an application collapse key exhausts its supply of
-available tokens, new messages are buffered in a pending queue until
-new tokens become available at the time of the periodic grant. Thus
-throttling in between periodic grant intervals may add to the latency
-of message delivery for an application collapse key that sends a large
-number of messages within a short period of time. Messages in the pending
-queue of an application collapse key may be delivered before the time
-of the next periodic grant, if they are piggybacked with messages
-belonging to a non-throttled category by GCM for network and battery
-efficiency reasons.</p>
-
-<h2 id="reg-state">Keeping the Registration State in Sync</h2>
-<p>Whenever the application registers as described in
-<a href="{@docRoot}google/gcm/client.html">Implementing GCM Client</a>,
-it should save the registration ID for future use, pass it to the
-3rd-party server to complete the registration, and keep track of
-whether the server completed the registration. If the server fails
-to complete the registration, it should try again or unregister from GCM.</p>
-
-<p>There are also two other scenarios that require special care:</p>
-<ul>
- <li>Application update</li>
- <li>Backup and restore
- </li>
-</ul>
-<p>When an application is updated, it should invalidate its existing registration
-ID, as it is not guaranteed to work with the new version. Because there is no
-lifecycle method called when the application is updated, the best way to achieve
-this validation is by storing the current application version when a registration
-ID is stored. Then when the application is started, compare the stored value with
-the current application version. If they do not match, invalidate the stored data
-and start the registration process again.</p>
-
-<p>Similarly, you should not save the registration ID when an application is
-backed up. This is because the registration ID could become invalid by the time
-the application is restored, which would put the application in an invalid state
-(that is, the application thinks it is registered, but the server and GCM do not
-store that registration ID anymore—thus the application will not get more
-messages).</p>
-<h3 id="canonical">Canonical IDs</h3>
-<p>On the server side, as long as the application is behaving well, everything
-should work normally. However, if a bug in the application triggers multiple
-registrations for the same device, it can be hard to reconcile state and you might
-end up with duplicate messages.</p>
-<p>GCM provides a facility called "canonical registration IDs" to easily
-recover from these situations. A canonical registration ID is defined to be the ID
-of the last registration requested by your application. This is the ID that the
-server should use when sending messages to the device.</p>
-<p>If later on you try to send a message using a different registration ID, GCM
-will process the request as usual, but it will include the canonical registration
-ID in the <code>registration_id</code> field of the response. Make sure to replace
-the registration ID stored in your server with this canonical ID, as eventually
-the ID you're using will stop working.</p>
-
-<h2 id="retry">Automatic Retry Using Exponential Back-Off</h2>
-
-<p>When registration or unregistration fails, the app should retry the failed operation.</p>
-<p>In the simplest case, if your application attempts to register and GCM is not a
-fundamental part of the application, the application could simply ignore the error
-and try to register again the next time it starts. Otherwise, it should retry the
-previous operation using exponential back-off. In exponential back-off, each time
-there is a failure, it should wait twice the previous amount of time before trying
-again. If the register (or unregister) operation was synchronous, it could be retried
-in a simple loop. However, since it is asynchronous, the best approach is to schedule
-a {@link android.app.PendingIntent} to retry the operation.
-
-<h2 id="unreg">Unregistration</h2>
-
-<p>This section explains when you should unregister in GCM and what happens
-when you do.</p>
-
-<h3 id="unreg-why">Why you should rarely unregister</h3>
-
-<p>A registration ID (regID) represents a particular Android application running
-on a particular device. You should only need to unregister in rare cases, such as
-if you want an app to stop receiving messages, or if you suspect that the regID has
-been compromised. In general, though, once an app has a regID, you shouldn't need
-to change it.</p>
-
-<p>In particular, you should never unregister your app as a mechanism for
-logout or for switching between users, for the following reasons:</p>
-
-<ul>
- <li>A regID maps an app to a device. It isn't associated with a particular
- logged in user. If you unregister and then re-register, GCM may return the same
- ID or a different ID—there's no guarantee either way.</li>
-
- <li>Unregistration may take up to 5 minutes to propagate.</li>
- <li>After unregistration, re-registration may again take up to 5 minutes to
-propagate. During this time messages may be rejected due to the state of being
-unregistered, and after all this, messages may still go to the wrong user.</li>
-</ul>
-
-
-<p>The solution is to manage your own mapping between users, the regID, and
-individual messages:</p>
-
-<ul>
- <li>Your app server should maintain a mapping between the current user
-and the regID. This should include information about which user is supposed to
-receive a particular message.</li>
- <li>The app running on the device should check to ensure that messages it
-receives match the logged in user.</li>
-</ul>
-
-
-<h3 id="unreg-how">How unregistration works</h3>
-
-<p>An application can be automatically unregistered after it is uninstalled from
-the device. However, this process does not happens right away, as Android does not
-provide an uninstall callback. What happens in this scenario is as follows:</p>
-<ol>
- <li>The end user uninstalls the application.</li>
- <li>The 3rd-party server sends a message to GCM server.</li>
- <li>The GCM server sends the message to the device.</li>
- <li>The GCM client receives the message and queries Package Manager about
-whether there are broadcast receivers configured to receive it, which returns
-<code>false</code>.
-</li>
- <li>The GCM client informs the GCM server that the application was uninstalled.</li>
- <li>The GCM server marks the registration ID for deletion.</li>
- <li>The 3rd-party server sends a message to GCM.</li>
- <li>The GCM returns a <code>NotRegistered</code> error message to the 3rd-party server.</li>
- <li>The 3rd-party deletes the registration ID.
- </li>
-</ol>
-
-<p class ="note"><strong>Note:</strong> The GCM client is the Google Cloud
-Messaging framework present on the device.</p>
-
-<p>Note that it might take a while for the registration ID be completely removed
-from GCM. Thus it is possible that messages sent during step 7 above gets a valid
-message ID as response, even though the message will not be delivered to the device.
-Eventually, the registration ID will be removed and the server will get a
-<code>NotRegistered</code> error, without any further action being required from
-the 3rd-party server (this scenario happens frequently while an application is
-being developed and tested).</p>
-
-<h2 id="collapsible">Send-to-Sync vs. Messages with Payload</h2>
-
-<p>Every message sent in GCM has the following characteristics:</p>
-<ul>
- <li>It has a payload limit of 4096 bytes.</li>
- <li>By default, it is stored by GCM for 4 weeks.</li>
-</ul>
-
-<p>But despite these similarities, messages can behave very differently depending
-on their particular settings. One major distinction between messages is whether
-they are collapsed (where each new message replaces the preceding message) or not
-collapsed (where each individual message is delivered). Every message sent in GCM
-is either a "send-to-sync" (collapsible) message or a "message with
-payload" (non-collapsible message). These concepts are described in more
-detail in the following sections.</p>
-
-<h3 id="s2s">Send-to-sync messages</h3>
-
-<p>A send-to-sync (collapsible) message is often a "tickle" that tells
-a mobile application to sync data from the server. For example, suppose you have
-an email application. When a user receives new email on the server, the server
-pings the mobile application with a "New mail" message. This tells the
-application to sync to the server to pick up the new email. The server might send
-this message multiple times as new mail continues to accumulate, before the application
-has had a chance to sync. But if the user has received 25 new emails, there's no
-need to preserve every "New mail" message. One is sufficient. Another
-example would be a sports application that updates users with the latest score.
-Only the most recent message is relevant, so it makes sense to have each new
-message replace the preceding message. </p>
-
-<p>The email and sports applications are cases where you would probably use the
-GCM <code>collapse_key</code> parameter. A <em>collapse key</em> is an arbitrary
-string that is used to collapse a group of like messages when the device is offline,
-so that only the most recent message gets sent to the client. For example,
-"New mail," "Updates available," and so on</p>
-<p>GCM allows a maximum of 4 different collapse keys to be used by the GCM server
-at any given time. In other words, the GCM server can simultaneously store 4
-different send-to-sync messages per device, each with a different collapse key.
-For example, Device A can have A1, A2, A3, and A4. Device B can have B1, B2, B3,
-and B4, and so on. If you exceed this number GCM will only keep 4 collapse keys, with no
-guarantees about which ones they will be.</p>
-
-<h3 id="payload">Messages with payload</h3>
-
-<p>Unlike a send-to-sync message, every "message with payload"
-(non-collapsible message) is delivered. The payload the message contains can be
-up to 4kb. For example, here is a JSON-formatted message in an IM application in
-which spectators are discussing a sporting event:</p>
-
-<pre class="prettyprint pretty-json">{
- "registration_id" : "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...",
- "data" : {
- "Nick" : "Mario",
- "Text" : "great match!",
- "Room" : "PortugalVSDenmark",
- },
-}</pre>
-
-<p>A "message with payload" is not simply a "ping" to the
-mobile application to contact the server to fetch data. In the aforementioned IM
-application, for example, you would want to deliver every message, because every
-message has different content. To specify a non-collapsible message, you simply
-omit the <code>collapse_key</code> parameter. Thus GCM will send each message
-individually. Note that the order of delivery is not guaranteed.</p>
-
-<p>GCM will store up to 100 non-collapsible messages. After that, all messages
-are discarded from GCM, and a new message is created that tells the client how
-far behind it is. The message is delivered through a regular
-<code>com.google.android.c2dm.intent.RECEIVE</code> intent with the
-extra <code>message_type</code>, for which the value is always the string
-"deleted_messages".</p>
-
-<p>The application should respond by syncing with the server to recover the
-discarded messages. </p>
-
-<h3 id="which">Which should I use?</h3>
- <p>If your application does not need to use non-collapsible messages, collapsible
-messages are a better choice from a performance standpoint, because they put less
-of a burden on the device battery. However, if you use collapsible messages, remember that
-<strong>GCM only allows a maximum of 4 different collapse keys to be used by the GCM server
-per device at any given time</strong>. You must not exceed this number, or it could cause
-unpredictable consequences.</p>
-
-<h2 dir="ltr" id="ttl">Setting an Expiration Date for a Message</h2>
-<p>The Time to Live (TTL) feature lets the sender specify the maximum lifespan
-of a message using the <code>time_to_live</code> parameter in the send request.
-The value of this parameter must be a duration from 0 to 2,419,200 seconds, and
-it corresponds to the maximum period of time for which GCM will store and try to
-deliver the message. Requests that don't contain this field default to the maximum
-period of 4 weeks.</p>
-<p>Here are some possible uses for this feature:</p>
-<ul>
- <li>Video chat incoming calls</li>
- <li>Expiring invitation events</li>
- <li>Calendar events</li>
-</ul>
-<h3 id="bg">Background </h3>
-<p>GCM will usually deliver messages immediately after they are sent. However,
-this might not always be possible. For example, the device could be turned off,
-offline, or otherwise unavailable. In other cases, the sender itself might request
-that messages not be delivered until the device becomes active by using the
-<code>delay_while_idle</code> flag. Finally, GCM might intentionally delay messages
-to prevent an application from consuming excessive resources and negatively
-impacting battery life.</p>
-
-<p>When this happens, GCM will store the message and deliver it as soon as it's
-feasible. While this is fine in most cases, there are some applications for which
-a late message might as well never be delivered. For example, if the message is
-an incoming call or video chat notification, it will only be meaningful for a
-small period of time before the call is terminated. Or if the message is an
-invitation to an event, it will be useless if received after the event has ended.</p>
-
-<p>Another advantage of specifying the expiration date for a message is that GCM
-will never throttle messages with a <code>time_to_live</code> value of 0 seconds.
-In other words, GCM will guarantee best effort for messages that must be delivered
-"now or never." Keep in mind that a <code>time_to_live</code> value of
-0 means messages that can't be delivered immediately will be discarded. However,
-because such messages are never stored, this provides the best latency for
-sending notifications.</p>
-
-<p>Here is an example of a JSON-formatted request that includes TTL:</p>
-<pre class="prettyprint pretty-json">
-{
- "collapse_key" : "demo",
- "delay_while_idle" : true,
- "registration_ids" : ["xyz"],
- "data" : {
- "key1" : "value1",
- "key2" : "value2",
- },
- "time_to_live" : 3
-},
-</pre>
-
-
-<h2 id="multi-senders">Receiving Messages from Multiple Senders</h2>
-
-<p>GCM allows multiple parties to send messages to the same application. For
-example, suppose your application is an articles aggregator with multiple
-contributors, and you want each of them to be able to send a message when they
-publish a new article. This message might contain a URL so that the application
-can download the article. Instead of having to centralize all sending activity in
-one location, GCM gives you the ability to let each of these contributors send
-its own messages.</p>
-
-<p>To make this possible, all you need to do is have each sender generate its own
-project number. Then include those IDs in the sender field, separated by commas,
-when requesting a registration. Finally, share the registration ID with your
-partners, and they'll be able to send messages to your application using their
-own authentication keys.</p>
-<p>This code snippet illustrates this feature. Senders are passed as an intent
-extra in a comma-separated list:</p>
-
-<pre class="prettyprint pretty-java">Intent intent = new Intent(GCMConstants.INTENT_TO_GCM_REGISTRATION);
-intent.setPackage(GSF_PACKAGE);
-intent.putExtra(GCMConstants.EXTRA_APPLICATION_PENDING_INTENT,
- PendingIntent.getBroadcast(context, 0, new Intent(), 0));
-String senderIds = "968350041068,652183961211";
-intent.putExtra(GCMConstants.EXTRA_SENDER, senderIds);
-ontext.startService(intent);
- </pre>
-
-<p>Note that there is limit of 100 multiple senders.</p>
diff --git a/docs/html/google/gcm/c2dm.jd b/docs/html/google/gcm/c2dm.jd
index 5c4a86e..fc95c2b 100644
--- a/docs/html/google/gcm/c2dm.jd
+++ b/docs/html/google/gcm/c2dm.jd
@@ -79,7 +79,7 @@
<h3 id="interop">Relationship between C2DM and GCM</h3>
-<p>C2DM and GCM are not interoperable. For example, you cannot post notifications from GCM to C2DM registration IDs, nor can you use C2DM registration IDs as GCM registration IDs. From your server-side application, you must keep keep track of whether a registration ID is from C2DM or GCM and use the proper endpoint. </p>
+<p>C2DM and GCM are not interoperable. For example, you cannot post notifications from GCM to C2DM registration IDs, nor can you use C2DM registration IDs as GCM registration IDs. From your server-side application, you must keep track of whether a registration ID is from C2DM or GCM and use the proper endpoint. </p>
<p>As you transition from C2DM to GCM, your server needs to be aware of whether a given registration ID
contains an old C2DM sender or a new GCM project number. This is the approach we recommend: have the new app version (the one that uses GCM) send a bit along with the registration ID. This bit tells your server that this registration ID is for GCM. If you don't get the extra bit, you mark the registration ID as C2DM. Once no more valid registration IDs are marked as C2DM, you can complete the migration.</p>
@@ -87,13 +87,11 @@
<h2 id="migrating">Migrating Your Apps</h2>
<p>This section describes how to move existing C2DM apps to GCM.</p>
<h3 id="client">Client changes</h3>
-<p>Migration is simple! The only change required in the application is replacing the email account passed in the sender parameter of the registration intent with the project number generated when signing up for the new service. For example:</p>
-<pre class="prettyprint pretty-java">Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
-// sets the app name in the intent
-registrationIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0));
-registrationIntent.putExtra("sender", senderID);
-startService(registrationIntent);</pre>
+<p>Migration is simple! Just re-register the client app for your target GCM-enabled platform. For
+ example, see <a href="{@docRoot}google/gcm/client.html#sample-register">Register for GCM</a></p>
+
<p>After receiving a response from GCM, the registration ID obtained must be sent to the application server. When doing this, the application should indicate that it is sending a GCM registration ID so that the server can distinguish it from existing C2DM registrations.</p>
+
<h3 id="server">Server changes</h3>
<p>When the application server receives a GCM registration ID, it should store it and mark it as such.</p>
<p>Sending messages to GCM devices requires a few changes:</p>
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index 6332b8d..143b057 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -36,6 +36,7 @@
<h2>See Also</h2>
<ol class="toc">
+<li><a href="server-ref.html">Server Reference</a></li>
<li><a href="{@docRoot}google/gcm/http.html">HTTP</a></li>
<li><a href="{@docRoot}google/gcm/gs.html">Getting Started</a></li>
<li><a href="{@docRoot}google/gcm/server.html">Implementing GCM Server</a></li>
@@ -73,8 +74,8 @@
APIs. For examples, see
<a href="#implement">Implementing an XMPP-based App Server</a>.</p>
-<p class="note"><strong>Note:</strong> See
-<a href="server.html#params">Implementing GCM Server</a> for a list of all the message
+<p class="note"><strong>Note:</strong> See the
+<a href="server-ref.html">Server Reference</a> for a list of all the message
parameters and which connection server(s) supports them.</p>
<h2 id="connecting">Establishing a Connection</h2>
@@ -176,8 +177,8 @@
<a href="#flow">Flow Control</a> for details.
</p>
-<p class="note"><strong>Note:</strong> See
-<a href="server.html#params">Implementing GCM Server</a> for a list of all the message
+<p class="note"><strong>Note:</strong> See the
+<a href="server-ref.html">Server Reference</a> for a list of all the message
parameters and which connection server(s) supports them.</p>
<h3 id="request">Request format</h3>
@@ -278,56 +279,11 @@
</message>
</pre>
-<p>The following table lists NACK error codes. Unless otherwise
+<p>See the <a href="server-ref.html#table11">Server Reference</a> for a complete list of the
+NACK error codes. Unless otherwise
indicated, a NACKed message should not be retried. Unexpected NACK error codes
should be treated the same as {@code INTERNAL_SERVER_ERROR}.</p>
-<p class="table-caption" id="table1">
- <strong>Table 1.</strong> NACK error codes.</p>
-
-<table border="1">
-<tr>
-<th>Error Code</th>
-<th>Description</th>
-</tr>
-<tr>
-<td>{@code BAD_ACK}</td>
-<td>The ACK message is improperly formed.</td>
-</tr>
-<tr>
-<td>{@code BAD_REGISTRATION}</td>
-<td>The device has a registration ID, but it's invalid or expired.</td>
-</tr>
-<tr>
-<td>{@code CONNECTION_DRAINING}</td>
-<td>The message couldn't be processed because the connection is draining. The
-message should be immediately retried over another connection.</td>
-</tr>
-<tr>
-<td>{@code DEVICE_UNREGISTERED}</td>
-<td>The device is not registered.</td>
-</tr>
-<tr>
-<td>{@code INTERNAL_SERVER_ERROR}</td>
-<td>The server encountered an error while trying to process the request.</td>
-</tr>
-<tr>
-<td>{@code INVALID_JSON}</td>
-<td>The JSON message payload is not valid.</td>
-</tr>
-<td>{@code DEVICE_MESSAGE_RATE_EXCEEDED}</td>
-<td>The rate of messages to a particular device is too high. You should reduce
-the number of messages sent to this device and should not immediately retry
-sending to this device. This error code is replacing {@code QUOTA_EXCEEDED}.</td>
-</tr>
-<tr>
- <td>{@code SERVICE_UNAVAILABLE}</td>
- <td>CCS is not currently able to process the message. The
- message should be retried over the same connection using exponential backoff
- with an initial delay of 1 second.</td>
-</tr>
-</table>
-
<h4 id="stanza">Stanza error</h4>
<p>You can also get a stanza error in certain cases.
diff --git a/docs/html/google/gcm/client.jd b/docs/html/google/gcm/client.jd
index d44ee3c..9cb3f84 100644
--- a/docs/html/google/gcm/client.jd
+++ b/docs/html/google/gcm/client.jd
@@ -1,4 +1,4 @@
-page.title=Implementing GCM Client
+page.title=Implementing GCM Client on Android
page.tags=cloud,push,messaging
@jd:body
@@ -15,8 +15,8 @@
<ol class="toc">
<li><a href="#sample-play">Check for Google Play Services APK</a></li>
<li><a href="#sample-register">Register for GCM</a></li>
- <li><a href="#sample-send">Send a message</a></li>
- <li><a href="#sample-receive">Receive a message</a></li>
+ <li><a href="#sample-receive">Receive a downstream message</a></li>
+ <li><a href="#sample-send">Send an upstream message</a></li>
</ol>
<li><a href="#run">Running the Sample</a></li>
<li><a href="#stats">Viewing Statistics</a></li>
@@ -34,14 +34,26 @@
</div>
</div>
-<p>A Google Cloud Messaging (GCM) client is a GCM-enabled app that runs on an
+<p>A Google Cloud Messaging (GCM) Android client is a GCM-enabled app that runs on an
Android device. To write your client code, we recommend that you use the
<a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
-GCM APIs</a>.
-The client helper library that was offered in previous versions of GCM still works,
-but it has been superseded by the more efficient
-<a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
-GCM APIs</a>.</p>
+{@code GoogleCloudMessaging}</a> API.</p>
+
+<p>Here are the requirements for running a GCM Android client:</p>
+
+<ul>
+ <li>At a bare minimum, GCM requires devices running Android 2.2 or higher that also have the
+Google Play Store application installed, or an emulator running Android 2.2
+with Google APIs. Note that you are not limited to deploying your
+Android applications through Google Play Store.</li>
+ <li>However, if you want to continue to use new GCM features that are distributed
+through Google Play Services, the device must be running Android 2.3 or higher, or
+you can use an emulator running Android 2.3 with Google APIs.</li>
+<li>On Android devices, GCM uses an existing connection for Google services. For
+pre-3.0 devices, this requires users to set up their Google accounts on their mobile
+devices. A Google account is not a requirement on devices running Android 4.0.4 or higher.</li>
+
+</ul>
<p>A full GCM implementation requires both a client implementation and a server
implementation. For more
@@ -58,7 +70,7 @@
<p>To write your client application, use the
<a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
-GCM APIs</a>.
+{@code GoogleCloudMessaging}</a> API.
To use this API, you must set up your project to use the Google Play services SDK,
as described in <a href="/google/play-services/setup.html">Setup Google Play
Services SDK</a>.</p>
@@ -88,9 +100,6 @@
the Android application can register and receive messages.</li>
<li>The <code>android.permission.INTERNET</code> permission so the Android
application can send the registration ID to the 3rd party server.</li>
- <li>The <code>android.permission.GET_ACCOUNTS</code> permission as GCM requires
-a Google account (necessary only if if the device is running a version lower than
-Android 4.0.4)</li>
<li>The <code>android.permission.WAKE_LOCK</code> permission so the application
can keep the processor from sleeping when a message is received. Optional—use
only if the app wants to keep the device from sleeping.</li>
@@ -101,7 +110,7 @@
<li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code>, with
the category set
as <code>applicationPackage</code>. The receiver should require the
-<code>com.google.android.c2dm.SEND</code> permission, so that only the GCM
+<code>com.google.android.c2dm.permission.SEND</code> permission, so that only the GCM
Framework can send a message to it. If your app uses an {@link android.app.IntentService}
(not required, but a common pattern), this receiver should be an instance of
{@link android.support.v4.content.WakefulBroadcastReceiver}.
@@ -324,8 +333,8 @@
return "";
}
// Check if app was updated; if so, it must clear the registration ID
- // since the existing regID is not guaranteed to work with the new
- // app version.
+ // since the existing registration ID is not guaranteed to work with
+ // the new app version.
int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion) {
@@ -340,14 +349,14 @@
*/
private SharedPreferences getGCMPreferences(Context context) {
// This sample app persists the registration ID in shared preferences, but
- // how you store the regID in your app is up to you.
+ // how you store the registration ID in your app is up to you.
return getSharedPreferences(DemoActivity.class.getSimpleName(),
Context.MODE_PRIVATE);
}</pre>
<p>If the registration ID doesn't exist or the app was updated,
{@code getRegistrationId()} returns an empty string
-to indicate that the app needs to get a new regID. {@code getRegistrationId()} calls
+to indicate that the app needs to get a new registration ID. {@code getRegistrationId()} calls
the following method to check the app version:</p>
<pre>/**
@@ -400,7 +409,7 @@
// will send upstream messages to a server that echo back the
// message using the 'from' address in the message.
- // Persist the regID - no need to register again.
+ // Persist the registration ID - no need to register again.
storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
@@ -433,7 +442,8 @@
<p>After registering, the app calls {@code storeRegistrationId()} to store the
registration ID in shared preferences for future use. This is just one way of
-persisting a regID. You might choose to use a different approach in your app:</p>
+persisting a registration ID. You might choose to use a different approach in
+your app:</p>
<pre>/**
* Stores the registration ID and app versionCode in the application's
@@ -455,64 +465,22 @@
<h4 id="reg-errors">Handle registration errors</h4>
<p>As stated above, an Android app must register with GCM servers and get a registration ID
-(regID) before it can receive messages. A given regID is not guaranteed to last indefinitely,
-so the first thing your app should always do is check to make sure it has a valid regID
-(as shown in the code snippets above).</p>
+before it can receive messages. A given registration ID is not guaranteed to last indefinitely,
+so the first thing your app should always do is check to make sure it has a valid
+registration ID (as shown in the code snippets above).</p>
-<p>In addition to confirming that it has a valid regID, your app should be prepared to handle
+<p>In addition to confirming that it has a valid registration ID, your app should be prepared to handle
the registration error {@code TOO_MANY_REGISTRATIONS}. This error indicates that the device
has too many apps registered with GCM. The error only occurs in cases where there are
extreme numbers of apps, so it should not affect the average user. The remedy is to prompt
-the user to delete some of the other GCM-enabled apps from the device to make
+the user to delete some of the other client apps from the device to make
room for the new one.</p>
-
-<h3 id="sample-send">Send a message</h3>
-<p>When the user clicks the app's <strong>Send</strong> button, the app sends an
-upstream message using the
-<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
-{@code GoogleCloudMessaging}</a> API. In order to receive the upstream message,
-your server should be connected to CCS. You can use one of the demo servers in
-<a href="ccs.html#implement">Implementing an XMPP-based App Server</a> to run the sample and connect
-to CCS.</p>
-
-<pre>public void onClick(final View view) {
- if (view == findViewById(R.id.send)) {
- new AsyncTask<Void, Void, String>() {
- @Override
- protected String doInBackground(Void... params) {
- String msg = "";
- try {
- Bundle data = new Bundle();
- data.putString("my_message", "Hello World");
- data.putString("my_action",
- "com.google.android.gcm.demo.app.ECHO_NOW");
- String id = Integer.toString(msgId.incrementAndGet());
- gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);
- msg = "Sent message";
- } catch (IOException ex) {
- msg = "Error :" + ex.getMessage();
- }
- return msg;
- }
-
- @Override
- protected void onPostExecute(String msg) {
- mDisplay.append(msg + "\n");
- }
- }.execute(null, null, null);
- } else if (view == findViewById(R.id.clear)) {
- mDisplay.setText("");
- }
-}</pre>
-
-<h3 id="sample-receive">Receive a message</h3>
+<h3 id="sample-receive">Receive a downstream message</h3>
<p>As described above in <a href="#manifest">Step 2</a>, the app includes a
{@link android.support.v4.content.WakefulBroadcastReceiver} for the <code>com.google.android.c2dm.intent.RECEIVE</code>
-intent. A broadcast receiver is the mechanism GCM uses to deliver messages. When {@code onClick()}
-calls {@code gcm.send()}, it triggers the broadcast receiver's {@code onReceive()}
-method, which has the responsibility of making sure that the GCM message gets handled.</p>
+intent. A broadcast receiver is the mechanism GCM uses to deliver messages. </p>
<p>A {@link android.support.v4.content.WakefulBroadcastReceiver} is a special type of
broadcast receiver that takes care of
creating and managing a
@@ -646,6 +614,46 @@
}
}</pre>
+
+<h3 id="sample-send">Send an upstream message</h3>
+<p>When the user clicks the app's <strong>Send</strong> button, the app sends an
+upstream message using the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> API. In order to receive the upstream message,
+your server should be connected to CCS. You can use one of the demo servers in
+<a href="ccs.html#implement">Implementing an XMPP-based App Server</a> to run the sample and connect
+to CCS.</p>
+
+<pre>public void onClick(final View view) {
+ if (view == findViewById(R.id.send)) {
+ new AsyncTask<Void, Void, String>() {
+ @Override
+ protected String doInBackground(Void... params) {
+ String msg = "";
+ try {
+ Bundle data = new Bundle();
+ data.putString("my_message", "Hello World");
+ data.putString("my_action",
+ "com.google.android.gcm.demo.app.ECHO_NOW");
+ String id = Integer.toString(msgId.incrementAndGet());
+ gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);
+ msg = "Sent message";
+ } catch (IOException ex) {
+ msg = "Error :" + ex.getMessage();
+ }
+ return msg;
+ }
+
+ @Override
+ protected void onPostExecute(String msg) {
+ mDisplay.append(msg + "\n");
+ }
+ }.execute(null, null, null);
+ } else if (view == findViewById(R.id.clear)) {
+ mDisplay.setText("");
+ }
+}</pre>
+
<h2 id="run">Running the Sample</h2>
<p>To run the sample:</p>
diff --git a/docs/html/google/gcm/gcm.jd b/docs/html/google/gcm/gcm.jd
index 3d6594d..4e345b3 100644
--- a/docs/html/google/gcm/gcm.jd
+++ b/docs/html/google/gcm/gcm.jd
@@ -9,58 +9,24 @@
<ol class="toc">
<li><a href="#key">Key Concepts</a></li>
<li><a href="#arch">Architectural Overview</a></li>
- <li><a href="#lifecycle">Lifecycle Flow</a>
- <ol class="toc">
- <li><a href="#register">Enable GCM</a></li>
- <li><a href="#push-process">Send a message</a></li>
- <li><a href="#receiving">Receive a message</a></li>
- </ol>
- </li>
+ <li><a href="#lifecycle">Lifecycle Flow</a></li>
+ <li><a href="#reg">Register to enable GCM</a></li>
</ol>
</div>
</div>
-<p>Google Cloud Messaging (GCM) for Android is a free service that helps
-developers send data from servers to their Android applications on Android
-devices, and upstream messages from the user's device back to the cloud.
-This could be a lightweight message telling the Android application
+<p>Google Cloud Messaging (GCM) is a free service that enables developers
+to send downstream messages (from servers to GCM-enabled client apps), and
+upstream messages (from the GCM-enabled client apps to servers).
+This could be a lightweight message telling the client app
that there is new data to be fetched from the server (for instance, a "new email"
-notification informing the application that it is out of sync with the back end),
+notification informing the app that it is out of sync with the back end),
or it could be a message containing up to 4kb of payload
data (so apps like instant messaging can consume the message directly). The GCM
-service handles all aspects of queueing of messages and delivery to the target
-Android application running on the target device.</p>
-
-<p class="note"> To jump right into using GCM with your Android
- applications, see <a href="gs.html">Getting Started</a>.</p>
+service handles all aspects of queueing of messages and delivery to and from
+the target client app.</p>
-<p>Here are the primary characteristics of Google Cloud
-Messaging (GCM):</p>
-
-<ul>
- <li>It allows 3rd-party application servers to send messages to
-their Android applications.</li>
- <li>Using the <a href="ccs.html">GCM Cloud Connection Server</a>, you can receive
-upstream messages from the user's device.</li>
- <li>An Android application on an Android device doesn't need to be running to receive
-messages. The system will wake up the Android application via Intent broadcast
-when the message arrives, as long as the application is set up with the proper
-broadcast receiver and permissions.</li>
- <li>It does not provide any built-in user interface or other handling for
-message data. GCM simply passes raw message data received straight to the
-Android application, which has full control of how to handle it. For example, the
-application might post a notification, display a custom user interface, or
-silently sync data.</li>
- <li>It requires devices running Android 2.2 or higher that also have the
-Google Play Store application installed, or or an emulator running Android 2.2
-with Google APIs. However, you are not limited to deploying your
-Android applications through Google Play Store.</li>
- <li>It uses an existing connection for Google services. For pre-3.0 devices,
-this requires users to
-set up their Google account on their mobile devices. A Google account is not a
-requirement on devices running Android 4.0.4 or higher.</li>
-</ul>
<h2 id="key">Key Concepts</h2>
@@ -70,7 +36,7 @@
<li><strong>Components</strong> — The entities that play a primary role in
GCM.</li>
<li><strong>Credentials</strong> — The IDs and tokens that are used in
-different stages of GCM to ensure that all parties have been authenticated, and
+GCM to ensure that all parties have been authenticated, and
that the message is going to the correct place.</li>
</ul>
@@ -81,24 +47,20 @@
<tr>
<th colspan="2">Components</th>
</tr>
- <tr>
- <td width="165"><strong>Client App</strong></td>
- <td width="1176">The GCM-enabled Android application that is running on a
- device. This must be a 2.2 Android device that has Google Play Store installed, and it must
-have at least one logged in Google account if the device is running a version
-lower than Android 4.0.4. Alternatively, for testing you can use an emulator
-running Android 2.2 with Google APIs.</td>
- </tr>
- <tr>
- <td><strong>3rd-party Application Server</strong></td>
- <td>An application server that you write as part of implementing
-GCM. The 3rd-party application server sends data to an
-Android application on the device via the GCM connection server.</td>
- </tr>
- <tr>
+<tr>
<td><strong>GCM Connection Servers</strong></td>
- <td>The Google-provided servers involved in taking messages from the 3rd-party
-application server and sending them to the device. </td>
+ <td>The Google-provided servers involved in sending messages between the
+3rd-party app server and the client app.</td>
+ </tr>
+ <tr>
+ <td><strong>Client App</strong></td>
+ <td>A GCM-enabled client app that communicates with a 3rd-party app server.</td>
+ </tr>
+ <tr>
+ <td><strong>3rd-party App Server</strong></td>
+ <td>An app server that you write as part of implementing
+GCM. The 3rd-party app server sends data to a client app via
+the GCM connection server.</td>
</tr>
<tr>
<th colspan="2">Credentials</th>
@@ -108,42 +70,28 @@
<td>A project number you acquire from the API console, as described in
<a href="gs.html#create-proj">Getting Started</a>. The sender
ID is used in the <a href="#register">registration process</a> to identify a
-3rd-party application server that is permitted to send messages to the device.</td>
- </tr>
- <tr>
- <td><strong>Application ID</strong></td>
- <td>The Android application that is registering to receive messages. The Android application
-is identified by the package name from the <a href="client.html#manifest">manifest</a>.
-This ensures that the messages are targeted to the correct Android application.</td>
- </tr>
- <tr>
- <td><strong>Registration ID</strong></td>
- <td>An ID issued by the GCM servers to the Android application that allows
-it to receive messages. Once the Android application has the registration ID, it sends
-it to the 3rd-party application server, which uses it to identify each device
-that has registered to receive messages for a given Android application. In other words,
-a registration ID is tied to a particular Android application running on a particular
-device. Note that registration IDs must be kept secret.
-<br/>
-<br/>
-<strong>Note:</strong> If you use
-<a href="https://developer.android.com/google/backup/index.html">backup and restore</a>,
-you should explicitly avoid backing up registration IDs. When you back up
-a device, apps back up shared prefs indiscriminately. If you don't explicitly
-exclude the GCM registration ID, it could get reused on a new device,
-which would cause delivery errors.
-</td>
- </tr>
- <tr>
- <td><strong>Google User Account</strong></td>
- <td>For GCM to work, the mobile device must include at least one Google
-account if the device is running a version lower than Android 4.0.4.</td>
+3rd-party app server that is permitted to send messages to the client app.</td>
</tr>
<tr>
<td id="apikey"><strong>Sender Auth Token</strong></td>
- <td>An API key that is saved on the 3rd-party application
-server that gives the application server authorized access to Google services.
-The API key is included in the header of POST requests that send messages.</td>
+ <td>An API key that is saved on the 3rd-party app
+server that gives the app server authorized access to Google services.
+The API key is included in the header of POST requests.
+</td>
+ </tr>
+ <tr>
+ <td><strong>Application ID</strong></td>
+ <td>The client app that is registering to receive messages. How this is implemented
+is platform-dependent. For example, an Android app
+is identified by the package name from the <a href="client.html#manifest">manifest</a>.
+This ensures that the messages are targeted to the correct Android app.</td>
+ </tr>
+ <tr>
+ <td><strong>Registration ID</strong></td>
+ <td>An ID issued by the GCM servers to the client app that allows
+it to receive messages. Note that registration IDs must be kept secret.
+
+</td>
</tr>
</table>
@@ -152,7 +100,8 @@
<p>A GCM implementation includes a Google-provided
connection server, a 3rd-party app server that interacts with the connection
-server, and a GCM-enabled client app running on an Android device:</p>
+server, and a GCM-enabled client app. For example, this diagram shows GCM
+communicating with a client app on an Android device:</p>
<img src="{@docRoot}images/gcm/GCM-arch.png">
@@ -163,84 +112,196 @@
<p>This is how these components interact:</p>
<ul>
<li>Google-provided <strong>GCM Connection Servers</strong> take messages from
-a 3rd-party application server and send these messages to a
-GCM-enabled Android application (the "client app") running on a device.
+a 3rd-party app server and send these messages to a
+GCM-enabled client app (the "client app").
Currently Google provides connection servers for <a href="http.html">HTTP</a>
and <a href="ccs.html">XMPP</a>.</li>
- <li>The <strong>3rd-Party Application Server</strong> is a component that you
+ <li>The <strong>3rd-Party App Server</strong> is a component that you
implement to work with your chosen GCM connection server(s). App servers send
messages to a GCM connection server; the connection server enqueues and stores the
-message, and then sends it to the device when the device is online.
+message, and then sends it to the client app.
For more information, see <a href="server.html">Implementing GCM Server</a>.</li>
- <li>The <strong>Client App</strong> is a GCM-enabled Android application running
-on a device. To receive GCM messages, this app must register with GCM and get a
+ <li>The <strong>Client App</strong> is a GCM-enabled client app.
+To receive GCM messages, this app must register with GCM and get a
registration ID. If you are using the <a href="ccs.html">XMPP</a> (CCS) connection
-server, the client app can send "upstream" messages back to the connection server.
+server, the client app can send "upstream" messages back to the 3rd-party app server.
For more information on how to implement the client app, see
-<a href="client.html">Implementing GCM Client</a>.</li>
+the documentation for your platform.</li>
</ul>
<h2 id="lifecycle">Lifecycle Flow</h2>
<ul>
- <li><a href="#register">Enable GCM</a>. An Android application running on a
-mobile device registers to receive messages.</li>
+ <li><strong>Register to enable GCM</strong>. A client app registers to receive messages.
+For more discussion, see <a href="#register">Register to enable GCM</a>.</li>
+ <li><strong>Send and receive downstream messages</strong>.
+ <ul>
+ <li>Send a message. A 3rd-party app server sends messages to the client app:
+ <ol>
+ <li>The 3rd-party app server <a href="server.html#send-msg">sends a message</a>
+to GCM connection servers.</li>
+ <li>The GCM connection server enqueues and stores the message if the device is offline.</li>
+ <li>When the device is online, the GCM connection server sends the message to the device. </li>
+ <li>On the device, the client app receives the message according to the platform-specific implementation.
+See your platform-specific documentation for details.</li>
+ </ol>
+ </li>
+ <li>Receive a message. A client app
+receives a message from a GCM server. See your platform-specific documentation for details
+on how a client app in that environment processes the messages it receives.</li>
+ </ul>
+</li>
- <li><a href="#push-process">Send a message</a>. A 3rd-party application
-server sends messages to the device.</li>
- <li><a href="#receiving">Receive a message</a>. An Android application
-receives a message from a GCM server.</li>
+ <li><strong>Send and receive upstream messages</strong>. This feature is only available if
+you're using the <a href="ccs.html">XMPP Cloud Connection Server</a> (CCS).
+<ul>
+ <li>Send a message. A client app sends messages to the 3rd-party app server:
+ <ol>
+ <li>On the device, the client app sends messages to XMPP (CCS).See your platform-specific
+ documentation for details on how a client app can send a message to XMPP (CCS).</li>
+ <li>XMPP (CCS) enqueues and stores the message if the server is disconnected.</li>
+ <li>When the 3rd-party app server is re-connected, XMPP (CCS) sends the message to the 3rd-party app server.</li>
+ </ol>
+ </li>
+ <li>Receive a message. A 3rd-party app server receives a message from XMPP (CCS) and then does the following:
+ <ol>
+ <li>Parses the message header to verify client app sender information.
+ <li>Sends "ack" to GCM XMPP connection server to acknowledge receiving the message.
+ <li>Optionally parses the message payload, as defined by the client app.
+ </ol>
+</li>
</ul>
-<p>These processes are described in more detail below.</p>
+</li>
-<h3 id="register">Enable GCM</h3>
-<p>The first time the Android application needs to use the messaging service, it
-calls the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
-{@code GoogleCloudMessaging}</a> method {@code register()}, as discussed in
-<a href="client.html">Implementing GCM Client</a>.
-The {@code register()} method returns a registration ID. The Android
-application should store this ID for later use (for instance,
-to check in <code>onCreate()</code> if it is already registered).
+</ul>
+
+<h2 id="reg">Register to enable GCM</h2>
+
+<p>Regardless of the platform you're developing on, the first step
+a client app must do is register with GCM. This section covers some of the general
+best practices for registration and unregistration. See your platform-specific docs for
+details on writing a GCM-enabled client app on that platform.</p>
+
+<h3 id="reg-state">Keeping the Registration State in Sync</h3>
+<p>Whenever the app registers as described in
+<a href="{@docRoot}google/gcm/client.html">Implementing GCM Client</a>,
+it should save the registration ID for future use, pass it to the
+3rd-party server to complete the registration, and keep track of
+whether the server completed the registration. If the server fails
+to complete the registration, the client app should retry passing the
+registration ID to 3rd-party app server to complete the registration.
+If this continues to fail, the client app should unregister from GCM.</p>
+
+<p>There are also two other scenarios that require special care:</p>
+<ul>
+ <li>Client app update</li>
+ <li>Backup and restore
+ </li>
+</ul>
+<p><bold>Client app update:</bold> When a client app is updated, it should invalidate its existing registration
+ID, as it is not guaranteed to work with the new version. The recommended way to achieve
+this validation is by storing the current app version when a registration
+ID is stored. Then when the app starts, compare the stored value with
+the current app version. If they do not match, invalidate the stored data
+and start the registration process again.</p>
+
+<p><bold>Backup and restore: </bold> You should not save the registration ID when an app is
+backed up. This is because the registration ID could become invalid by the time
+the app is restored, which would put the app in an invalid state
+(that is, the app thinks it is registered, but the server and GCM do not
+store that registration ID anymore—thus the app will not get more
+messages). The best practice is to initiate the registration process as if the app has been
+installed for the first time.</p>
+
+<h4 id="canonical">Canonical IDs</h4>
+<p>If a bug in the app triggers multiple
+registrations for the same device, it can be hard to reconcile state and you might
+end up with duplicate messages.</p>
+<p>GCM provides a facility called "canonical registration IDs" to easily
+recover from these situations. A canonical registration ID is defined to be the ID
+of the last registration requested by your app. This is the ID that the
+server should use when sending messages to the device.</p>
+<p>If later on you try to send a message using a different registration ID, GCM
+will process the request as usual, but it will include the canonical registration
+ID in the <code>registration_id</code> field of the response. Make sure to replace
+the registration ID stored in your server with this canonical ID, as eventually
+the ID you're using will stop working.</p>
+
+<h3 id="retry">Automatic Retry Using Exponential Back-Off</h3>
+
+<p>When registration or unregistration fails, the app should retry the failed operation.</p>
+<p>In the simplest case, if your app attempts to register and GCM is not a
+fundamental part of the app, the app could simply ignore the error
+and try to register again the next time it starts. Otherwise, it should retry the
+previous operation using exponential back-off. In exponential back-off, each time
+there is a failure, it should wait twice the previous amount of time before trying
+again.
</p>
-<h3 id="push-process">Send a message</h3>
+<h3 id="unreg">Unregistration</h3>
-<p>Here is the sequence of events that occurs when the application server sends a
-message:</p>
+<p>This section explains when you should unregister in GCM and what happens
+when you do.</p>
+<h4 id="unreg-why">Why you should rarely unregister</h4>
+
+<p>You should only need to unregister in rare cases, such as
+if you want an app to stop receiving messages, or if you suspect that the registration ID has
+been compromised. In general, once an app has a registration ID, you shouldn't need
+to change it.</p>
+
+<p>In particular, you should never unregister your app as a mechanism for
+logout or for switching between users, for the following reasons:</p>
+
+<ul>
+ <li>A registration ID isn't associated with a particular
+ logged in user. If you unregister and then re-register, GCM may return the same
+ ID or a different ID—there's no guarantee either way.</li>
+
+ <li>Unregistration may take up to 5 minutes to propagate.</li>
+ <li>After unregistration, re-registration may again take up to 5 minutes to
+propagate. During this time messages may be rejected due to the state of being
+unregistered, and after all this, messages may still go to the wrong user.</li>
+</ul>
+
+
+<p>To make sure that messages go to the intended user:</p>
+
+<ul>
+ <li>Your app server can maintain a mapping between the current user
+and the registration ID.</li>
+ <li>The app can then check to ensure that messages it
+receives match the logged in user.</li>
+</ul>
+
+
+<h4 id="unreg-how">How unregistration works</h4>
+
+<p>An app can be automatically unregistered after it is uninstalled.
+However, this process does not happen right away. What happens in
+this scenario is as follows:</p>
<ol>
- <li>The application server sends a message to GCM servers.</li>
- <li>Google enqueues and stores the message in case the device is
-offline.</li>
- <li>When the device is online, Google sends the message to the device. </li>
- <li>On the device, the system broadcasts the message to the specified
-Android application via Intent broadcast with proper permissions, so that only the
-targeted Android application gets the message. This wakes the Android application up. The
-Android application does not need to be running beforehand to receive the message.</li>
- <li>The Android application processes the message. If the Android application is doing
-non-trivial processing, you may want to grab a
-{@link android.os.PowerManager.WakeLock} and do any processing in a service.</li>
+ <li>The end user uninstalls the client app.</li>
+ <li>The 3rd-party app server sends a message to GCM server.</li>
+ <li>The GCM server sends the message to the GCM client on the device.</li>
+ <li>The GCM client on the device receives the message and detects that the client app has been
+ uninstalled; the detection details depend on the platform on which the client app is running.
+</li>
+ <li>The GCM client on the device informs the GCM server that the client app was uninstalled.</li>
+ <li>The GCM server marks the registration ID for deletion.</li>
+ <li>The 3rd-party app server sends a message to GCM.</li>
+ <li>The GCM returns a <code>NotRegistered</code> error message to the 3rd-party app server.</li>
+ <li>The 3rd-party app server deletes the registration ID.
+ </li>
</ol>
-<p> An Android application can unregister GCM if it no longer wants to receive
-messages.</p>
-
-<h3 id="receiving">Receive a message</h3>
-
-<p>This is the sequence of events that occurs when an Android application
-installed on a mobile device receives a message:</p>
-
-<ol>
- <li>The system receives the incoming message and extracts the raw key/value
-pairs from the message payload, if any.</li>
- <li>The system passes the key/value pairs to the targeted Android application
-in a <code>com.google.android.c2dm.intent.RECEIVE</code> Intent as a set of
-extras.</li>
- <li>The Android application extracts the raw data
-from the <code>com.google.android.c2dm.intent.RECEIVE</code><code> </code>Intent
-by key and processes the data.</li>
-</ol>
-
+<p>Note that it might take a while for the registration ID be completely removed
+from GCM. Thus it is possible that messages sent during step 7 above gets a valid
+message ID as response, even though the message will not be delivered to the client app.
+Eventually, the registration ID will be removed and the server will get a
+<code>NotRegistered</code> error, without any further action being required from
+the 3rd-party server (this scenario happens frequently while an app is
+being developed and tested).</p>
diff --git a/docs/html/google/gcm/gs.jd b/docs/html/google/gcm/gs.jd
index a889624..2331292 100644
--- a/docs/html/google/gcm/gs.jd
+++ b/docs/html/google/gcm/gs.jd
@@ -1,4 +1,4 @@
-page.title=Getting Started
+page.title=Getting Started on Android
page.tags=cloud,push,messaging
@jd:body
@@ -46,7 +46,7 @@
<li>Copy down your project number. You will use it later on as the
<a href="{@docRoot}google/gcm/gcm.html#senderid">GCM sender ID</a>.</li>
-
+
</ol>
<h2 id="gcm-service">Enabling the GCM Service</h2>
<p>To enable the GCM service:</p>
@@ -71,7 +71,7 @@
<li>In the refreshed page, copy the
<a href="{@docRoot}google/gcm/gcm.html#apikey">API key</a>.
-You will need the API key later on to perform authentication in your application server.</li>
+You will need the API key later on to perform authentication in your app server.</li>
<p class="note"><strong>Note:</strong> If you need to rotate the key, click
<strong>Regenerate key</strong>. A new key will be created. If you think the key has been
@@ -84,16 +84,11 @@
implementing GCM. Here is an overview of the basic steps:</p>
<ol>
- <li>Decide which Google-provided GCM connection server you want to use—
- <a href="http.html">HTTP</a> or <a href="ccs.html">XMPP</a> (CCS). GCM connection servers
-take messages from a 3rd-party application
-server (written by you) and send them to a GCM-enabled Android application (the
-"client app," also written by you) running on a device. </li>
- <li>Implement an application server (the "3rd-party application server") to interact
+ <li>Implement an app server (the "3rd-party app server") to interact
with your chosen GCM connection server. The app server sends data to a
-GCM-enabled Android client application via the GCM connection server. For more
+GCM-enabled Android client app via the GCM connection server. For more
information about implementing the server side, see <a href="server.html">
Implementing GCM Server</a>.</li>
-<li>Write your client app. This is the GCM-enabled Android application that runs
+<li>Write your client app. This is the GCM-enabled Android app that runs
on a device. See <a href="client.html">Implementing GCM Client</a> for more information.</li>
</ol>
diff --git a/docs/html/google/gcm/http.jd b/docs/html/google/gcm/http.jd
index 773acd1..5022e09 100644
--- a/docs/html/google/gcm/http.jd
+++ b/docs/html/google/gcm/http.jd
@@ -23,6 +23,7 @@
<h2>See Also</h2>
<ol class="toc">
+<li><a href="server-ref.html">Server Reference</a></li>
<li><a href="gs.html">Getting Started</a></li>
<li><a href="client.html">Implementing GCM Client</a></li>
<li><a href="ccs.html">Cloud Connection Server</a></li>
@@ -42,26 +43,30 @@
applies to <a href="http://developer.chrome.com/apps/cloudMessaging">
GCM with Chrome apps</a> as well as Android.</p>
-<p>See
-<a href="server.html#params">Implementing GCM Server</a> for a list of all the message
+<p>See the
+<a href="server-ref.html">Server Reference</a> for a list of all the message
parameters and which connection server(s) supports them.</p>
<h2 id="auth">Authentication</h2>
-<p>To send a message, the application server issues a POST request to
-<code>https://android.googleapis.com/gcm/send</code>.</p>
+<p>To send a message, the application server issues a POST request. For example:</p>
+<pre>https://android.googleapis.com/gcm/send</pre>
<p>A message request is made of 2 parts: HTTP header and HTTP body.</p>
<p>The HTTP header must contain the following headers:</p>
<ul>
<li><code>Authorization</code>: key=YOUR_API_KEY</li>
- <li><code>Content-Type</code>: <code>application/json</code> for JSON; <code>application/x-www-form-urlencoded;charset=UTF-8</code> for plain text.
+ <li><code>Content-Type</code>: <code>application/json</code> for JSON;
+<code>application/x-www-form-urlencoded;charset=UTF-8</code> for plain text.
+If <code>Content-Type</code> is omitted, the format
+is assumed to be plain text.
</li>
</ul>
<p>For example:
</p>
+
<pre>Content-Type:application/json
Authorization:key=AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA
@@ -71,26 +76,30 @@
...
},
}</pre>
-<p class="note">
- <p><strong>Note:</strong> If <code>Content-Type</code> is omitted, the format
-is assumed to be plain text.</p>
-</p>
+
<p>The HTTP body content depends on whether you're using JSON or plain text.
See
-<a href="server.html#params">Implementing GCM Server</a> for a list of all the
+<a href="server-ref.html#params">the Server Reference</a> for a list of all the
parameters your JSON or plain text message can contain.</p>
<h2 id="request">Request Format</h2>
+
+<p>This section shows you how to format a request for both JSON and plain text. See
+the <a href="server-ref.html#table1">Server Reference</a> for a complete
+list of the fields you can include in a request.</p>
+
<p>Here is the smallest possible request (a message without any parameters and
just one recipient) using JSON:</p>
+
<pre class="prettyprint pretty-json">{ "registration_ids": [ "42" ] }</pre>
<p>And here the same example using plain text:</p>
<pre class="prettyprint">registration_id=42</pre>
<p> Here is a message with a payload and 6 recipients:</p>
+
<pre class="prettyprint pretty-HTML">{ "data": {
"score": "5x1",
"time": "15:10"
@@ -112,10 +121,25 @@
<pre class="prettyprint">collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.score=4x8&data.time=15:16.2342&registration_id=42
</pre>
+<p>Here is a message that includes a notification key and payload:</p>
+
+<pre>
+{
+ "data": {
+ "message": "ciao"
+ },
+ "notification_key":"aUniqueKey"
+}
+</pre>
+
+<p>For more information about notifications and how to use them, see
+<a href="{@docRoot}google/gcm/notifications.html">User Notifications</a>.</p>
+
+
<p class="note"><strong>Note:</strong> If your organization has a firewall
that restricts the traffic to or
from the Internet, you need to configure it to allow connectivity with GCM in order for
-your Android devices to receive messages.
+your GCM client apps to receive messages.
The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but
it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should allow
your firewall to accept outgoing connections to all IP addresses
@@ -127,54 +151,12 @@
<p>There are two possible outcomes when trying to send a message:</p>
<ul>
- <li>The message is processed successfully.</li>
- <li>The GCM server rejects the request.</li>
+ <li>The message is processed successfully. The HTTP response has a 200 status, and
+the body contains more information about the status of the message (including possible errors).</li>
+ <li>The GCM server rejects the request. The HTTP response contains a
+non-200 status code (such as 400, 401 or 5xx).</li>
</ul>
-<p>When the message is processed successfully, the HTTP response has a 200 status
-and the body contains more information about the status of the message
-(including possible errors). When the request is rejected,
-the HTTP response contains a non-200 status code (such as 400, 401, or 503).</p>
-
-<p>The following table summarizes the statuses that the HTTP response header might
-contain. Click the troubleshoot link for advice on how to deal with each type of
-error.</p>
-<table border=1>
- <tr>
- <th>Response</th>
- <th>Description</th>
- </tr>
- <tr>
- <td>200</td>
- <td>Message was processed successfully. The response body will contain more
-details about the message status, but its format will depend whether the request
-was JSON or plain text. See <a href="#success">Interpreting a success response</a>
-for more details.</td>
- </tr>
- <tr>
- <td>400</td>
- <td><span id="internal-source-marker_0.2">Only applies for JSON requests.
-Indicates that the request could not be parsed as JSON, or it contained invalid
-fields (for instance, passing a string where a number was expected). The exact
-failure reason is described in the response and the problem should be addressed
-before the request can be retried.</td>
- </tr>
- <tr>
- <td>401</td>
- <td>There was an error authenticating the sender account.
-<a href="#auth_error">Troubleshoot</a></td>
- </tr>
- <tr>
- <td>5xx</td>
- <td>Errors in the 500-599 range (such as 500 or 503) indicate that there was
-an internal error in the GCM server while trying to process the request, or that
-the server is temporarily unavailable (for example, because of timeouts). Sender
-must retry later, honoring any <code>Retry-After</code> header included in the
-response. Application servers must implement exponential back-off.
-<a href="#internal_error">Troubleshoot</a></td>
- </tr>
-</table>
-
<h3 id="success">Interpreting a success response</h3>
<p>When a JSON request is successful (HTTP status code 200), the response body
contains a JSON object with the following fields:</p>
@@ -241,8 +223,8 @@
request.</li>
<li>If it is <code>NotRegistered</code>, you should remove the registration
ID from your server database because the application was uninstalled from the
-device or it does not have a broadcast receiver configured to receive
-<code>com.google.android.c2dm.intent.RECEIVE</code> intents.</li>
+device, or the client app isn't configured to receive
+messages.</li>
<li>Otherwise, there is something wrong in the registration ID passed in
the request; it is probably a non-recoverable error that will also require removing
the registration from the server database. See <a href="#error_codes">Interpreting
@@ -291,8 +273,7 @@
<dt id="invalid_reg"><strong>Invalid Registration ID</strong></dt>
<dd>Check the formatting of the registration ID that you pass to the server. Make
-sure it matches the registration ID the phone receives in the
-<code>com.google.android.c2dm.intent.REGISTRATION</code> intent and that you're
+sure it matches the registration ID the client app receives and that you're
not truncating it or adding additional characters.
<br/>Happens when error code is <code>InvalidRegistration</code>.</dd>
@@ -306,17 +287,13 @@
<dt id="unreg_device"><strong>Unregistered Device</strong></dt>
<dd>An existing registration ID may cease to be valid in a number of scenarios, including:
<ul>
- <li>If the application manually unregisters by issuing a
-<span class="prettyprint pretty-java">
-<code>com.google.android.c2dm.intent.UNREGISTER</code></span><code>
-</code>intent.</li>
+ <li>If the application manually unregisters.</li>
<li>If the application is automatically unregistered, which can happen
(but is not guaranteed) if the user uninstalls the application.</li>
<li>If the registration ID expires. Google might decide to refresh registration
IDs. </li>
- <li>If the application is updated but the new version does not have a broadcast
-receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code>
-intents.</li>
+ <li>If the application is updated but the new version is not configured to receive
+messages.</li>
</ul>
For all these cases, you should remove this registration ID from the 3rd-party
server and stop using it to send
@@ -331,8 +308,7 @@
<dt id="invalid_datakey"><strong>Invalid Data Key</strong></dt>
<dd>The payload data contains a key (such as <code>from</code> or any value
-prefixed by <code>google.</code>) that is used internally by GCM in the
-<code>com.google.android.c2dm.intent.RECEIVE</code> Intent and cannot be used.
+prefixed by <code>google.</code>) that is used internally by GCM and therefore cannot be used.
Note that some words (such as <code>collapse_key</code>) are also used by GCM
but are allowed in the payload, in which case the payload value will be
overridden by the GCM value.
@@ -354,9 +330,9 @@
<li>Request originated from a server not whitelisted in the Server Key IPs.</li>
</ul>
-Check that the token you're sending inside the <code>Authorization</code> header
-is the correct API key associated with your project. You can check the validity
-of your API key by running the following command:<br/>
+When there is an Authentication Error, you can check the validity of your API key by running You can check the validity
+of your API key by running the following command (this example shows what you
+would do on Android; see the documentation for your platform):<br/>
<pre># api_key=YOUR_API_KEY
@@ -405,8 +381,7 @@
<dd>
The server encountered an error while trying to process the request. You
could retry the same request (obeying the requirements listed in the <a href="#timeout">Timeout</a>
-section), but if the error persists, please report the problem in the
-<a href="https://groups.google.com/forum/?fromgroups#!forum/android-gcm">android-gcm group</a>.
+section), but if the error persists, please report the problem to Google.
<br />
Happens when the HTTP status code is 500, or when the <code>error</code> field of a JSON
object in the results array is <code>InternalServerError</code>.
@@ -488,7 +463,7 @@
<p>This section gives examples of implementing an app server that works with the
GCM HTTP connection server. Note that a full GCM implementation requires a
-client-side implementation, in addition to the server.</a>
+client-side implementation, in addition to the server. This example is based on Android.</a>
<p>Requirements</p>
@@ -508,7 +483,7 @@
</ul>
<p>For the Android application:</p>
<ul>
- <li>Emulator (or device) running Android 2.2 with Google APIs.</li>
+ <li>Emulator (or device) running Android 2.2 (ideally, 2.3 or above) with Google APIs.</li>
<li>The Google API project number of the account registered to use GCM.</li>
</ul>
diff --git a/docs/html/google/gcm/notifications.jd b/docs/html/google/gcm/notifications.jd
index 147b69c..333d4b6 100644
--- a/docs/html/google/gcm/notifications.jd
+++ b/docs/html/google/gcm/notifications.jd
@@ -306,9 +306,3 @@
<p>In the case of failure, the response has HTTP code 503 and no JSON. When a message
fails to be delivered to one or more of the regIDs associated with a {@code notification_key},
the 3rd-party server should retry.</p>
-
-
-
-
-
-
diff --git a/docs/html/google/gcm/server-ref.jd b/docs/html/google/gcm/server-ref.jd
new file mode 100644
index 0000000..a94e727
--- /dev/null
+++ b/docs/html/google/gcm/server-ref.jd
@@ -0,0 +1,763 @@
+page.title=Server Reference
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+
+<ol class="toc">
+ <li><a href="#downstream">Downstream Messages</a></li>
+<ol class="toc">
+ <li><a href="#send-downstream">Sending a downstream message</a></li>
+ <li><a href="#interpret-downstream">Interpreting a downstream message response</a></li>
+ </ol>
+ <li><a href="#upstream">Upstream Messages (XMPP)</a>
+ <ol class="toc">
+ <li><a href="#interpret-upstream">Interpreting an upstream XMPP message</a></li>
+ <li><a href="#upstream-response">Sending an upstream XMPP message response</a></li>
+ </ol>
+ </li>
+<li><a href="#ccs">Cloud Connection Server Messages (XMPP)</a></li>
+<li><a href="#error-codes">Downstream message error response codes (HTTP and XMPP)</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>This document provides a reference for the syntax used to pass
+messages back and forth in GCM. These messages fall into
+the following broad categories:</p>
+
+<ul>
+ <li><a href="#downstream">Downstream messages</a></li>
+ <li><a href="#upstream">Upstream messages</a></li>
+ <li><a href="#ccs">Cloud Connection Server messages (XMPP)</a></li>
+ <li><a href="#error-codes">Downstream message error response codes (HTTP and XMPP)</a></li>
+</ul>
+
+<p>The following sections describe the basic requirements for
+sending messages.</p>
+
+<h2 id="downstream">Downstream Messages</h2>
+<p>This is the message that a 3rd-party app server sends to a client app.
+</p>
+<p>A downstream message includes the following components:</p>
+<ul>
+ <li>Target: specifies the recipient of the message.</li>
+ <li>Options: specifies attributes of the message.</li>
+ <li>Payload: specifies additional content to be included in the message. Optional.</li>
+</ul>
+
+<p>The syntax for each of these components is described in the tables below. </p>
+
+<h3 id="send-downstream">Sending a downstream message</h3>
+
+<p>This section gives the syntax for sending a downstream messages. For JSON,
+these messages can be either HTTP or XMPP. For plain text, these messages can only be HTTP.</p>
+
+<h4>Downstream HTTP or XMPP messages (JSON)</h4>
+
+<p>The following table lists the targets, options, and payload for HTTP or XMPP JSON messages.</p>
+<p class="table-caption" id="table1">
+ <strong>Table 1.</strong> Targets, options, and payload for downstream HTTP or XMPP message (JSON).</p>
+<table border="1">
+ <tr>
+ <th>Parameter</th>
+ <th>Protocol</th>
+ <th>Usage</th>
+ <th>Description</th>
+ </tr>
+<tr>
+ <td colspan="4"><strong>Targets</strong></td>
+ </tr>
+ <tr>
+ <td><code>to</code></td>
+ <td>XMPP</td>
+ <td>Required, string</td>
+ <td><p>This parameter specifies the recipient of a message. </p>
+ <p>The value must be a registration ID or notification key.</p>
+ <p>This parameter is used in XMPP in place of {@code registration_ids} or {@code notification_key} in HTTP.</p></td>
+ </tr>
+ <tr>
+ <td><code>registration_ids</code></td>
+ <td>HTTP</td>
+ <td>Required if {@code notification_key} not present, string array</td>
+ <td><p>This parameter specifies the list of devices (registration IDs)
+receiving the message. It must contain at least 1 and at most 1000 registration IDs.</p>
+ <p>Multicast messages (sending to more than 1 registration IDs) are allowed using HTTP JSON format only.</p>
+ <p>This parameter or {@code notification_key} is used in HTTP in place of {@code to} in XMPP.</p></td>
+ </tr>
+ <tr>
+ <td><code>notification_key</code></td>
+ <td>HTTP</td>
+ <td>Required if {@code registration_ids} not present, string</td>
+ <td><p>This parameter specifies the mapping of a single user to
+multiple registration IDs associated with that user.</p>
+ <p>This allows a 3rd-party app server to send a single message to multiple app instances
+(typically on multiple devices) owned by a single user.</p>
+ <p>A 3rd-party app server can use {@code notification_key} as the target for a
+message instead of an individual registration ID (or array of registration IDs).
+The maximum number of members allowed for a {@code notification_key} is 20.</p>
+ <p>This parameter or {@code registration_ids} is used in HTTP in place of {@code to} in XMPP.</p>
+ <p>See <a href="notifications.html">User Notifications</a> for details.</p></td>
+ </tr>
+<tr>
+ <td colspan="4"><strong>Options</strong></td>
+ </tr>
+ <tr>
+ <td><code>message_id</code></td>
+ <td>XMPP</td>
+ <td>Required, string</td>
+ <td><p>This parameter uniquely identifies a message in an XMPP connection.</p></td>
+ </tr>
+ <tr>
+ <td><code>collapse_key</code></td>
+ <td>HTTP, XMPP</td>
+ <td>Optional, string</td>
+ <td><p>This parameters identifies a group of messages (e.g., with
+{@code collapse_key: "Updates Available"}) that can be collapsed, so that only the
+last message gets sent when delivery can be resumed. This is intended to avoid sending too
+many of the same messages when the device comes back online or becomes active (see {@code delay_while_idle}).</p>
+ <p>Note that there is no guarantee of the order in which messages get sent.</p>
+ <p>Messages with collapse key are also called
+<a href="{@docRoot}google/gcm/server.html#s2s">send-to-sync messages</a> messages.
+</p>
+ <p>Note: A maximum of 4 different collapse keys is allowed at any given time. This means a
+GCM connection server can simultaneously store 4 different send-to-sync messages per client app. If you
+exceed this number, there is no guarantee which 4 collapse keys the GCM connection server will keep. </p></td>
+ </tr>
+ <tr>
+ <td><code>delay_while_idle</code></td>
+ <td>HTTP, XMPP</td>
+ <td>Optional, JSON boolean</td>
+ <td>When this parameter is set to {@code true}, it indicates that the message should not be
+sent until the device becomes active.</p>
+ <p>The default value is {@code false}.</p></td>
+ </tr>
+ <tr>
+ <td><code>time_to_live</code></td>
+ <td>HTTP, XMPP</td>
+ <td>Optional, JSON number</td>
+ <td><p>This parameter specifies how long (in seconds) the message should be kept in GCM storage
+if the device is offline. The maximum time to live supported is 4 weeks.</p>
+ <p>The default value is 4 weeks. </p></td>
+ </tr>
+ <tr>
+ <td><code>delivery_receipt_
+<br>requested</code></td>
+ <td>XMPP</td>
+ <td>Optional, JSON boolean</td>
+ <td><p>This parameter lets 3rd-party app server request confirmation of message delivery.</p>
+ <p>When this parameter is set to {@code true}, CCS sends a delivery receipt
+when the device confirms that it received the message.</p>
+ <p>The default value is {@code false}.</p></td>
+ </tr>
+ <tr>
+ <td><code>restricted_package_
+<br>name</code></td>
+ <td>HTTP</td>
+ <td>Optional, string</td>
+ <td>This parameter specifies the package name of the application where the
+registration IDs must match in order to receive the message.</td>
+ </tr>
+ <tr>
+ <td><code>dry_run</code></td>
+ <td>HTTP</td>
+ <td>Optional, JSON boolean</td>
+ <td><p>This parameter, when set to {@code true}, allows developers to test a
+request without actually sending a message.</p>
+ <p>The default value is {@code false}.</p></td>
+ </tr>
+<tr>
+ <td colspan="4"><strong>Payload</strong></td>
+ </tr>
+ <tr>
+ <td><code>data</code></td>
+ <td>HTTP, XMPP</td>
+ <td>Optional, JSON object</td>
+ <td><p>This parameter specifies the key-value pairs of the message's payload. There is
+no limit on the number of key-value pairs, but there is a total message size limit of 4kb.</p>
+ <p>For instance, in Android, <code>data:{"score":"3x1"}</code> would result in an intent extra
+named {@code score} with the string value {@code 3x1}.</p>
+ <p>The key should not be a reserved word ({@code from} or any word starting with
+{@code google}). It is also not recommended to use words defined in this table
+(such as {@code collapse_key}) because that could yield unpredictable outcomes. </p>
+ <p>Values in string types are recommended. You have to convert values in objects
+or other non-string data types (e.g., integers or booleans) to string.</p></td>
+ </tr>
+</table>
+
+<h3>Downstream HTTP messages (Plain Text)</h3>
+
+<p>The following table lists the syntax for targets, options, and payload in plain
+text downstream HTTP messages.</p>
+
+<p class="table-caption" id="table2">
+ <strong>Table 2.</strong> Targets, options, and payload for downstream plain text HTTP messages.</p>
+
+<table border="1">
+ <tr>
+ <th>Parameter</th>
+ <th>Usage</th>
+ <th>Description</th>
+ </tr>
+<tr>
+ <td colspan="3"><strong>Targets</strong></td>
+ </tr>
+ <tr>
+ <td><code>registration _id</code></td>
+ <td>Required, string</td>
+ <td><p>This parameter specifies the client apps (registration ID) receiving the message.</p>
+ <p>Multicast messaging (sending to more than one registration ID) is allowed using HTTP JSON format only.</p></td>
+ </tr>
+<tr>
+ <td colspan="3"><strong>Options</strong></td>
+ </tr>
+ <tr>
+ <td><code>collapse_key</code></td>
+ <td>Optional, string</td>
+ <td>See <a href="#table1">table 1</a> for details.</td>
+ </tr>
+ <tr>
+ <td><code>delay_while_idle</code></td>
+ <td>Optional, boolean or number</td>
+ <td>See <a href="#table1">table 1</a> for details.</td>
+ </tr>
+ <tr>
+ <td><code>time_to_live</code></td>
+ <td>Optional, number</td>
+ <td>See <a href="#table1">table 1</a> for details.</td>
+ </tr>
+ <tr>
+ <td><code>restricted_package_name</code></td>
+ <td>Optional, string</td>
+ <td>See <a href="#table1">table 1</a> for details.</td>
+ </tr>
+ <tr>
+ <td><code>dry_run </code></td>
+ <td>Optional, boolean</td>
+ <td>See <a href="#table1">table 1</a> for details.</td>
+ </tr>
+<tr>
+ <td colspan="3"><strong>Payload</strong></td>
+ </tr>
+ <tr>
+ <td><code>data.<key></code></td>
+ <td>Optional, string</td>
+ <td><p>This parameter specifies the key-value pairs of the message's payload.
+There is no limit on the number of key-value parameters,
+but there is a total message size limit of 4kb.</p>
+ <p>For instance, in Android, <code>data:{"score":"3x1"}</code> would result in an intent extra
+named {@code score} with the string value {@code 3x1}.</p>
+ <p>The key should not be a reserved word ({@code from} or any word starting with
+{@code google}). It is also not recommended to use words defined in this table
+(such as {@code collapse_key}) because that could yield unpredictable outcomes.</p></td>
+ </tr>
+</table>
+
+<h3 id="interpret-downstream">Interpreting a Downstream Message Response</h3>
+
+<p>This section describes the syntax of a response to a downstream message. A client
+app or the GCM Connection Server sends the response to 3rd-party app server upon processing
+the message request. </p>
+
+<h4>Interpreting a downstream HTTP message response </h4>
+<p>The 3rd-party app server should look at both the message response header and the body
+to interpret the message response sent from the GCM Connection Server. The following table
+describes the possible responses.</p>
+<p>
+
+<p class="table-caption" id="table3">
+ <strong>Table 3.</strong> Downstream HTTP message response header.</p>
+<table border=1>
+ <tr>
+ <th>Response</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>200</td>
+ <td>Message was processed successfully. The response body will contain more
+details about the message status, but its format will depend whether the request
+was JSON or plain text. See <a href="#table4">table 4</a>
+for more details.</td>
+ </tr>
+ <tr>
+ <td>400</td>
+ <td>Only applies for JSON requests.
+Indicates that the request could not be parsed as JSON, or it contained invalid
+fields (for instance, passing a string where a number was expected). The exact
+failure reason is described in the response and the problem should be addressed
+before the request can be retried.</td>
+ </tr>
+ <tr>
+ <td>401</td>
+ <td>There was an error authenticating the sender account.
+<a href="server.html#auth_error">Troubleshoot</a></td>
+ </tr>
+ <tr>
+ <td>5xx</td>
+ <td>Errors in the 500-599 range (such as 500 or 503) indicate that there was
+an internal error in the GCM server while trying to process the request, or that
+the server is temporarily unavailable (for example, because of timeouts). Sender
+must retry later, honoring any <code>Retry-After</code> header included in the
+response. Application servers must implement exponential back-off.
+<a href="server.html#internal_error">Troubleshoot</a></td>
+ </tr>
+</table>
+
+<p>The following table lists the fields in a downstream message response body
+(JSON).</p>
+
+
+<p class="table-caption" id="table4">
+ <strong>Table 4.</strong> Downstream HTTP message response body (JSON).</p>
+<table>
+ <tr>
+ <th>Parameter</th>
+ <th>Usage</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>multicast_id</code></td>
+ <td>Required, number</td>
+ <td>Unique ID (number) identifying the multicast message.</td>
+ </tr>
+ <tr>
+ <td><code>success</code></td>
+ <td>Required, number</td>
+ <td>Number of messages that were processed without an error.</td>
+ </tr>
+ <tr>
+ <td><code>failure</code></td>
+ <td>Required, number</td>
+ <td>Number of messages that could not be processed.</td>
+ </tr>
+ <tr>
+ <td><code>canonical_ids</code></td>
+ <td>Required, number</td>
+ <td>Number of results that contain a canonical registration ID. See the
+<a href="{@docRoot}google/gcm/gcm.html#canonical">Overview</a> for more discussion of this topic.</td>
+ </tr>
+ <tr>
+ <td><code>results</code></td>
+ <td>Optional, array object</td>
+ <td>Array of objects representing the status of the messages processed. The
+objects are listed in the same order as the request (i.e., for each registration
+ID in the request, its result is listed in the same index in the response).<br>
+ <ul>
+ <li><code>message_id</code>: String specifying a unique ID for each successfully processed
+ message.</li>
+ <li><code>registration_id</code>: Optional string specifying the canonical registration ID
+ for the client app that the message was processed and sent to. Sender should use this
+ value as the Registration ID for future requests. Otherwise, the messages might
+ be rejected.
+ </li>
+ <li><code>error</code>: String specifying the error that occurred when processing the
+ message for the recipient. The possible values can be found in <a href="#table11">table 11
+ </a>.</li>
+ </ul></td>
+ </tr>
+</table>
+
+
+<p class="table-caption" id="table5">
+ <strong>Table 5.</strong> Success response for downstream HTTP message response body (Plain Text).</p>
+<table border="1">
+ <tr>
+ <th>Parameter</th>
+ <th>Usage</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>id</code></td>
+ <td>Required, string</td>
+ <td>This parameter specifies the unique message ID that GCM server processed successfully.</td>
+ </tr>
+ <tr>
+ <td><code>registration_id</code></td>
+ <td>Optional, string</td>
+ <td>This parameter specifies the canonical registration ID for the client app that the message was
+processed and sent to. Sender should replace the registration ID with this value on future requests,
+otherwise, the messages might be rejected.</td>
+ </tr>
+</table>
+
+<p class="table-caption" id="table6">
+ <strong>Table 6.</strong> Error response for downstream HTTP message response body (Plain Text).</p>
+<table border="1">
+ <tr>
+ <th>Parameter</th>
+ <th>Usage</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>{@code Error}</td>
+ <td>Required, string</td>
+ <td>This parameter specifies the error value while processing the message for the recipient.
+See <a href="#table11">table 11</a> for details. </td>
+ </tr>
+</table>
+
+<h4>Interpreting a downstream XMPP message response</h4>
+
+<p>The following table lists the fields that appear in a downstream XMPP message response.</p>
+
+<p class="table-caption" id="table7">
+ <strong>Table 7.</strong> Downstream message XMPP message response body.</p>
+<table border="1">
+ <tr>
+ <th>Parameter</th>
+ <th>Usage</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>from</code></td>
+ <td>Required, string</td>
+ <td><p>This parameter specifies who sent this response.</p>
+ <p>The value is the registration ID of the client app.</p></td>
+ </tr>
+ <tr>
+ <td><code>message_id</code></td>
+ <td>Required, string</td>
+ <td>This parameter uniquely identifies a message in an XMPP connection.
+The value is a string that uniquely identifies the associated message.</td>
+ </tr>
+ <tr>
+ <td><code>message_type</code></td>
+ <td>Required, string</td>
+ <td><p>This parameter specifies an 'ack' or 'nack' message from XMPP (CCS)
+to the 3rd-party app server.</p>
+ <p>If the value is set to {@code nack}, the 3rd-party app server should look at
+{@code error} and {@code error_description} to get failure information. </p></td>
+ </tr>
+ <tr>
+ <td><code>error</code></td>
+ <td>Optional, string</td>
+ <td>This parameter specifies an error related to the downstream message. It is set when the
+{@code message_type} is {@code nack}. See <a href="#table11">table 6</a> for details.</td>
+ </tr>
+ <tr>
+ <td><code>error_description</code></td>
+ <td>Optional, string</td>
+ <td>This parameter provides descriptive information for the error. It is set
+when the {@code message_type} is {@code nack}.</td>
+ </tr>
+</table>
+<h2 id="upstream">Upstream Messages (XMPP)</h2>
+
+<p>An upstream message is a message the client app sends to the 3rd-party app server.
+Currently only CCS (XMPP) supports upstream messaging.</p>
+
+<h3 id="interpret-upstream">Interpreting an upstream XMPP message </h3>
+<p>The following table describes the fields that appear in an upstream XMPP message.
+
+<p class="table-caption" id="table8">
+ <strong>Table 8.</strong> Upstream XMPP messages.</p>
+<table border="1">
+ <tr>
+ <th>Parameter</th>
+ <th>Usage</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>from</code></td>
+ <td>Required, string</td>
+ <td><p>This parameter specifies who sent the message.</p>
+ <p>The value is the registration ID of the client app.</p></td>
+ </tr>
+ <tr>
+ <td><code>category</code></td>
+ <td>Required, string</td>
+ <td>This parameter specifies the application package name of the client app that sent the message. </td>
+ </tr>
+ <tr>
+ <td><code>message_id</code></td>
+ <td>Required, string</td>
+ <td>This parameter specifies the unique ID of the message. </td>
+ </tr>
+ <tr>
+ <td><code>data</code></td>
+ <td>Optional, string</td>
+ <td>This parameter specifies the key-value pairs of the message's payload.</td>
+ </tr>
+</table>
+
+<h3 id="upstream-response">Sending an upstream XMPP message response</h3>
+
+<p>The following table describes the response that 3rd-party app server is expected to send to
+<a href="{@docRoot}google/gcm/ccs.html">XMPP (CCS)</a> in response to an
+upstream message it (the app server) received.</p>
+
+<p class="table-caption" id="table9">
+ <strong>Table 9.</strong> Upstream XMPP message response.</p>
+<table border="1">
+ <tr>
+ <th>Parameter</th>
+ <th>Usage</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>to</code></td>
+ <td>Required, string</td>
+ <td><p>This parameter specifies the recipient of a response message. </p>
+ <p>The value must be a registration ID of the client app that sent the upstream message.</p></td>
+ </tr>
+ <tr>
+ <td><code>message_id</code></td>
+ <td>Required, string</td>
+ <td>This parameter specifies which message the response is intended for. The value must be
+the {@code message_id} value from the corresponding upstream message.</td>
+ </tr>
+ <tr>
+ <td><code>message_type</code></td>
+ <td>Required, string</td>
+ <td>This parameter specifies an {@code ack} message from a 3rd-party app server to CCS.</td>
+ </tr>
+</table>
+<h2 id="ccs">Cloud Connection Server Messages (XMPP) </h2>
+<p>This is a message sent from XMPP (CCS) to a 3rd-party app server. Here are the primary types
+of messages that XMPP (CCS) sends to the 3rd-party app server:</p>
+<ul>
+ <li><strong>Delivery Receipt:</strong> If the 3rd-party app server included {@code delivery_receipt_requested}
+in the downstream message, XMPP (CCS) sends a delivery receipt when it receives confirmation
+that the device received the message.</li>
+ <li><strong>Control:</strong> These CCS-generated messages indicate that
+action is required from the 3rd-party app server.</li>
+</ul>
+
+<p>The following table describes the fields included in the messages CCS
+sends to a 3rd-party app server.</p>
+
+<p class="table-caption" id="table10">
+ <strong>Table 10.</strong> GCM Cloud Connection Server messages (XMPP).</p>
+<table border="1">
+ <tr>
+ <th>Parameter</th>
+ <th>Usage</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td colspan="3"><strong>Common Field</strong></td>
+ </tr>
+ <tr>
+ <td><code>message_type</code></td>
+ <td>Required, string</td>
+ <td><p>This parameter specifies the type of the CCS message: either delivery receipt or control.</p>
+ <p>When it is set to {@code receipt}, the message includes {@code from}, {@code message_id},
+ {@code category} and {@code data} fields to provide additional information.</p>
+ <p>When it is set to {@code control}, the message includes {@code control_type} to indicate the
+type of control message.</p></td>
+ </tr>
+ <tr>
+ <td colspan="3"><strong>Delivery receipt-specific</strong></td>
+ </tr>
+ <tr>
+ <td><code>from</code></td>
+ <td>Required, string</td>
+ <td>This parameter is set to {@code gcm.googleapis.com}, indicating that the
+message is sent from CCS.</td>
+ </tr>
+ <tr>
+ <td><code>message_id</code></td>
+ <td>Required, string</td>
+ <td>This parameter specifies the original message ID that the receipt is intended for,
+prefixed with {@code dr2:} to indicate that the message is a delivery receipt. A 3rd-party app
+server must send an {@code ack} message with this message ID to acknowledge that it
+received this delivery receipt. See <a href="#table9">table 9</a> for the 'ack' message format.</td>
+ </tr>
+ <tr>
+ <td><code>category</code></td>
+ <td>Optional, string</td>
+ <td>This parameter specifies the application package name of the client app that
+receives the message that this delivery receipt is reporting. This is available when
+{@code message_type} is {@code receipt}.</td>
+ </tr>
+ <tr>
+ <td><code>data</code></td>
+ <td>Optional, string</td>
+ <td>This parameter specifies the key-value pairs for the delivery receipt message. This is available
+when the {@code message_type} is {@code receipt}.
+ <ul>
+ <li>{@code message_status}: This parameter specifies the status of the receipt message.
+It is set to {@code MESSAGE_SENT_TO_DEVICE} to indicate the device has confirmed its receipt of
+the original message.</li>
+ <li>{@code original_message_id}: This parameter specifies the ID of the original message
+that the 3rd-party app server sent to the client app.</li>
+ <li>{@code device_registration_id}: This parameter specifies the registration ID of the
+client app to which the original message was sent.</li>
+ </ul>
+</td>
+ </tr>
+ <tr>
+ <td colspan="3"><strong>Control-specific</strong></td>
+ </tr>
+ <tr>
+ <td><code>control_type</code></td>
+ <td>Optional, string</td>
+ <td><p>This parameter specifies the type of control message sent from CCS.</p>
+ <p>Currently, only {@code CONNECTION_DRAINING} is supported. XMPP (CCS) sends this control message
+before it closes a connection to perform load balancing. As the connection drains, no more messages
+are allowed to be sent to the connection, but existing messages in the pipeline will
+continue to be processed.</p></td>
+ </tr>
+</table>
+
+<h2 id="error-codes">Downstream message error response codes (HTTP and XMPP)</h2>
+
+<p>The following table lists the error response codes for downstream messages (HTTP and XMPP).</p>
+
+<p class="table-caption" id="table11">
+ <strong>Table 11.</strong> Downstream message error response codes.</p>
+<table border="1">
+ <tr>
+ <th>Error</th>
+ <th>HTTP Code</th>
+ <th>XMPP Code</th>
+ <th>Recommended Action</th>
+ </tr>
+ <tr>
+ <td>Missing Registration ID</td>
+ <td>200 + error:MissingRegistration</td>
+ <td><code>INVALID_JSON</code></td>
+ <td>Check that the request contains a registration ID (either in the
+{@code registration_id} in a plain text message, or in the {@code registration_ids} in JSON).</td>
+ </tr>
+ <tr>
+ <td>Invalid Registration ID</td>
+ <td>200 + error:InvalidRegistration</td>
+ <td><code>BAD_REGISTRATION</code></td>
+ <td>Check the format of the registration ID you pass to the server. Make sure it
+matches the registration ID the client app receives from registering with GCM. Do not
+truncate or add additional characters.</td>
+ </tr>
+ <tr>
+ <td>Unregistered Device</td>
+ <td>200 + error:NotRegistered</td>
+ <td><code>DEVICE_UNREGISTERED</code></td>
+ <td>An existing registration ID may cease to be valid in a number of scenarios, including:<br>
+ <ul>
+ <li>If the client app unregisters with GCM.</li>
+ <li>If the client app is automatically unregistered, which can happen if the user uninstalls the application.</li>
+ <li>If the registration ID expires (for example, Google might decide to refresh registration IDs).</li>
+ <li>If the client app is updated but the new version is not configured to receive messages.</li>
+</ul>
+ For all these cases, remove this registration ID from the 3rd-party app
+server and stop using it to send messages.</td>
+ </tr>
+ <tr>
+ <td>Invalid Package Name</td>
+ <td>200 + error:InvalidPackageName</td>
+ <td></td>
+ <td>Make sure the message was addressed to a registration ID whose package name
+matches the value passed in the request.</td>
+ </tr>
+ <tr>
+ <td>Authentication Error</td>
+ <td>401</td>
+ <td> </td>
+ <td>The sender account used to send a message couldn't be authenticated. Possible causes are:<br>
+<ul>
+ <li>Authorization header missing or with invalid syntax in HTTP request.</li>
+ <li>Invalid project number sent as key.</li>
+ <li>Key valid but with GCM service disabled.</li>
+ <li>Request originated from a server not whitelisted in the Server Key IPs.</li>
+</ul>
+ Check that the token you're sending inside the Authentication header is
+the correct API key associated with your project. See
+<a href="{@docRoot}google/gcm/http.html">GCM HTTP Connection Server</a> for details.</td>
+ </tr>
+ <tr>
+ <td>Mismatched Sender</td>
+ <td>200 + error:MismatchSenderId</td>
+ <td><code>BAD_REGISTRATION</code></td>
+ <td>A registration ID is tied to a certain group of senders. When a client app registers
+for GCM, it must specify which senders are allowed to send messages. You should use one
+of those sender IDs when sending messages to the client app. If you switch to a different
+sender, the existing registration IDs won't work.</td>
+ </tr>
+ <tr>
+ <td>Invalid JSON</td>
+ <td>400</td>
+ <td><code>INVALID_JSON</code></td>
+ <td>Check that the JSON message is properly formatted and contains valid fields
+(for instance, making sure the right data type is passed in).</td>
+ </tr>
+ <tr>
+ <td>Message Too Big</td>
+ <td>200 + error:MessageTooBig</td>
+ <td><code>INVALID_JSON</code></td>
+ <td>Check that the total size of the payload data included in a message does
+not exceed 4096 bytes. This includes both the the keys and the values.</td>
+ </tr>
+ <tr>
+ <td>Invalid Data Key</td>
+ <td>200 + error:
+<br />
+InvalidDataKey</td>
+ <td><code>INVALID_JSON</code></td>
+ <td>Check that the payload data does not contain a key (such as {@code from} or any value
+prefixed by {@code google}) that is used internally by GCM. Note that some words (such as {@code collapse_key})
+are also used by GCM but are allowed in the payload, in which case the payload value
+will be overridden by the GCM value.</td>
+ </tr>
+ <tr>
+ <td>Invalid Time to Live</td>
+ <td>200 + error:InvalidTtl</td>
+ <td><code>INVALID_JSON</code></td>
+ <td>Check that the value used in {@code time_to_live} is an integer representing a
+duration in seconds between 0 and 2,419,200 (4 weeks).</td>
+ </tr>
+ <tr>
+ <td>Bad ACK message</td>
+ <td>N/A</td>
+ <td><code>BAD_ACK</code></td>
+ <td>Check that the 'ack' message is properly formatted before retrying. See
+<a href="#table9">table 9</a> for details.</td>
+ </tr>
+ <tr>
+ <td>Timeout</td>
+ <td>5xx or 200 + error:Unavailable</td>
+ <td><code>SERVICE_UNAVAILABLE</code></td>
+ <td><p>The server couldn't process the request in time. Retry the same request, but you must:<br>
+<ul>
+ <li>For HTTP: Honor the {@code Retry-After} header if it is included in the response from the
+GCM Connection Server.</li>
+ <li>Implement exponential back-off in your retry mechanism. (e.g. if you waited one second
+before the first retry, wait at least two second before the next one, then 4 seconds and so on).
+If you're sending multiple messages, delay each one independently by an additional random amount
+to avoid issuing a new request for all messages at the same time.</li>
+ <li>For CCS: The initial retry delay should be set to 1 second.</li>
+</ul>
+ <p>Senders that cause problems risk being blacklisted.</p></td>
+ </tr>
+ <tr>
+ <td>Internal Server Error</td>
+ <td>500 or 200 + error:InternalServerError</td>
+ <td><code>INTERNAL_SERVER_
+<br />
+ERROR</code></td>
+ <td>The server encountered an error while trying to process the request. You could retry
+the same request following the requirements listed in "Timeout" (see row above). If the error persists, please
+report the problem in the {@code android-gcm group}.</td>
+ </tr>
+ <tr>
+ <td>Device Message Rate Exceeded</td>
+ <td>200 + error:
+<br />DeviceMessageRate
+<br />
+Exceeded</td>
+ <td><code>DEVICE_MESSAGE_RATE<br />
+_EXCEEDED</code></td>
+ <td>The rate of messages to a particular device is too high. Reduce the
+number of messages sent to this device and do not immediately retry sending to this device.</td>
+ </tr>
+ <tr>
+ <td>Connection Draining</td>
+ <td>N/A</td>
+ <td><code>CONNECTION_DRAINING</code></td>
+ <td>The message couldn't be processed because the connection is draining. This happens because
+periodically, XMPP (CCS) needs to close down a connection to perform load balancing. Retry the message over
+another XMPP connection.</td>
+ </tr>
+</table>
diff --git a/docs/html/google/gcm/server.jd b/docs/html/google/gcm/server.jd
index 20e2b2e..004fd0e 100644
--- a/docs/html/google/gcm/server.jd
+++ b/docs/html/google/gcm/server.jd
@@ -7,9 +7,9 @@
<h2>In this document</h2>
<ol class="toc">
- <li><a href="#choose">Choosing a GCM Connection Server</a></li>
<li><a href="#role">Role of the 3rd-party Application Server</a></li>
- <li><a href="#send-msg">Sending Messages</a>
+ <li><a href="#choose">Choosing a GCM Connection Server</a></li>
+ <li><a href="#send-msg">Sending Messages</a>
<ol class="toc">
<li><a href="#target">Target</a></li>
@@ -17,7 +17,18 @@
<li><a href="#params">Message parameters</a>
</ol>
</li>
- <li><a href="#receive">Receiving Messages</a> </li>
+ <li><a href="#adv">Messaging Concepts and Best Practices</a>
+
+ <ol class="toc">
+
+ <li><a href="#collapsible">Send-to-Sync vs. Messages with Payload</a></li>
+ <li><a href="#ttl">Setting an Expiration Date for a Message</a></li>
+ <li><a href="#multi-senders">Receiving Messages from Multiple Senders</a>
+ <li><a href="#lifetime">Lifetime of a Message</a>
+ <li><a href="#throttling">Throttling</a>
+ </ol>
+
+</li>
</li>
</ol>
@@ -25,6 +36,7 @@
<h2>See Also</h2>
<ol class="toc">
+<li><a href="server-ref.html">Server Reference</a></li>
<li><a href="gs.html">Getting Started</a></li>
<li><a href="client.html">Implementing GCM Client</a></li>
<li><a href="ccs.html">Cloud Connection Server (XMPP)</a></li>
@@ -37,79 +49,28 @@
</div>
-<p>The server side of Google Cloud Messaging (GCM) consists of 2 components:</p>
+<p>The server side of Google Cloud Messaging (GCM) consists of two components:</p>
<ul>
<li>Google-provided <strong>GCM Connection Servers</strong>
-take messages from a 3rd-party application server and send them to a GCM-enabled
-Android application (the "client app") running on a device. For example,
+take messages from a <a href="{@docRoot}google/gcm/server.html#role">3rd-party app server</a>
+and send them to a GCM-enabled
+application (the "client app") running on a device. For example,
Google provides connection servers for <a href="{@docRoot}google/gcm/http.html">
-HTTP</a> and <a href="{@docRoot}google/gcm/ccs.html">CCS</a> (XMPP).</li>
+HTTP</a> and <a href="{@docRoot}google/gcm/ccs.html">XMPP (CCS)</a> (XMPP).</li>
<li>A <strong>3rd-party application server</strong> that you must implement. This application
-server sends data to a GCM-enabled Android application via the chosen GCM connection server.</li>
+server sends data to a GCM-enabled client app via the chosen GCM connection server.</li>
</ul>
</p>
-<p>Here are the basic steps you follow to implement your 3rd-party app server:</p>
-
-<ul>
- <li>Decide which GCM connection server(s) you want to use. Note that if you want to use
- upstream messaging from your client applications, you must use CCS. For a more detailed
- discussion of this, see <a href="#choose">
- Choosing a GCM Connection Server</a>.</li>
- <li>Decide how you want to implement your app server. For example:
- <ul>
- <li>If you decide to use the HTTP connection server, you can use the
-GCM server helper library and demo app to help in implementing your app server.</li>
- <li>If you decide to use the XMPP connection server, you can use
-the provided Python or Java <a href="http://www.igniterealtime.org/projects/smack/">
-Smack</a> demo apps as a starting point.</li>
- <li>Note that Google AppEngine does not support connections to CCS.</li>
- </ul>
- </li>
- </ul>
- </li>
-</ul>
-
<p>A full GCM implementation requires both a client implementation and a server
implementation. For more
information about implementing the client side, see <a href="client.html">
Implementing GCM Client</a>.</p>
-<h2 id="choose">Choosing a GCM Connection Server</h2>
-
-<p>Currently GCM provides two connection servers: <a href="{@docRoot}google/gcm/http.html">
-HTTP</a> and <a href="{@docRoot}google/gcm/ccs.html">CCS</a> (XMPP). You can use them
-separately or in tandem. CCS messaging differs from GCM HTTP messaging in the following ways:</p>
-<ul>
- <li>Upstream/Downstream messages
- <ul>
- <li>GCM HTTP: Downstream only: cloud-to-device. </li>
- <li>CCS: Upstream and downstream (device-to-cloud, cloud-to-device). </li>
- </ul>
- </li>
- <li>Asynchronous messaging
- <ul>
- <li>GCM HTTP: 3rd-party app servers send messages as HTTP POST requests and
-wait for a response. This mechanism is synchronous and causes the sender to block
-before sending another message.</li>
- <li>CCS: 3rd-party app servers connect to Google infrastructure using a
-persistent XMPP connection and send/receive messages to/from all their devices
-at full line speed. CCS sends acknowledgment or failure notifications (in the
-form of special ACK and NACK JSON-encoded XMPP messages) asynchronously.</li>
- </ul>
- </li>
-
- <li>JSON
- <ul>
- <li>GCM HTTP: JSON messages sent as HTTP POST.</li>
- <li>CCS: JSON messages encapsulated in XMPP messages.</li>
- </ul>
- </li>
-</ul>
<h2 id="role">Role of the 3rd-party Application Server</h2>
-<p>Before you can write client Android applications that use the GCM feature, you must
+<p>Before you can write client apps that use the GCM feature, you must
have an application server that meets the following criteria:</p>
<ul>
@@ -117,308 +78,363 @@
<li>Able to fire off properly formatted requests to the GCM server.</li>
<li>Able to handle requests and resend them as needed, using
<a href="http://en.wikipedia.org/wiki/Exponential_backoff">exponential back-off.</a></li>
- <li>Able to store the API key and client registration IDs. The
-API key is included in the header of POST requests that send
-messages.</li>
+ <li>Able to store the API key and client registration IDs. In HTTP, the API key is
+included in the header of POST requests that send messages. In XMPP, the API key is
+used in the SASL PLAIN authentication request as a password to authenticate the connection.</li>
<li>Able to generate message IDs to uniquely identify each message it sends. Message IDs
should be unique per sender ID.</li>
</ul>
+<p>Here are the basic steps you follow to implement your 3rd-party app server:</p>
+
+<ul>
+ <li>Decide which GCM connection server(s) you want to use. Note that if you want to use
+ upstream messaging from your client applications, you must use XMPP (CCS). For a more detailed
+ discussion of this, see <a href="#choose">
+ Choosing a GCM Connection Server</a>.</li>
+ <li>Decide how you want to implement your app server. We provide helper libraries and code
+samples to assist you with your 3rd-party app server implementation. For example:
+ <ul>
+ <li>If you decide to use the HTTP connection server, you can use the
+GCM server helper library and demo app to help in implementing your app server.</li>
+ <li>If you decide to use the XMPP connection server, you can use
+the provided Python or Java <a href="http://www.igniterealtime.org/projects/smack/">
+Smack</a> demo apps as a starting point.</li>
+ <li>Note that Google AppEngine does not support connections to XMPP (CCS).</li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+
+
+<h2 id="choose">Choosing a GCM Connection Server</h2>
+
+<p>Currently GCM provides two connection servers: <a href="{@docRoot}google/gcm/http.html">
+HTTP</a> and <a href="{@docRoot}google/gcm/ccs.html">XMPP (CCS)</a>. You can use them
+separately or in tandem. XMPP (CCS) messaging differs from HTTP messaging in the following ways:</p>
+<ul>
+ <li>Upstream/Downstream messages
+ <ul>
+ <li>HTTP: Downstream only, cloud-to-device up to 4KB of data. </li>
+ <li>XMPP (CCS): Upstream and downstream (device-to-cloud, cloud-to-device),
+ up to 4 KB of data. </li>
+ </ul>
+ </li>
+ <li>Messaging (synchronous or asynchronous)
+ <ul>
+ <li>HTTP: Synchronous. 3rd-party app servers send messages as HTTP POST requests and
+wait for a response. This mechanism is synchronous and blocks the sender from sending
+another message until the response is received.</li>
+ <li>XMPP (CCS): Asynchronous. 3rd-party app servers send/receive messages to/from all their
+devices at full line speed over persistent XMPP connections.
+XMPP (CCS) sends acknowledgment or failure notifications (in the
+form of special ACK and NACK JSON-encoded XMPP messages) asynchronously.</li>
+ </ul>
+ </li>
+
+ <li>JSON
+ <ul>
+ <li>HTTP: JSON messages sent as HTTP POST.</li>
+ <li>XMPP (CCS): JSON messages encapsulated in XMPP messages.</li>
+ </ul>
+ </li>
+ <li>Plain Text
+ <ul>
+ <li>HTTP: Plain Text messages sent as HTTP POST.</li>
+ <li>XMPP (CCS): Not supported.</li>
+ </ul>
+ </li>
+ <li>Multicast downstream send to multiple registration IDs.
+ <ul>
+ <li>HTTP: Supported in JSON message format.</li>
+ <li>XMPP (CCS): Not supported.</li>
+ </ul>
+ </li>
+</ul>
+
+
<h2 id="send-msg">Sending Messages</h2>
+<p>This section gives an overview of sending messages. For details of message syntax,
+see <a href="{@docRoot}google/gcm/server-ref.html">Server Reference</a>.</p>
+
+<h3>Overview</h3>
+
<p>Here is the general sequence of events that occurs when a 3rd-party application
-server sends a message:</p>
+server sends a message (the details vary depending on the platform):</p>
<ol>
- <li>The application server sends a message to GCM servers.</li>
- <li>Google enqueues and stores the message in case the device is offline.</li>
- <li>When the device is online, Google sends the message to the device.</li>
- <li>On the device, the system broadcasts the message to the specified Android
-application via Intent broadcast with proper permissions, so that only the targeted
-Android application gets the message. This wakes the Android application up.
-The Android application does not need to be running beforehand to receive the message.</li>
- <li>The Android application processes the message. </li>
+ <li>The 3rd-party app server sends a message to GCM servers.</li>
+ <li>The GCM connection server enqueues and stores the message if the device is offline.</li>
+ <li>When the device is online, GCM connection server sends the message to the device.</li>
+ <li>The client app processes the message. </li>
</ol>
-<p>The following sections describe the basic requirements for
-sending messages.</p>
+<h3>Implement send request</h3>
-<h3 id="target">Target</h3>
+<p>The following sections describe the basic components involved in
+sending a request. See the <a href="{@docRoot}google/gcm/server-ref.html">Server Reference</a>
+for details.</p>
+
+<h4 id="target">Target</h4>
<p>Required. When your app server sends a message in GCM, it must specify a target.</p>
-<p>For HTTP you must specify the target as one of:</p>
+<p>For HTTP you must specify the target as one of the following:</p>
<ul>
<li><code>registration_ids</code>: For sending to 1 or more devices (up to 1000).
When you send a message to multiple registration IDs, that is called a multicast message.</li>
<li><code>notification_key</code>: For sending to multiple devices owned by a single user.</li>
</ul>
-<p>For CCS (XMPP):</p>
+<p>For CCS (XMPP) you must specify the target as:</p>
<ul>
-<li>You must specify the target as the "to" field, where the "to"
+<li>{@code to}: This
field may contain a single registration ID or a notification key.
-CCS does not support multicast messaging.</li>
+XMPP (CCS) does not support multicast messaging.</li>
</ul>
-<h3 id="payload">Payload</h3>
-<p>Optional. If you are including a payload in the message, you use the <code>data</code>
-parameter to include the payload. This applies for both HTTP and CCS.</p>
-<h3 id="params">Message parameters</h3>
+<h4 id="options">Options</h4>
-<p>The following table lists the parameters that a 3rd-party app server might
-include in the JSON messages it sends to a connection server. See the "Where Supported"
-column for information about which connection servers support that particular
-parameter.</p>
+<p>There are various options the 3rd-party app server can set when sending a downstream
+message to a client app. See the <a href="{@docRoot}google/gcm/server-ref.html#table1">
+Server Reference</a> for details. Here are a few examples of possible options:</p>
-<p class="table-caption" id="table1">
- <strong>Table 1.</strong> Message Parameters JSON (CCS and HTTP).</p>
-
-<table>
- <tr>
- <th>Parameter</th>
- <th>Description</th>
-<th>Where Supported</th>
-</tr>
- <td><code>to</code></td>
-<td>In CCS, this parameter is used in place of <code>registration_ids</code> to
-specify the recipient of a message. Its value must be a registration ID.
-The value is a string. Required.</td>
-<td>CCS</td>
-</tr>
-<tr>
-<td><code>message_id</code></td>
-<td>In CCS, this parameter uniquely identifies a message in an XMPP connection.
-The value is a string that uniquely identifies the associated message. Required.</td>
-<td>CCS</td>
-</tr>
-<tr>
-<td><code>message_type</code></td>
-<td>In CCS, this parameter indicates a special status message, typically sent by the system.
-However, your app server also uses this parameter to send an 'ack' or 'nack'
-message back to the CCS connection server. For more discussion of this topic, see
-<a href="ccs.html">Cloud Connection Server</a>. The value is a string. Optional.</td>
-<td>CCS</td>
-<tr>
- <td><code>registration_ids</code></td>
- <td>This parameter specifies a string array containing the list of devices
-(registration IDs) receiving the
-message. It must contain at least 1 and at most 1000 registration IDs. To send a
-multicast message, you must use JSON. For sending a single message to a single
-device, you could use a JSON object with just 1 registration id, or plain text
-(see below). A request must include a recipient—this can be either a
-registration ID, an array of registration IDs, or a {@code notification_key}.
-Required.</td>
-<td>HTTP</td>
-</tr>
- <tr>
- <td><code>notification_key</code></td>
- <td>This parameter specifies a string that maps a single user to multiple
-registration IDs associated
-with that user. This allows a 3rd-party server to send a single message to
-multiple app instances (typically on multiple devices) owned by a single user.
-A 3rd-party server can use {@code notification_key} as the target for a message
-instead of an individual registration ID (or array of registration IDs). The maximum
-number of members allowed for a {@code notification_key} is 20. For more discussion
-of this topic, see <a href="notifications.html">User Notifications</a>. Optional.
-</td>
-<td style="width:100px">HTTP. This feature is supported in CCS, but you use it by
-specifying a notification key in the "to" field.</td>
-</tr>
- <tr>
- <td><code>collapse_key</code></td>
- <td>This parameter specifies an arbitrary string (such as
-"Updates Available") that is used
-to collapse a group of like messages
-when the device is offline, so that only the last message gets sent to the
-client. This is intended to avoid sending too many messages to the phone when it
-comes back online. Note that since there is no guarantee of the order in which
-messages get sent, the "last" message may not actually be the last
-message sent by the application server. Messages with collapse keys are also called
-<a href="#s2s">send-to-sync messages</a>.
-<br>
-<strong>Note:</strong> GCM allows a maximum of 4 different collapse keys to be
-used by the GCM server
-at any given time. In other words, the GCM server can simultaneously store 4
-different send-to-sync messages per device, each with a different collapse key.
-If you exceed
-this number GCM will only keep 4 collapse keys, with no guarantees about which
-ones they will be. See <a href="adv.html#collapsible">Advanced Topics</a> for more
-discussion of this topic. Optional.</td>
-<td>CCS, HTTP</td>
-</tr>
- <tr>
- <td><code>data</code></td>
- <td>This parameter specifies a JSON object whose fields represents the
-key-value pairs of the message's
-payload data. If present, the payload data will be
-included in the Intent as application data, with the key being the extra's name.
-For instance, <code>"data":{"score":"3x1"}</code> would result in an intent extra
-named <code>score</code> whose value is the string <code>3x1</code>.
-There is no limit on the number of key/value pairs, though there is a limit on
-the total size of the message (4kb). The values could be any JSON object, but we
-recommend using strings, since the values will be converted to strings in the GCM
-server anyway. If you want to include objects or other non-string data types
-(such as integers or booleans), you have to do the conversion to string yourself.
-Also note that the key cannot be a reserved word (<code>from</code> or any word
-starting with <code>google.</code>). Using words defined in this table as field
-names (such as <code>collapse_key</code>) could yield unpredictable outcomes and
-is not recommended. Optional.</td>
-<td>CCS, HTTP</td>
-</tr>
- <tr>
- <td><code>delay_while_idle</code></td>
- <td>This parameter indicates that the message should not be sent immediately
-if the device is idle. The server will wait for the device to become active, and
-then only the last message for each <code>collapse_key</code> value will be
-sent. The default value is <code>false</code>, and must be a JSON boolean. Optional.</td>
-<td>CCS, HTTP</td>
-</tr>
- <tr>
- <td><code>time_to_live</code></td>
- <td>This parameter specifies how long (in seconds) the message should be kept on GCM
-storage if the device is offline. Optional (default time-to-live is 4 weeks, and must be set as
-a JSON number).</td>
-<td>CCS, HTTP</td>
-</tr>
-<tr>
- <td><code>restricted_package_name</code></td>
- <td>This parameter specifies a string containing the package
-name of your application. When set, messages
-are only sent to registration IDs that match the package name. Optional.
- </td>
-<td>HTTP</td>
-</tr>
-<tr>
- <td><code>dry_run</code></td>
- <td>This parameter allows developers to test a request without actually
-sending a message. Optional. The default value is <code>false</code>, and must
-be a JSON boolean.
- </td>
-<td>HTTP</td>
-</tr>
-<tr>
- <td><code>delivery_receipt_requested</code></td>
- <td>This parameter lets you request confirmation of message delivery. When
-this parameter is set to <code>true</code>, CCS sends a
-delivery receipt when a device confirms that it received a message sent by CCS.
-The default value is <code>false</code>, and must be a JSON boolean. Optional.<br />
-This parameter relates to <a href="{@docRoot}google/gcm/ccs.html#receipts"}>
-delivery receipts</a>.
-</td>
- <td>CCS</td>
-</tr>
-<tr>
- <td><code>message_status</code></td>
- <td>This parameter specifies the status of the receipt message.
-The parameter appears inside the
-<code>"data"</code> field of a
-delivery receipt message. Currently the only possible value
-is <code>MESSAGE_SENT_TO_DEVICE</code>, which indicates that a device acknowledges
-receiving a message sent by CCS.<br />
-This parameter relates to <a href="{@docRoot}google/gcm/ccs.html#receipts"}>
-delivery receipts</a>.</td>
- <td>CCS</td>
-</tr>
-<tr>
- <td><code>original_message_id</code></td>
- <td>The value of this parameter is the ID of the original message that the server sent to
-the device. This parameter appears inside the <code>"data"</code> field of a
-delivery receipt message. <br />
-This parameter relates to <a href="{@docRoot}google/gcm/ccs.html#receipts"}>
-delivery receipts</a>.</td>
- <td>CCS</td>
-</tr>
-<tr>
- <td><code>device_registration_id</code></td>
- <td>For the purpose of tracking the delivery receipt, this parameter lists
-the registration ID of the device to which a given message was sent. This parameter
-appears inside the <code>"data"</code> field of a
-delivery receipt message. <br />
-This parameter relates to <a href="{@docRoot}google/gcm/ccs.html#receipts"}>
-delivery receipts</a>.</td>
- <td>CCS</td>
-</tr>
-
-</table>
-
+<ul>
+ <li>{@code collapse_key}: whether a message should be "send-to-sync" or a "message with
+payload".</li>
+ <li>{@code time_to_live}: setting an expiration date for a message.</li>
+ <li>{@code dry_run}: Test your server.
<p>If you want to test your request (either JSON or plain text) without delivering
-the message to the devices, you can set an optional HTTP or JSON parameter called
+the message to the devices, you can set an optional HTTP parameter called
<code>dry_run</code> with the value <code>true</code>. The result will be almost
identical to running the request without this parameter, except that the message
will not be delivered to the devices. Consequently, the response will contain fake
IDs for the message and multicast parameters.</p>
+</li>
+</ul>
-<p>If you are using plain text instead of JSON, the message parameters must be set as
-HTTP parameters sent in the body, and their syntax is slightly different, as
-described in the following table:
+<h4 id="payload">Payload</h4>
+<p>Optional. If you are including a payload in the message, you use the <code>data</code>
+parameter to include the payload. This applies for both HTTP and XMPP.</p>
-<p class="table-caption" id="table2">
- <strong>Table 2.</strong> Message Parameters Plain Text (HTTP only).</p>
-<table>
- <tr>
- <th>Parameter</th>
- <th>Description</th>
- </tr>
- <tr>
- <td><code>registration_id</code></td>
- <td>This parameter specifies the registration ID of the single device
-receiving the message.
-Required.</td>
- </tr>
- <tr>
- <td><code>collapse_key</code></td>
- <td>Same as JSON (see previous table). Optional.</td>
- </tr>
- <tr>
- <td><code>data.<key></code></td>
+<p>See the <a href="{@docRoot}google/gcm/server-ref.html">Server Reference</a> for details on sending
+and receiving messages.</p>
- <td>This parameter specifies payload data, expressed as parameters
-prefixed with <code>data.</code> and
-suffixed as the key. For instance, a parameter of <code>data.score=3x1</code> would
-result in an intent extra named <code>score</code> whose value is the string
-<code>3x1</code>. There is no limit on the number of key/value parameters, though
-there is a limit on the total size of the message. Also note that the key cannot
-be a reserved word (<code>from</code> or any word starting with
-<code>google.</code>). Using words defined in this table as field
-names (such as <code>collapse_key</code>) could yield unpredictable outcomes and
-is not recommended. Optional.</td>
+<h2 id="adv">Messaging Concepts and Best Practices</h2>
- </tr>
- <tr>
- <td><code>delay_while_idle</code></td>
- <td>This parameter specifies whether messages should be delivered when the device
-is asleep. A value of <code>1</code> or <code>true</code> indicates
-<code>true</code>, and anything else indicates <code>false</code>. Optional. The default
-value is <code>false</code>.</td>
- </tr>
- <tr>
- <td><code>time_to_live</code></td>
- <td>Same as JSON (see previous table). Optional.</td>
- </tr>
-<tr>
- <td><code>restricted_package_name</code></td>
- <td>Same as JSON (see previous table). Optional.
- </td>
-</tr>
-<tr>
- <td><code>dry_run</code></td>
- <td>Same as JSON (see previous table). Optional.
- </td>
-</tr>
-</table>
+<p>This section has a discussion of general messaging topics.</p>
-<h2 id="receive">Receiving Messages</h2>
+<h3 id="collapsible">Send-to-Sync vs. Messages with Payload</h3>
-<p>This is the sequence of events that occurs when an Android application
-installed on a mobile device receives a message:</p>
+<p>Every message sent in GCM has the following characteristics:</p>
+<ul>
+ <li>It has a payload limit of 4096 bytes.</li>
+ <li>By default, it is stored by GCM for 4 weeks.</li>
+</ul>
-<ol>
- <li>The system receives the incoming message and extracts the raw key/value
-pairs from the message payload, if any.</li>
- <li>The system passes the key/value pairs to the targeted Android application
-in a <code>com.google.android.c2dm.intent.RECEIVE</code> Intent as a set of
-extras.</li>
- <li>The Android application extracts the raw data
-from the <code>com.google.android.c2dm.intent.RECEIVE</code><code> </code>Intent
-by key and processes the data.</li>
-</ol>
+<p>But despite these similarities, messages can behave very differently depending
+on their particular settings. One major distinction between messages is whether
+they are collapsed (where each new message replaces the preceding message) or not
+collapsed (where each individual message is delivered). Every message sent in GCM
+is either a "send-to-sync" (collapsible) message or a "message with
+payload" (non-collapsible message).</p>
-<p>See the documentation for each connection server for more detail on how it
-handles responses.</p>
+<h4 id="s2s">Send-to-sync messages</h4>
+
+<p>A send-to-sync (collapsible) message is often a "tickle" that tells
+a mobile application to sync data from the server. For example, suppose you have
+an email application. When a user receives new email on the server, the server
+pings the mobile application with a "New mail" message. This tells the
+application to sync to the server to pick up the new email. The server might send
+this message multiple times as new mail continues to accumulate, before the application
+has had a chance to sync. But if the user has received 25 new emails, there's no
+need to preserve every "New mail" message. One is sufficient. Another
+example would be a sports application that updates users with the latest score.
+Only the most recent message is relevant. </p>
+
+<p>GCM allows a maximum of 4 different collapse keys to be used by the GCM server
+at any given time. In other words, the GCM server can simultaneously store 4
+different send-to-sync messages per device, each with a different collapse key.
+For example, Device A can have A1, A2, A3, and A4. Device B can have B1, B2, B3,
+and B4, and so on. If you exceed this number GCM will only keep 4 collapse keys, with no
+guarantees about which ones they will be.</p>
+
+<h3 id="payload">Messages with payload</h3>
+
+<p>Unlike a send-to-sync message, every "message with payload"
+(non-collapsible message) is delivered. The payload the message contains can be
+up to 4kb. For example, here is a JSON-formatted message in an IM application in
+which spectators are discussing a sporting event:</p>
+
+<pre class="prettyprint pretty-json">{
+ "registration_id" : "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...",
+ "data" : {
+ "Nick" : "Mario",
+ "Text" : "great match!",
+ "Room" : "PortugalVSDenmark",
+ },
+}</pre>
+
+<p>A "message with payload" is not simply a "ping" to the
+mobile application to contact the server to fetch data. In the aforementioned IM
+application, for example, you would want to deliver every message, because every
+message has different content. To specify a non-collapsible message, you simply
+omit the <code>collapse_key</code> parameter. Thus GCM will send each message
+individually. Note that the order of delivery is not guaranteed.</p>
+
+<p>GCM will store up to 100 non-collapsible messages. After that, all messages
+are discarded from GCM, and a new message is created that tells the client how
+far behind it is.</p>
+
+<p>The application should respond by syncing with the server to recover the
+discarded messages. </p>
+
+<h4 id="which">Which should I use?</h4>
+ <p>If your application does not need to use non-collapsible messages, collapsible
+messages are a better choice from a performance standpoint. However, if you use
+collapsible messages, remember that <strong>GCM only allows a maximum of 4 different collapse
+keys to be used by the GCM server per registration ID at any given time</strong>. You must
+not exceed this number, or it could cause unpredictable consequences.</p>
+
+<h3 id="ttl">Setting an Expiration Date for a Message</h3>
+<p>You can use the <code>time_to_live</code> parameter in the send request
+to specify the maximum lifespan of a message.
+The value of this parameter must be a duration from 0 to 2,419,200 seconds, and
+it corresponds to the maximum period of time for which GCM will store and try to
+deliver the message. Requests that don't contain this field default to the maximum
+period of 4 weeks.</p>
+<p>Here are some possible uses for this feature:</p>
+<ul>
+ <li>Video chat incoming calls</li>
+ <li>Expiring invitation events</li>
+ <li>Calendar events</li>
+</ul>
+<h4 id="bg">Background </h4>
+<p>GCM usually delivers messages immediately after they are sent. However,
+this might not always be possible. For example, if the platform is Android,
+the device could be turned off, offline, or otherwise unavailable.
+Or the sender itself might request
+that messages not be delivered until the device becomes active by using the
+<code>delay_while_idle</code> flag. Finally, GCM might intentionally delay messages
+to prevent an application from consuming excessive resources and negatively
+impacting battery life.</p>
+
+<p>When this happens, GCM will store the message and deliver it as soon as it's
+feasible. While this is fine in most cases, there are some applications for which
+a late message might as well never be delivered. For example, if the message is
+an incoming call or video chat notification, it will only be meaningful for a
+small period of time before the call is terminated. Or if the message is an
+invitation to an event, it will be useless if received after the event has ended.</p>
+
+<p>Another advantage of specifying the expiration date for a message is that GCM
+will never throttle messages with a <code>time_to_live</code> value of 0 seconds.
+In other words, GCM will guarantee best effort for messages that must be delivered
+"now or never." Keep in mind that a <code>time_to_live</code> value of
+0 means messages that can't be delivered immediately will be discarded. However,
+because such messages are never stored, this provides the best latency for
+sending notifications.</p>
+
+<p>Here is an example of a JSON-formatted request that includes TTL:</p>
+<pre class="prettyprint pretty-json">
+{
+ "collapse_key" : "demo",
+ "delay_while_idle" : true,
+ "registration_ids" : ["xyz"],
+ "data" : {
+ "key1" : "value1",
+ "key2" : "value2",
+ },
+ "time_to_live" : 3
+},
+</pre>
+
+
+<h3 id="multi-senders">Receiving Messages from Multiple Senders</h3>
+
+<p>GCM allows multiple parties to send messages to the same application. For
+example, suppose your application is an articles aggregator with multiple
+contributors, and you want each of them to be able to send a message when they
+publish a new article. This message might contain a URL so that the application
+can download the article. Instead of having to centralize all sending activity in
+one location, GCM gives you the ability to let each of these contributors send
+its own messages.</p>
+
+<p>To make this possible, all you need to do is have each sender generate its own
+project number. Then include those IDs in the sender field, separated by commas,
+when requesting a registration. Finally, share the registration ID with your
+partners, and they'll be able to send messages to your application using their
+own authentication keys.</p>
+
+<p>Note that there is limit of 100 multiple senders.</p>
+
+<h3 id="lifetime">Lifetime of a Message</h3>
+
+<p>When a 3rd-party server posts a message to GCM and receives a message ID back,
+it does not mean that the message was already delivered to the device. Rather, it
+means that it was accepted for delivery. What happens to the message after it is
+accepted depends on many factors.</p>
+
+<p>In the best-case scenario, if the device is connected to GCM, the screen is on,
+and there are no throttling restrictions (see <a href="#throttling">Throttling</a>),
+the message will be delivered right away.</p>
+
+<p>If the device is connected but idle, the message will still be
+delivered right away unless the <code>delay_while_idle</code> flag is set to true.
+Otherwise, it will be stored in the GCM servers until the device is awake. And
+that's where the <code>collapse_key</code> flag plays a role: if there is already
+a message with the same collapse key (and registration ID) stored and waiting for
+delivery, the old message will be discarded and the new message will take its place
+(that is, the old message will be collapsed by the new one). However, if the collapse
+key is not set, both the new and old messages are stored for future delivery.
+Collapsible messages are also called <a href="#s2s">send-to-sync messages</a>.</p>
+
+<p class="note"><strong>Note:</strong> There is a limit on how many messages can
+be stored without collapsing. That limit is currently 100. If the limit is reached,
+all stored messages are discarded. Then when the device is back online, it receives
+a special message indicating that the limit was reached. The application can then
+handle the situation properly, typically by requesting a full sync.
+<br><br>
+Likewise, there is a limit on how many <code>collapse_key</code>s you can have for
+a particular device. GCM allows a maximum of 4 different collapse keys to be used
+by the GCM server per device
+any given time. In other words, the GCM server can simultaneously store 4 different
+send-to-sync messages, each with a different collapse key. If you exceed this number
+GCM will only keep 4 collapse keys, with no guarantees about which ones they will be.
+See <a href="#s2s">Send-to-sync messages</a> for more information.
+</p>
+
+<p>If the device is not connected to GCM, the message will be stored until a
+connection is established (again respecting the collapse key rules). When a connection
+is established, GCM will deliver all pending messages to the device, regardless of
+the <code>delay_while_idle</code> flag. If the device never gets connected again
+(for instance, if it was factory reset), the message will eventually time out and
+be discarded from GCM storage. The default timeout is 4 weeks, unless the
+<code>time_to_live</code> flag is set.</p>
+
+<p>Finally, when GCM attempts to deliver a message to the device and the
+application was uninstalled, GCM will discard that message right away and
+invalidate the registration ID. Future attempts to send a message to that device
+will get a <code>NotRegistered</code> error. See <a href="#unreg">
+How Unregistration Works</a> for more information.</p>
+<p>Although is not possible to track the status of each individual message, the
+Google Cloud Console stats are broken down by messages sent to device, messages
+collapsed, and messages waiting for delivery.</p>
+
+<h3 id="throttling">Throttling</h3>
+<p>To prevent abuse (such as sending a flood of messages to a device) and
+to optimize for the overall network efficiency and battery life of
+devices, GCM implements throttling of messages using a token bucket
+scheme. Messages are throttled on a per application and per <a href="#collapsible">collapse
+key</a> basis (including non-collapsible messages). Each application
+collapse key is granted some initial tokens, and new tokens are granted
+periodically therefter. Each token is valid for a single message sent to
+the device. If an application collapse key exhausts its supply of
+available tokens, new messages are buffered in a pending queue until
+new tokens become available at the time of the periodic grant. Thus
+throttling in between periodic grant intervals may add to the latency
+of message delivery for an application collapse key that sends a large
+number of messages within a short period of time. Messages in the pending
+queue of an application collapse key may be delivered before the time
+of the next periodic grant, if they are piggybacked with messages
+belonging to a non-throttled category by GCM for network and battery
+efficiency reasons.</p>
+
+
diff --git a/docs/html/google/google_toc.cs b/docs/html/google/google_toc.cs
index 0c48a0a..4e8e638 100644
--- a/docs/html/google/google_toc.cs
+++ b/docs/html/google/google_toc.cs
@@ -169,22 +169,15 @@
<span class="en">HTTP</span></a></li>
</ul>
</li>
+ <li><a href="<?cs var:toroot?>google/gcm/server-ref.html">
+ <span class="en">Server Reference</span></a>
+ </li>
<li><a href="<?cs var:toroot?>google/gcm/notifications.html">
<span class="en">User Notifications</span></a>
</li>
- <li><a href="<?cs var:toroot?>google/gcm/adv.html">
- <span class="en">Advanced Topics</span></a>
- </li>
<li><a href="<?cs var:toroot?>google/gcm/c2dm.html">
<span class="en">Migration</span></a>
</li>
- <li id="gcm-tree-list" class="nav-section">
- <div class="nav-section-header">
- <a href="<?cs var:toroot ?>reference/gcm-packages.html">
- <span class="en">Reference</span>
- </a>
- <div>
- </li>
</ul>
</li>
diff --git a/docs/html/images/opengl/ogl-triangle-projected.png b/docs/html/images/opengl/ogl-triangle-projected.png
index 4b18b98..a561bc5 100644
--- a/docs/html/images/opengl/ogl-triangle-projected.png
+++ b/docs/html/images/opengl/ogl-triangle-projected.png
Binary files differ
diff --git a/docs/html/images/opengl/ogl-triangle-touch.png b/docs/html/images/opengl/ogl-triangle-touch.png
index 8323dd9..67c4466 100644
--- a/docs/html/images/opengl/ogl-triangle-touch.png
+++ b/docs/html/images/opengl/ogl-triangle-touch.png
Binary files differ
diff --git a/docs/html/images/opengl/ogl-triangle.png b/docs/html/images/opengl/ogl-triangle.png
index 66047ab..f51c0c6 100644
--- a/docs/html/images/opengl/ogl-triangle.png
+++ b/docs/html/images/opengl/ogl-triangle.png
Binary files differ
diff --git a/docs/html/training/graphics/opengl/draw.jd b/docs/html/training/graphics/opengl/draw.jd
index ba00627..a588066 100644
--- a/docs/html/training/graphics/opengl/draw.jd
+++ b/docs/html/training/graphics/opengl/draw.jd
@@ -50,13 +50,21 @@
for memory and processing efficiency.</p>
<pre>
-public void onSurfaceCreated(GL10 unused, EGLConfig config) {
- ...
+public class MyGLRenderer implements GLSurfaceView.Renderer {
- // initialize a triangle
- mTriangle = new Triangle();
- // initialize a square
- mSquare = new Square();
+ ...
+ private Triangle mTriangle;
+ private Square mSquare;
+
+ public void onSurfaceCreated(GL10 unused, EGLConfig config) {
+ ...
+
+ // initialize a triangle
+ mTriangle = new Triangle();
+ // initialize a square
+ mSquare = new Square();
+ }
+ ...
}
</pre>
@@ -77,21 +85,27 @@
<p>You need at least one vertex shader to draw a shape and one fragment shader to color that shape.
These shaders must be complied and then added to an OpenGL ES program, which is then used to draw
-the shape. Here is an example of how to define basic shaders you can use to draw a shape:</p>
+the shape. Here is an example of how to define basic shaders you can use to draw a shape in the
+<code>Triangle</code> class:</p>
<pre>
-private final String vertexShaderCode =
- "attribute vec4 vPosition;" +
- "void main() {" +
- " gl_Position = vPosition;" +
- "}";
+public class Triangle {
-private final String fragmentShaderCode =
- "precision mediump float;" +
- "uniform vec4 vColor;" +
- "void main() {" +
- " gl_FragColor = vColor;" +
- "}";
+ private final String vertexShaderCode =
+ "attribute vec4 vPosition;" +
+ "void main() {" +
+ " gl_Position = vPosition;" +
+ "}";
+
+ private final String fragmentShaderCode =
+ "precision mediump float;" +
+ "uniform vec4 vColor;" +
+ "void main() {" +
+ " gl_FragColor = vColor;" +
+ "}";
+
+ ...
+}
</pre>
<p>Shaders contain OpenGL Shading Language (GLSL) code that must be compiled prior to using it in
@@ -125,13 +139,28 @@
public class Triangle() {
...
- int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
- int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
+ private final int mProgram;
- mProgram = GLES20.glCreateProgram(); // create empty OpenGL ES Program
- GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
- GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
- GLES20.glLinkProgram(mProgram); // creates OpenGL ES program executables
+ public Triangle() {
+ ...
+
+ int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
+ vertexShaderCode);
+ int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
+ fragmentShaderCode);
+
+ // create empty OpenGL ES Program
+ mProgram = GLES20.glCreateProgram();
+
+ // add the vertex shader to program
+ GLES20.glAttachShader(mProgram, vertexShader);
+
+ // add the fragment shader to program
+ GLES20.glAttachShader(mProgram, fragmentShader);
+
+ // creates OpenGL ES program executables
+ GLES20.glLinkProgram(mProgram);
+ }
}
</pre>
@@ -145,6 +174,12 @@
function.</p>
<pre>
+private int mPositionHandle;
+private int mColorHandle;
+
+private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
+private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
+
public void draw() {
// Add program to OpenGL ES environment
GLES20.glUseProgram(mProgram);
@@ -176,8 +211,17 @@
<p>Once you have all this code in place, drawing this object just requires a call to the
{@code draw()} method from within your renderer’s {@link
-android.opengl.GLSurfaceView.Renderer#onDrawFrame onDrawFrame()} method. When you run the
-application, it should look something like this:</p>
+android.opengl.GLSurfaceView.Renderer#onDrawFrame onDrawFrame()} method:
+
+<pre>
+public void onDrawFrame(GL10 unused) {
+ ...
+
+ mTriangle.draw();
+}
+</pre>
+
+<p>When you run the application, it should look something like this:</p>
<img src="{@docRoot}images/opengl/ogl-triangle.png">
<p class="img-caption">
diff --git a/docs/html/training/graphics/opengl/environment.jd b/docs/html/training/graphics/opengl/environment.jd
index 6b00c76..cf2b64a 100644
--- a/docs/html/training/graphics/opengl/environment.jd
+++ b/docs/html/training/graphics/opengl/environment.jd
@@ -129,28 +129,22 @@
<pre>
class MyGLSurfaceView extends GLSurfaceView {
+ private final MyGLRenderer mRenderer;
+
public MyGLSurfaceView(Context context){
super(context);
+ // Create an OpenGL ES 2.0 context
+ setEGLContextClientVersion(2);
+
+ mRenderer = new MyGLRenderer();
+
// Set the Renderer for drawing on the GLSurfaceView
- setRenderer(new MyRenderer());
+ setRenderer(mRenderer);
}
}
</pre>
-<p>When using OpenGL ES 2.0, you must add another call to your {@link android.opengl.GLSurfaceView}
-constructor, specifying that you want to use the 2.0 API:</p>
-
-<pre>
-// Create an OpenGL ES 2.0 context
-setEGLContextClientVersion(2);
-</pre>
-
-<p class="note"><strong>Note:</strong> If you are using the OpenGL ES 2.0 API, make sure you declare
-this in your application manifest. For more information, see <a href="#manifest">Declare OpenGL ES
-Use
-in the Manifest</a>.</p>
-
<p>One other optional addition to your {@link android.opengl.GLSurfaceView} implementation is to set
the render mode to only draw the view when there is a change to your drawing data using the
{@link android.opengl.GLSurfaceView#RENDERMODE_WHEN_DIRTY GLSurfaceView.RENDERMODE_WHEN_DIRTY}
@@ -186,7 +180,7 @@
</ul>
<p>Here is a very basic implementation of an OpenGL ES renderer, that does nothing more than draw a
-gray background in the {@link android.opengl.GLSurfaceView}:</p>
+black background in the {@link android.opengl.GLSurfaceView}:</p>
<pre>
public class MyGLRenderer implements GLSurfaceView.Renderer {
@@ -208,7 +202,7 @@
</pre>
<p>That’s all there is to it! The code examples above create a simple Android application that
-displays a gray screen using OpenGL. While this code does not do anything very interesting, by
+displays a black screen using OpenGL. While this code does not do anything very interesting, by
creating these classes, you have laid the foundation you need to start drawing graphic elements with
OpenGL.</p>
diff --git a/docs/html/training/graphics/opengl/motion.jd b/docs/html/training/graphics/opengl/motion.jd
index fbcdd7f..b026a4a 100644
--- a/docs/html/training/graphics/opengl/motion.jd
+++ b/docs/html/training/graphics/opengl/motion.jd
@@ -45,16 +45,17 @@
<h2 id="rotate">Rotate a Shape</h2>
-<p>Rotating a drawing object with OpenGL ES 2.0 is relatively simple. You create another
-transformation matrix (a rotation matrix) and then combine it with your projection and
+<p>Rotating a drawing object with OpenGL ES 2.0 is relatively simple. In your renderer, create
+another transformation matrix (a rotation matrix) and then combine it with your projection and
camera view transformation matrices:</p>
<pre>
private float[] mRotationMatrix = new float[16];
public void onDrawFrame(GL10 gl) {
- ...
float[] scratch = new float[16];
+ ...
+
// Create a rotation transformation for the triangle
long time = SystemClock.uptimeMillis() % 4000L;
float angle = 0.090f * ((int) time);
diff --git a/docs/html/training/graphics/opengl/projection.jd b/docs/html/training/graphics/opengl/projection.jd
index b09e74c..356d5d4 100644
--- a/docs/html/training/graphics/opengl/projection.jd
+++ b/docs/html/training/graphics/opengl/projection.jd
@@ -71,6 +71,11 @@
android.opengl.Matrix#frustumM Matrix.frustumM()} method:</p>
<pre>
+// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
+private final float[] mMVPMatrix = new float[16];
+private final float[] mProjectionMatrix = new float[16];
+private final float[] mViewMatrix = new float[16];
+
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
@@ -95,10 +100,10 @@
<h2 id="camera-view">Define a Camera View</h2>
<p>Complete the process of transforming your drawn objects by adding a camera view transformation as
-part of the drawing process. In the following example code, the camera view transformation is
-calculated using the {@link android.opengl.Matrix#setLookAtM Matrix.setLookAtM()} method and then
-combined with the previously calculated projection matrix. The combined transformation matrices
-are then passed to the drawn shape.</p>
+part of the drawing process in your renderer. In the following example code, the camera view
+transformation is calculated using the {@link android.opengl.Matrix#setLookAtM Matrix.setLookAtM()}
+method and then combined with the previously calculated projection matrix. The combined
+transformation matrices are then passed to the drawn shape.</p>
<pre>
@Override
@@ -119,7 +124,32 @@
<h2 id="#transform">Apply Projection and Camera Transformations</h2>
<p>In order to use the combined projection and camera view transformation matrix shown in the
-previews sections, modify the {@code draw()} method of your graphic objects to accept the combined
+previews sections, first add a matrix variable to the <em>vertex shader</em> previously defined
+in the <code>Triangle</code> class:</p>
+
+<pre>
+public class Triangle {
+
+ private final String vertexShaderCode =
+ // This matrix member variable provides a hook to manipulate
+ // the coordinates of the objects that use this vertex shader
+ <strong>"uniform mat4 uMVPMatrix;" +</strong>
+ "attribute vec4 vPosition;" +
+ "void main() {" +
+ // the matrix must be included as a modifier of gl_Position
+ // Note that the uMVPMatrix factor *must be first* in order
+ // for the matrix multiplication product to be correct.
+ " gl_Position = <strong>uMVPMatrix</strong> * vPosition;" +
+ "}";
+
+ // Use to access and set the view transformation
+ private int mMVPMatrixHandle;
+
+ ...
+}
+</pre>
+
+<p>Next, modify the {@code draw()} method of your graphic objects to accept the combined
transformation matrix and apply it to the shape:</p>
<pre>
@@ -127,14 +157,16 @@
...
// get handle to shape's transformation matrix
- mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
+ <strong>mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");</strong>
// Pass the projection and view transformation to the shader
- GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
+ <strong>GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);</strong>
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
- ...
+
+ // Disable vertex array
+ GLES20.glDisableVertexAttribArray(mPositionHandle);
}
</pre>
diff --git a/docs/html/training/graphics/opengl/touch.jd b/docs/html/training/graphics/opengl/touch.jd
index 4c9f0c7..089ede7 100644
--- a/docs/html/training/graphics/opengl/touch.jd
+++ b/docs/html/training/graphics/opengl/touch.jd
@@ -50,6 +50,10 @@
an angle of rotation for a shape.</p>
<pre>
+private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
+private float mPreviousX;
+private float mPreviousY;
+
@Override
public boolean onTouchEvent(MotionEvent e) {
// MotionEvent reports input details from the touch screen
@@ -77,7 +81,7 @@
mRenderer.setAngle(
mRenderer.getAngle() +
- ((dx + dy) * TOUCH_SCALE_FACTOR); // = 180.0f / 320
+ ((dx + dy) * TOUCH_SCALE_FACTOR));
requestRender();
}
@@ -108,12 +112,22 @@
<p>The example code above requires that you expose the rotation angle through your renderer by
adding a public member. Since the renderer code is running on a separate thread from the main user
interface thread of your application, you must declare this public variable as {@code volatile}.
-Here is the code to do that:</p>
+Here is the code to declare the variable and expose the getter and setter pair:</p>
<pre>
public class MyGLRenderer implements GLSurfaceView.Renderer {
...
+
public volatile float mAngle;
+
+ public float getAngle() {
+ return mAngle;
+ }
+
+ public void setAngle(float angle) {
+ mAngle = angle;
+ }
+}
</pre>
diff --git a/docs/html/training/wearables/watch-faces/index.jd b/docs/html/training/wearables/watch-faces/index.jd
index c7affd1..453c30e 100644
--- a/docs/html/training/wearables/watch-faces/index.jd
+++ b/docs/html/training/wearables/watch-faces/index.jd
@@ -21,6 +21,14 @@
</div>
</a>
+<a class="notice-developers-video wide"
+ href="https://www.youtube.com/watch?v=AK38PJZmIW8">
+<div>
+ <h3>Video</h3>
+ <p>DevBytes: Watch Faces for Android Wear</p>
+</div>
+</a>
+
<p>Watch faces in Android Wear leverage a dynamic digital canvas to tell time using colors,
animations, and relevant contextual information. The <a
href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app">Android
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 505bd1d..9e4674b 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -92,6 +92,8 @@
private int[] mPaddingB;
private final Rect mTmpRect = new Rect();
+ private final Rect mTmpOutRect = new Rect();
+ private final Rect mTmpContainer = new Rect();
private Rect mHotspotBounds;
private boolean mMutated;
@@ -945,7 +947,7 @@
int padR = 0;
int padB = 0;
- final Rect outRect = mTmpRect;
+ final Rect outRect = mTmpOutRect;
final int layoutDirection = getLayoutDirection();
final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST;
final ChildDrawable[] array = mLayerState.mChildren;
@@ -953,7 +955,8 @@
for (int i = 0; i < N; i++) {
final ChildDrawable r = array[i];
final Drawable d = r.mDrawable;
- final Rect container = d.getBounds();
+ final Rect container = mTmpContainer;
+ container.set(d.getBounds());
// Take the resolved layout direction into account. If start / end
// padding are defined, they will be resolved (hence overriding) to
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index e0f2ec43..5373275 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -35,6 +35,10 @@
LOG_ALWAYS_FATAL_IF(stageFlag & mStageFlags, "Stage %d cannot be run twice"); \
mStageFlags = static_cast<StageFlags>(mStageFlags | stageFlag)
+#define REQUIRE_STAGES(requiredFlags) \
+ LOG_ALWAYS_FATAL_IF((mStageFlags & requiredFlags) != requiredFlags, \
+ "not prepared for current stage")
+
GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop)
: mRenderState(renderState)
, mCaches(caches)
@@ -127,12 +131,14 @@
}
TRIGGER_STAGE(kFillStage);
+ REQUIRE_STAGES(kMeshStage);
mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
const bool SWAP_SRC_DST = false;
// TODO: account for texture blend
- if (alphaScale < 1.0f) {
+ if (alphaScale < 1.0f
+ || (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)) {
Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
&mOutGlop->blend.src, &mOutGlop->blend.dst);
} else {
@@ -143,6 +149,7 @@
}
GlopBuilder& GlopBuilder::setPaint(const SkPaint& paint, float alphaScale) {
TRIGGER_STAGE(kFillStage);
+ REQUIRE_STAGES(kMeshStage);
const SkShader* shader = paint.getShader();
const SkColorFilter* colorFilter = paint.getColorFilter();
@@ -169,6 +176,7 @@
mOutGlop->blend = { GL_ZERO, GL_ZERO };
if (mOutGlop->fill.color.a < 1.0f
+ || (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)
|| PaintUtils::isBlendedShader(shader)
|| PaintUtils::isBlendedColorFilter(colorFilter)
|| mode != SkXfermode::kSrcOver_Mode) {
@@ -242,7 +250,7 @@
}
void GlopBuilder::build() {
- LOG_ALWAYS_FATAL_IF(mStageFlags != kAllStages, "glop not fully prepared!");
+ REQUIRE_STAGES(kAllStages);
mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
mOutGlop->fill.program = mCaches.programCache.get(mDescription);
diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp
index 5efac0e..585fb86 100644
--- a/libs/hwui/renderstate/MeshState.cpp
+++ b/libs/hwui/renderstate/MeshState.cpp
@@ -67,7 +67,11 @@
}
void MeshState::dump() {
- ALOGD("MeshState vertices: unitQuad %d, current %d", mUnitQuadBuffer, mCurrentBuffer);
+ ALOGD("MeshState VBOs: unitQuad %d, current %d", mUnitQuadBuffer, mCurrentBuffer);
+ ALOGD("MeshState vertices: vertex data %p, stride %d",
+ mCurrentPositionPointer, mCurrentPositionStride);
+ ALOGD("MeshState texCoord: data %p, stride %d",
+ mCurrentTexCoordsPointer, mCurrentTexCoordsStride);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
index 5f445f4..b6d2c4d 100644
--- a/libs/hwui/tests/main.cpp
+++ b/libs/hwui/tests/main.cpp
@@ -210,7 +210,7 @@
renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
renderer->insertReorderBarrier(true);
- card = createCard(40, 40, 200, 200);
+ card = createCard(40, 40, 400, 400);
renderer->drawRenderNode(card.get(), DUMMY, 0);
renderer->insertReorderBarrier(false);
@@ -228,11 +228,10 @@
node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
DisplayListRenderer* renderer = startRecording(node.get());
- renderer->drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode);
SkPaint paint;
paint.setAntiAlias(true);
- paint.setColor(0xFF00FFFF);
+ paint.setColor(0xFF000000);
renderer->drawOval(0, 0, width, height, paint);
endRecording(renderer, node.get());
diff --git a/media/java/android/media/AudioFocusInfo.java b/media/java/android/media/AudioFocusInfo.java
index fbdda3c..540c328 100644
--- a/media/java/android/media/AudioFocusInfo.java
+++ b/media/java/android/media/AudioFocusInfo.java
@@ -45,8 +45,9 @@
* @param gainRequest
* @param lossReceived
* @param flags
+ * @hide
*/
- AudioFocusInfo(AudioAttributes aa, String clientId, String packageName,
+ public AudioFocusInfo(AudioAttributes aa, String clientId, String packageName,
int gainRequest, int lossReceived, int flags) {
mAttributes = aa == null ? new AudioAttributes.Builder().build() : aa;
mClientId = clientId == null ? "" : clientId;
@@ -91,7 +92,7 @@
public int getLossReceived() { return mLossReceived; }
/** @hide */
- void clearLossReceived() { mLossReceived = 0; }
+ public void clearLossReceived() { mLossReceived = 0; }
/**
* The flags set in the audio focus request.
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 07b19a4..7084eba 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -663,8 +663,7 @@
int keyCode = event.getKeyCode();
if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
&& keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
- && mVolumeKeyUpTime + AudioService.PLAY_SOUND_DELAY
- > SystemClock.uptimeMillis()) {
+ && mVolumeKeyUpTime + AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
/*
* The user has hit another key during the delay (e.g., 300ms)
* since the last volume key up, so cancel any sounds.
@@ -2501,7 +2500,7 @@
service.requestAudioFocus(new AudioAttributes.Builder()
.setInternalLegacyStreamType(streamType).build(),
durationHint, mICallBack, null,
- MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
+ AudioSystem.IN_VOICE_COMM_FOCUS_ID,
mContext.getOpPackageName(),
AUDIOFOCUS_FLAG_LOCK,
null /* policy token */);
@@ -2519,7 +2518,7 @@
public void abandonAudioFocusForCall() {
IAudioService service = getService();
try {
- service.abandonAudioFocus(null, MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
+ service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
null /*AudioAttributes, legacy behavior*/);
} catch (RemoteException e) {
Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService:", e);
diff --git a/media/java/android/media/AudioRoutesInfo.java b/media/java/android/media/AudioRoutesInfo.java
index 3e0ec07..6ae0d46 100644
--- a/media/java/android/media/AudioRoutesInfo.java
+++ b/media/java/android/media/AudioRoutesInfo.java
@@ -25,27 +25,27 @@
* @hide
*/
public class AudioRoutesInfo implements Parcelable {
- static final int MAIN_SPEAKER = 0;
- static final int MAIN_HEADSET = 1<<0;
- static final int MAIN_HEADPHONES = 1<<1;
- static final int MAIN_DOCK_SPEAKERS = 1<<2;
- static final int MAIN_HDMI = 1<<3;
- static final int MAIN_USB = 1<<4;
+ public static final int MAIN_SPEAKER = 0;
+ public static final int MAIN_HEADSET = 1<<0;
+ public static final int MAIN_HEADPHONES = 1<<1;
+ public static final int MAIN_DOCK_SPEAKERS = 1<<2;
+ public static final int MAIN_HDMI = 1<<3;
+ public static final int MAIN_USB = 1<<4;
- CharSequence mBluetoothName;
- int mMainType = MAIN_SPEAKER;
+ public CharSequence bluetoothName;
+ public int mainType = MAIN_SPEAKER;
public AudioRoutesInfo() {
}
public AudioRoutesInfo(AudioRoutesInfo o) {
- mBluetoothName = o.mBluetoothName;
- mMainType = o.mMainType;
+ bluetoothName = o.bluetoothName;
+ mainType = o.mainType;
}
AudioRoutesInfo(Parcel src) {
- mBluetoothName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
- mMainType = src.readInt();
+ bluetoothName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
+ mainType = src.readInt();
}
@Override
@@ -55,8 +55,8 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- TextUtils.writeToParcel(mBluetoothName, dest, flags);
- dest.writeInt(mMainType);
+ TextUtils.writeToParcel(bluetoothName, dest, flags);
+ dest.writeInt(mainType);
}
public static final Parcelable.Creator<AudioRoutesInfo> CREATOR
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 7084656..787320e 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -16,7 +16,10 @@
package android.media;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.media.audiopolicy.AudioMix;
+
import java.util.ArrayList;
/* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET
@@ -65,6 +68,19 @@
private static final int NUM_STREAM_TYPES = 10;
public static final int getNumStreamTypes() { return NUM_STREAM_TYPES; }
+ public static final String[] STREAM_NAMES = new String[] {
+ "STREAM_VOICE_CALL",
+ "STREAM_SYSTEM",
+ "STREAM_RING",
+ "STREAM_MUSIC",
+ "STREAM_ALARM",
+ "STREAM_NOTIFICATION",
+ "STREAM_BLUETOOTH_SCO",
+ "STREAM_SYSTEM_ENFORCED",
+ "STREAM_DTMF",
+ "STREAM_TTS"
+ };
+
/*
* Sets the microphone mute on or off.
*
@@ -570,5 +586,93 @@
public static native int getAudioHwSyncForSession(int sessionId);
public static native int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register);
+
+
+ // Items shared with audio service
+
+ /**
+ * The delay before playing a sound. This small period exists so the user
+ * can press another key (non-volume keys, too) to have it NOT be audible.
+ * <p>
+ * PhoneWindow will implement this part.
+ */
+ public static final int PLAY_SOUND_DELAY = 300;
+
+ /**
+ * Constant to identify a focus stack entry that is used to hold the focus while the phone
+ * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
+ * entering and exiting calls.
+ */
+ public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
+
+ /**
+ * @see AudioManager#setVibrateSetting(int, int)
+ */
+ public static int getValueForVibrateSetting(int existingValue, int vibrateType,
+ int vibrateSetting) {
+
+ // First clear the existing setting. Each vibrate type has two bits in
+ // the value. Note '3' is '11' in binary.
+ existingValue &= ~(3 << (vibrateType * 2));
+
+ // Set into the old value
+ existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
+
+ return existingValue;
+ }
+
+ public static int getDefaultStreamVolume(int streamType) {
+ return DEFAULT_STREAM_VOLUME[streamType];
+ }
+
+ public static int[] DEFAULT_STREAM_VOLUME = new int[] {
+ 4, // STREAM_VOICE_CALL
+ 7, // STREAM_SYSTEM
+ 5, // STREAM_RING
+ 11, // STREAM_MUSIC
+ 6, // STREAM_ALARM
+ 5, // STREAM_NOTIFICATION
+ 7, // STREAM_BLUETOOTH_SCO
+ 7, // STREAM_SYSTEM_ENFORCED
+ 11, // STREAM_DTMF
+ 11 // STREAM_TTS
+ };
+
+ public static String streamToString(int stream) {
+ if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
+ if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
+ return "UNKNOWN_STREAM_" + stream;
+ }
+
+ /** The platform has no specific capabilities */
+ public static final int PLATFORM_DEFAULT = 0;
+ /** The platform is voice call capable (a phone) */
+ public static final int PLATFORM_VOICE = 1;
+ /** The platform is a television or a set-top box */
+ public static final int PLATFORM_TELEVISION = 2;
+
+ /**
+ * Return the platform type that this is running on. One of:
+ * <ul>
+ * <li>{@link #PLATFORM_VOICE}</li>
+ * <li>{@link #PLATFORM_TELEVISION}</li>
+ * <li>{@link #PLATFORM_DEFAULT}</li>
+ * </ul>
+ */
+ public static int getPlatformType(Context context) {
+ if (context.getResources().getBoolean(com.android.internal.R.bool.config_voice_capable)) {
+ return PLATFORM_VOICE;
+ } else if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+ return PLATFORM_TELEVISION;
+ } else {
+ return PLATFORM_DEFAULT;
+ }
+ }
+
+ public static final int DEFAULT_MUTE_STREAMS_AFFECTED =
+ (1 << STREAM_MUSIC) |
+ (1 << STREAM_RING) |
+ (1 << STREAM_NOTIFICATION) |
+ (1 << STREAM_SYSTEM);
}
diff --git a/media/java/android/media/ClosedCaptionRenderer.java b/media/java/android/media/ClosedCaptionRenderer.java
index d34b21b..e3680e9 100644
--- a/media/java/android/media/ClosedCaptionRenderer.java
+++ b/media/java/android/media/ClosedCaptionRenderer.java
@@ -154,6 +154,7 @@
private int mMode = MODE_PAINT_ON;
private int mRollUpSize = 4;
+ private int mPrevCtrlCode = INVALID;
private CCMemory mDisplay = new CCMemory();
private CCMemory mNonDisplay = new CCMemory();
@@ -260,6 +261,13 @@
private boolean handleCtrlCode(CCData ccData) {
int ctrlCode = ccData.getCtrlCode();
+
+ if (mPrevCtrlCode != INVALID && mPrevCtrlCode == ctrlCode) {
+ // discard double ctrl codes (but if there's a 3rd one, we still take that)
+ mPrevCtrlCode = INVALID;
+ return true;
+ }
+
switch(ctrlCode) {
case RCL:
// select pop-on style
@@ -325,10 +333,12 @@
break;
case INVALID:
default:
- // not handled
+ mPrevCtrlCode = INVALID;
return false;
}
+ mPrevCtrlCode = ctrlCode;
+
// handled
return true;
}
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 958ffab..5285074 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -171,15 +171,15 @@
}
void updateAudioRoutes(AudioRoutesInfo newRoutes) {
- if (newRoutes.mMainType != mCurAudioRoutesInfo.mMainType) {
- mCurAudioRoutesInfo.mMainType = newRoutes.mMainType;
+ if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) {
+ mCurAudioRoutesInfo.mainType = newRoutes.mainType;
int name;
- if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_HEADPHONES) != 0
- || (newRoutes.mMainType&AudioRoutesInfo.MAIN_HEADSET) != 0) {
+ if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HEADPHONES) != 0
+ || (newRoutes.mainType&AudioRoutesInfo.MAIN_HEADSET) != 0) {
name = com.android.internal.R.string.default_audio_route_name_headphones;
- } else if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
+ } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
name = com.android.internal.R.string.default_audio_route_name_dock_speakers;
- } else if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_HDMI) != 0) {
+ } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HDMI) != 0) {
name = com.android.internal.R.string.default_media_route_name_hdmi;
} else {
name = com.android.internal.R.string.default_audio_route_name;
@@ -188,21 +188,21 @@
dispatchRouteChanged(sStatic.mDefaultAudioVideo);
}
- final int mainType = mCurAudioRoutesInfo.mMainType;
+ final int mainType = mCurAudioRoutesInfo.mainType;
- if (!TextUtils.equals(newRoutes.mBluetoothName, mCurAudioRoutesInfo.mBluetoothName)) {
- mCurAudioRoutesInfo.mBluetoothName = newRoutes.mBluetoothName;
- if (mCurAudioRoutesInfo.mBluetoothName != null) {
+ if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
+ mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
+ if (mCurAudioRoutesInfo.bluetoothName != null) {
if (sStatic.mBluetoothA2dpRoute == null) {
final RouteInfo info = new RouteInfo(sStatic.mSystemCategory);
- info.mName = mCurAudioRoutesInfo.mBluetoothName;
+ info.mName = mCurAudioRoutesInfo.bluetoothName;
info.mDescription = sStatic.mResources.getText(
com.android.internal.R.string.bluetooth_a2dp_audio_route_name);
info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO;
sStatic.mBluetoothA2dpRoute = info;
addRouteStatic(sStatic.mBluetoothA2dpRoute);
} else {
- sStatic.mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.mBluetoothName;
+ sStatic.mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.bluetoothName;
dispatchRouteChanged(sStatic.mBluetoothA2dpRoute);
}
} else if (sStatic.mBluetoothA2dpRoute != null) {
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index a8b91d2..a73209b 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -484,6 +484,7 @@
status_t err = AMediaExtractor_setDataSourceFd(ex, fd, offset, length);
if (err != AMEDIA_OK) {
+ AMediaExtractor_delete(ex);
return err;
}
diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml
index a3518e1..dae8a02 100644
--- a/packages/PrintSpooler/res/values-si-rLK/strings.xml
+++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml
@@ -24,7 +24,7 @@
<string name="label_paper_size" msgid="908654383827777759">"කඩදාසියේ ප්රමාණය"</string>
<string name="label_paper_size_summary" msgid="5668204981332138168">"කඩදාසියේ ප්රමාණය:"</string>
<string name="label_color" msgid="1108690305218188969">"වර්ණය"</string>
- <string name="label_duplex" msgid="1263181386446435253">"දෙපත්"</string>
+ <string name="label_duplex" msgid="1263181386446435253">"ඩුප්ලෙක්ස්"</string>
<string name="label_orientation" msgid="2853142581990496477">"දිශානතිය"</string>
<string name="label_pages" msgid="7768589729282182230">"පිටු"</string>
<string name="template_all_pages" msgid="3322235982020148762">"සියලුම <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index c3e23d2..2eb7abf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -127,6 +127,7 @@
public void pauseScanning() {
if (mScanner != null) {
mScanner.pause();
+ mScanner = null;
}
}
@@ -134,10 +135,10 @@
* Resume scanning for wifi networks after it has been paused.
*/
public void resumeScanning() {
+ if (mScanner == null) {
+ mScanner = new Scanner();
+ }
if (mWifiManager.isWifiEnabled()) {
- if (mScanner == null) {
- mScanner = new Scanner();
- }
mScanner.resume();
}
updateAccessPoints();
@@ -335,11 +336,17 @@
private void updateWifiState(int state) {
if (state == WifiManager.WIFI_STATE_ENABLED) {
- mScanner.resume();
+ if (mScanner != null) {
+ // We only need to resume if mScanner isn't null because
+ // that means we want to be scanning.
+ mScanner.resume();
+ }
} else {
mLastInfo = null;
mLastNetworkInfo = null;
- mScanner.pause();
+ if (mScanner != null) {
+ mScanner.pause();
+ }
}
if (mListener != null) {
mListener.onWifiStateChanged(state);
@@ -382,26 +389,34 @@
@VisibleForTesting
class Scanner extends Handler {
+ private static final int MSG_SCAN = 0;
+
private int mRetry = 0;
void resume() {
- if (!hasMessages(0)) {
- sendEmptyMessage(0);
+ if (!hasMessages(MSG_SCAN)) {
+ sendEmptyMessage(MSG_SCAN);
}
}
void forceScan() {
- removeMessages(0);
- sendEmptyMessage(0);
+ removeMessages(MSG_SCAN);
+ sendEmptyMessage(MSG_SCAN);
}
void pause() {
mRetry = 0;
- removeMessages(0);
+ removeMessages(MSG_SCAN);
+ }
+
+ @VisibleForTesting
+ boolean isScanning() {
+ return hasMessages(MSG_SCAN);
}
@Override
public void handleMessage(Message message) {
+ if (message.what != MSG_SCAN) return;
if (mWifiManager.startScan()) {
mRetry = 0;
} else if (++mRetry >= 3) {
diff --git a/packages/SettingsLib/tests/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 73d4938..8eb1ca4 100644
--- a/packages/SettingsLib/tests/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -201,6 +201,29 @@
assertTrue("Connected to wifi", accessPoints.get(0).isActive());
}
+ public void testEnableResumeScanning() {
+ mWifiTracker.mScanner = null;
+
+ Intent i = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ // Make sure disable/enable cycle works with no scanner (no crashing).
+ i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
+ mWifiTracker.mReceiver.onReceive(mContext, i);
+ i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_ENABLED);
+ mWifiTracker.mReceiver.onReceive(mContext, i);
+
+ Mockito.when(mWifiManager.isWifiEnabled()).thenReturn(false);
+ i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
+ mWifiTracker.mReceiver.onReceive(mContext, i);
+ // Now enable scanning while wifi is off, it shouldn't start.
+ mWifiTracker.resumeScanning();
+ assertFalse(mWifiTracker.mScanner.isScanning());
+
+ // Turn on wifi and make sure scanning starts.
+ i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_ENABLED);
+ mWifiTracker.mReceiver.onReceive(mContext, i);
+ assertTrue(mWifiTracker.mScanner.isScanning());
+ }
+
private String[] generateTestNetworks(List<WifiConfiguration> wifiConfigs,
List<ScanResult> scanResults, boolean connectedIsEphemeral) {
String[] expectedSsids = new String[NUM_NETWORKS];
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 6a05af1..06e26bd 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -28,8 +28,8 @@
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;
+import android.media.AudioSystem;
import android.media.AudioManager;
-import android.media.AudioService;
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Environment;
@@ -568,7 +568,7 @@
stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
+ " VALUES(?,?);");
loadSetting(stmt, Settings.System.VOLUME_BLUETOOTH_SCO,
- AudioService.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO));
+ AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO));
db.setTransactionSuccessful();
} finally {
db.endTransaction();
@@ -2051,11 +2051,11 @@
int vibrateSetting = getIntValueFromSystem(db, Settings.System.VIBRATE_ON, 0);
// If the ringer vibrate value is invalid, set it to the default
if ((vibrateSetting & 3) == AudioManager.VIBRATE_SETTING_OFF) {
- vibrateSetting = AudioService.getValueForVibrateSetting(0,
+ vibrateSetting = AudioSystem.getValueForVibrateSetting(0,
AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_ONLY_SILENT);
}
// Apply the same setting to the notification vibrate value
- vibrateSetting = AudioService.getValueForVibrateSetting(vibrateSetting,
+ vibrateSetting = AudioSystem.getValueForVibrateSetting(vibrateSetting,
AudioManager.VIBRATE_TYPE_NOTIFICATION, vibrateSetting);
SQLiteStatement stmt = null;
@@ -2199,25 +2199,25 @@
+ " VALUES(?,?);");
loadSetting(stmt, Settings.System.VOLUME_MUSIC,
- AudioService.getDefaultStreamVolume(AudioManager.STREAM_MUSIC));
+ AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_MUSIC));
loadSetting(stmt, Settings.System.VOLUME_RING,
- AudioService.getDefaultStreamVolume(AudioManager.STREAM_RING));
+ AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_RING));
loadSetting(stmt, Settings.System.VOLUME_SYSTEM,
- AudioService.getDefaultStreamVolume(AudioManager.STREAM_SYSTEM));
+ AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_SYSTEM));
loadSetting(
stmt,
Settings.System.VOLUME_VOICE,
- AudioService.getDefaultStreamVolume(AudioManager.STREAM_VOICE_CALL));
+ AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_VOICE_CALL));
loadSetting(stmt, Settings.System.VOLUME_ALARM,
- AudioService.getDefaultStreamVolume(AudioManager.STREAM_ALARM));
+ AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_ALARM));
loadSetting(
stmt,
Settings.System.VOLUME_NOTIFICATION,
- AudioService.getDefaultStreamVolume(AudioManager.STREAM_NOTIFICATION));
+ AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_NOTIFICATION));
loadSetting(
stmt,
Settings.System.VOLUME_BLUETOOTH_SCO,
- AudioService.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO));
+ AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO));
// By default:
// - ringtones, notification, system and music streams are affected by ringer mode
@@ -2236,7 +2236,7 @@
ringerModeAffectedStreams);
loadSetting(stmt, Settings.System.MUTE_STREAMS_AFFECTED,
- AudioService.DEFAULT_MUTE_STREAMS_AFFECTED);
+ AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED);
} finally {
if (stmt != null) stmt.close();
}
@@ -2256,10 +2256,10 @@
// Vibrate on by default for ringer, on for notification
int vibrate = 0;
- vibrate = AudioService.getValueForVibrateSetting(vibrate,
+ vibrate = AudioSystem.getValueForVibrateSetting(vibrate,
AudioManager.VIBRATE_TYPE_NOTIFICATION,
AudioManager.VIBRATE_SETTING_ONLY_SILENT);
- vibrate |= AudioService.getValueForVibrateSetting(vibrate,
+ vibrate |= AudioSystem.getValueForVibrateSetting(vibrate,
AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_ONLY_SILENT);
loadSetting(stmt, Settings.System.VIBRATE_ON, vibrate);
} finally {
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 42b50d4..8a73fca 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -244,10 +244,10 @@
<bool name="doze_pulse_on_notifications">true</bool>
<!-- Doze: when to pulse after a buzzworthy notification arrives -->
- <string name="doze_pulse_schedule" translatable="false">1s,10s,30s,60s,120s</string>
+ <string name="doze_pulse_schedule" translatable="false">1s,10s,30s,60s</string>
<!-- Doze: maximum number of times the notification pulse schedule can be reset -->
- <integer name="doze_pulse_schedule_resets">3</integer>
+ <integer name="doze_pulse_schedule_resets">2</integer>
<!-- Doze: duration to avoid false pickup gestures triggered by notification vibrations -->
<integer name="doze_pickup_vibration_threshold">2000</integer>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 3b99af1..ca54349 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1181,14 +1181,15 @@
}
if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
- final boolean allowed = 0 != Settings.Secure.getIntForUser(
+ final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
userHandle);
final boolean allowedByDpm = (dpmFlags
& DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
- mUsersAllowingPrivateNotifications.append(userHandle, allowed && allowedByDpm);
+ final boolean allowed = allowedByUser && allowedByDpm;
+ mUsersAllowingPrivateNotifications.append(userHandle, allowed);
return allowed;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 600b750..0e21457 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -31,6 +31,7 @@
void setUserId(int userId);
boolean isZenAvailable();
ComponentName getEffectsSuppressor();
+ boolean isCountdownConditionSupported();
public static class Callback {
public void onZenChanged(int zen) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 37ed7d8..dbdb578 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -169,6 +169,12 @@
return NotificationManager.from(mContext).getEffectsSuppressor();
}
+ @Override
+ public boolean isCountdownConditionSupported() {
+ return NotificationManager.from(mContext)
+ .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH);
+ }
+
private void fireNextAlarmChanged() {
for (Callback cb : mCallbacks) {
cb.onNextAlarmChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 19a631a..31264ee 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -37,7 +37,6 @@
import android.graphics.drawable.ColorDrawable;
import android.media.AudioAttributes;
import android.media.AudioManager;
-import android.media.AudioService;
import android.media.AudioSystem;
import android.media.RingtoneManager;
import android.media.ToneGenerator;
@@ -88,7 +87,7 @@
private static final String TAG = "VolumePanel";
private static boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
- private static final int PLAY_SOUND_DELAY = AudioService.PLAY_SOUND_DELAY;
+ private static final int PLAY_SOUND_DELAY = AudioSystem.PLAY_SOUND_DELAY;
/**
* The delay before vibrating. This small period exists so if the user is
@@ -351,6 +350,17 @@
};
}
+ protected LayoutParams getDialogLayoutParams(Window window, Resources res) {
+ final LayoutParams lp = window.getAttributes();
+ lp.token = null;
+ lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
+ lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL;
+ lp.format = PixelFormat.TRANSLUCENT;
+ lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation;
+ lp.setTitle(TAG);
+ return lp;
+ }
+
public VolumePanel(Context context, ZenModeController zenController) {
mTag = String.format("%s.%08x", TAG, hashCode());
mContext = context;
@@ -409,14 +419,7 @@
mDialog.create();
- final LayoutParams lp = window.getAttributes();
- lp.token = null;
- lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
- lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL;
- lp.format = PixelFormat.TRANSLUCENT;
- lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation;
- lp.setTitle(TAG);
- window.setAttributes(lp);
+ window.setAttributes(getDialogLayoutParams(window, res));
updateWidth();
@@ -1012,7 +1015,7 @@
}
private static String streamToString(int stream) {
- return AudioService.streamToString(stream);
+ return AudioSystem.streamToString(stream);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index d40a2c0..5726fa7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -19,7 +19,6 @@
import android.animation.LayoutTransition;
import android.animation.LayoutTransition.TransitionListener;
import android.app.ActivityManager;
-import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -85,10 +84,6 @@
private final int mSubheadWarningColor;
private final int mSubheadColor;
private final Interpolator mInterpolator;
- private final int mMaxConditions;
- private final int mMaxOptionalConditions;
- private final boolean mCountdownConditionSupported;
- private final int mFirstConditionIndex;
private final TransitionHelper mTransitionHelper = new TransitionHelper();
private final Uri mForeverId;
@@ -103,6 +98,10 @@
private Callback mCallback;
private ZenModeController mController;
+ private boolean mCountdownConditionSupported;
+ private int mMaxConditions;
+ private int mMaxOptionalConditions;
+ private int mFirstConditionIndex;
private boolean mRequestingConditions;
private Condition mExitCondition;
private String mExitConditionText;
@@ -127,14 +126,6 @@
mSubheadColor = res.getColor(R.color.qs_subhead);
mInterpolator = AnimationUtils.loadInterpolator(mContext,
com.android.internal.R.interpolator.fast_out_slow_in);
- mCountdownConditionSupported = NotificationManager.from(mContext)
- .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH);
- final int countdownDelta = mCountdownConditionSupported ? 1 : 0;
- mFirstConditionIndex = COUNTDOWN_CONDITION_INDEX + countdownDelta;
- final int minConditions = 1 /*forever*/ + countdownDelta;
- mMaxConditions = MathUtils.constrain(res.getInteger(R.integer.zen_mode_max_conditions),
- minConditions, 100);
- mMaxOptionalConditions = mMaxConditions - minConditions;
mForeverId = Condition.newId(mContext).appendPath("forever").build();
if (DEBUG) Log.d(mTag, "new ZenModePanel");
}
@@ -192,9 +183,6 @@
Interaction.register(mMoreSettings, mInteractionCallback);
mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions);
- for (int i = 0; i < mMaxConditions; i++) {
- mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
- }
setLayoutTransition(newLayoutTransition(mTransitionHelper));
}
@@ -306,6 +294,16 @@
public void init(ZenModeController controller) {
mController = controller;
+ mCountdownConditionSupported = mController.isCountdownConditionSupported();
+ final int countdownDelta = mCountdownConditionSupported ? 1 : 0;
+ mFirstConditionIndex = COUNTDOWN_CONDITION_INDEX + countdownDelta;
+ final int minConditions = 1 /*forever*/ + countdownDelta;
+ mMaxConditions = MathUtils.constrain(mContext.getResources()
+ .getInteger(R.integer.zen_mode_max_conditions), minConditions, 100);
+ mMaxOptionalConditions = mMaxConditions - minConditions;
+ for (int i = 0; i < mMaxConditions; i++) {
+ mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
+ }
setExitCondition(mController.getExitCondition());
refreshExitConditionText();
mSessionZen = getSelectedZen(-1);
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
index c6b76f1..74391eb 100644
--- a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
+++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
@@ -72,16 +72,22 @@
@Override
public String resolvePacFile(String host, String url) throws RemoteException {
try {
+ if (host == null) {
+ throw new IllegalArgumentException("The host must not be null");
+ }
+ if (url == null) {
+ throw new IllegalArgumentException("The URL must not be null");
+ }
// Check for characters that could be used for an injection attack.
new URL(url);
for (char c : host.toCharArray()) {
if (!Character.isLetterOrDigit(c) && (c != '.') && (c != '-')) {
- throw new RemoteException("Invalid host was passed");
+ throw new IllegalArgumentException("Invalid host was passed");
}
}
return mPacNative.makeProxyRequest(url, host);
} catch (MalformedURLException e) {
- throw new RemoteException("Invalid URL was passed");
+ throw new IllegalArgumentException("Invalid URL was passed");
}
}
diff --git a/policy/Android.mk b/policy/Android.mk
deleted file mode 100644
index 47d8fb8..0000000
--- a/policy/Android.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# the library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE := android.policy
-
-include $(BUILD_JAVA_LIBRARY)
-
-# additionally, build unit tests in a separate .apk
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/policy/src/com/android/internal/policy/impl/Policy.java b/policy/src/com/android/internal/policy/impl/Policy.java
deleted file mode 100644
index 42bfc5f..0000000
--- a/policy/src/com/android/internal/policy/impl/Policy.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-import android.util.Log;
-import android.view.FallbackEventHandler;
-import android.view.LayoutInflater;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-import com.android.internal.policy.IPolicy;
-
-/**
- * {@hide}
- */
-
-// Simple implementation of the policy interface that spawns the right
-// set of objects
-public class Policy implements IPolicy {
- private static final String TAG = "PhonePolicy";
-
- private static final String[] preload_classes = {
- "com.android.internal.policy.impl.PhoneLayoutInflater",
- "com.android.internal.policy.impl.PhoneWindow",
- "com.android.internal.policy.impl.PhoneWindow$1",
- "com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback",
- "com.android.internal.policy.impl.PhoneWindow$DecorView",
- "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
- "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
- };
-
- static {
- // For performance reasons, preload some policy specific classes when
- // the policy gets loaded.
- for (String s : preload_classes) {
- try {
- Class.forName(s);
- } catch (ClassNotFoundException ex) {
- Log.e(TAG, "Could not preload class for phone policy: " + s);
- }
- }
- }
-
- public Window makeNewWindow(Context context) {
- return new PhoneWindow(context);
- }
-
- public LayoutInflater makeNewLayoutInflater(Context context) {
- return new PhoneLayoutInflater(context);
- }
-
- public WindowManagerPolicy makeNewWindowManager() {
- return new PhoneWindowManager();
- }
-
- public FallbackEventHandler makeNewFallbackEventHandler(Context context) {
- return new PhoneFallbackEventHandler(context);
- }
-}
diff --git a/policy/src/com/android/internal/policy/impl/package.html b/policy/src/com/android/internal/policy/impl/package.html
deleted file mode 100644
index c9f96a6..0000000
--- a/policy/src/com/android/internal/policy/impl/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<body>
-
-{@hide}
-
-</body>
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index e979a1be..4af6688 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -58,15 +58,13 @@
Allocation mAdaptedAllocation;
int mSize;
- boolean mConstrainedLOD;
- boolean mConstrainedFace;
- boolean mConstrainedY;
- boolean mConstrainedZ;
boolean mReadAllowed = true;
boolean mWriteAllowed = true;
+ int mSelectedX;
int mSelectedY;
int mSelectedZ;
int mSelectedLOD;
+ int mSelectedArray[];
Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X;
int mCurrentDimX;
diff --git a/rs/java/android/renderscript/AllocationAdapter.java b/rs/java/android/renderscript/AllocationAdapter.java
index 3522a52..9e28f7c 100644
--- a/rs/java/android/renderscript/AllocationAdapter.java
+++ b/rs/java/android/renderscript/AllocationAdapter.java
@@ -21,76 +21,20 @@
*
**/
public class AllocationAdapter extends Allocation {
- AllocationAdapter(long id, RenderScript rs, Allocation alloc) {
+ Type mWindow;
+
+ AllocationAdapter(long id, RenderScript rs, Allocation alloc, Type t) {
super(id, rs, alloc.mType, alloc.mUsage);
mAdaptedAllocation = alloc;
+ mWindow = t;
}
+ /*
long getID(RenderScript rs) {
throw new RSInvalidStateException(
"This operation is not supported with adapters at this time.");
}
-
- /**
- * @hide
- */
- public void subData(int xoff, FieldPacker fp) {
- super.setFromFieldPacker(xoff, fp);
- }
- /**
- * @hide
- */
- public void subElementData(int xoff, int component_number, FieldPacker fp) {
- super.setFromFieldPacker(xoff, component_number, fp);
- }
- /**
- * @hide
- */
- public void subData1D(int off, int count, int[] d) {
- super.copy1DRangeFrom(off, count, d);
- }
- /**
- * @hide
- */
- public void subData1D(int off, int count, short[] d) {
- super.copy1DRangeFrom(off, count, d);
- }
- /**
- * @hide
- */
- public void subData1D(int off, int count, byte[] d) {
- super.copy1DRangeFrom(off, count, d);
- }
- /**
- * @hide
- */
- public void subData1D(int off, int count, float[] d) {
- super.copy1DRangeFrom(off, count, d);
- }
- /**
- * @hide
- */
- public void subData2D(int xoff, int yoff, int w, int h, int[] d) {
- super.copy2DRangeFrom(xoff, yoff, w, h, d);
- }
- /**
- * @hide
- */
- public void subData2D(int xoff, int yoff, int w, int h, float[] d) {
- super.copy2DRangeFrom(xoff, yoff, w, h, d);
- }
- /**
- * @hide
- */
- public void readData(int[] d) {
- super.copyTo(d);
- }
- /**
- * @hide
- */
- public void readData(float[] d) {
- super.copyTo(d);
- }
+ */
void initLOD(int lod) {
if (lod < 0) {
@@ -125,6 +69,26 @@
mSelectedZ = 0;
}
+ private void updateOffsets() {
+ int a1 = 0, a2 = 0, a3 = 0, a4 = 0;
+
+ if (mSelectedArray.length > 0) {
+ a1 = mSelectedArray[0];
+ }
+ if (mSelectedArray.length > 1) {
+ a2 = mSelectedArray[2];
+ }
+ if (mSelectedArray.length > 2) {
+ a3 = mSelectedArray[2];
+ }
+ if (mSelectedArray.length > 3) {
+ a4 = mSelectedArray[3];
+ }
+ mRS.nAllocationAdapterOffset(getID(mRS), mSelectedX, mSelectedY, mSelectedZ,
+ mSelectedLOD, mSelectedFace.mID, a1, a2, a3, a4);
+
+ }
+
/**
* Set the active LOD. The LOD must be within the range for the
* type being adapted. The base allocation must have mipmaps.
@@ -138,11 +102,13 @@
if (!mAdaptedAllocation.getType().hasMipmaps()) {
throw new RSInvalidStateException("Cannot set LOD when the allocation type does not include mipmaps.");
}
- if (!mConstrainedLOD) {
+ if (mWindow.hasMipmaps()) {
throw new RSInvalidStateException("Cannot set LOD when the adapter includes mipmaps.");
}
initLOD(lod);
+ mSelectedLOD = lod;
+ updateOffsets();
}
/**
@@ -155,14 +121,38 @@
if (!mAdaptedAllocation.getType().hasFaces()) {
throw new RSInvalidStateException("Cannot set Face when the allocation type does not include faces.");
}
- if (!mConstrainedFace) {
- throw new RSInvalidStateException("Cannot set LOD when the adapter includes mipmaps.");
+ if (mWindow.hasFaces()) {
+ throw new RSInvalidStateException("Cannot set face when the adapter includes faces.");
}
if (cf == null) {
throw new RSIllegalArgumentException("Cannot set null face.");
}
mSelectedFace = cf;
+ updateOffsets();
+ }
+
+
+ /**
+ * @hide
+ * Set the active X. The x value must be within the range for
+ * the allocation being adapted.
+ *
+ * @param x The x to make active.
+ */
+ public void setX(int x) {
+ if (mAdaptedAllocation.getType().getX() <= x) {
+ throw new RSInvalidStateException("Cannot set X greater than dimension of allocation.");
+ }
+ if (mWindow.getX() == mAdaptedAllocation.getType().getX()) {
+ throw new RSInvalidStateException("Cannot set X when the adapter includes X.");
+ }
+ if ((mWindow.getX() + x) >= mAdaptedAllocation.getType().getX()) {
+ throw new RSInvalidStateException("Cannot set (X + window) which would be larger than dimension of allocation.");
+ }
+
+ mSelectedX = x;
+ updateOffsets();
}
/**
@@ -179,11 +169,15 @@
if (mAdaptedAllocation.getType().getY() <= y) {
throw new RSInvalidStateException("Cannot set Y greater than dimension of allocation.");
}
- if (!mConstrainedY) {
+ if (mWindow.getY() == mAdaptedAllocation.getType().getY()) {
throw new RSInvalidStateException("Cannot set Y when the adapter includes Y.");
}
+ if ((mWindow.getY() + y) >= mAdaptedAllocation.getType().getY()) {
+ throw new RSInvalidStateException("Cannot set (Y + window) which would be larger than dimension of allocation.");
+ }
mSelectedY = y;
+ updateOffsets();
}
/**
@@ -200,35 +194,112 @@
if (mAdaptedAllocation.getType().getZ() <= z) {
throw new RSInvalidStateException("Cannot set Z greater than dimension of allocation.");
}
- if (!mConstrainedZ) {
+ if (mWindow.getZ() == mAdaptedAllocation.getType().getZ()) {
throw new RSInvalidStateException("Cannot set Z when the adapter includes Z.");
}
+ if ((mWindow.getZ() + z) >= mAdaptedAllocation.getType().getZ()) {
+ throw new RSInvalidStateException("Cannot set (Z + window) which would be larger than dimension of allocation.");
+ }
mSelectedZ = z;
+ updateOffsets();
+ }
+
+ /**
+ * @hide
+ */
+ public void setArray(int arrayNum, int arrayVal) {
+ if (mAdaptedAllocation.getType().getArray(arrayNum) == 0) {
+ throw new RSInvalidStateException("Cannot set arrayNum when the allocation type does not include arrayNum dim.");
+ }
+ if (mAdaptedAllocation.getType().getArray(arrayNum) <= arrayVal) {
+ throw new RSInvalidStateException("Cannot set arrayNum greater than dimension of allocation.");
+ }
+ if (mWindow.getArray(arrayNum) == mAdaptedAllocation.getType().getArray(arrayNum)) {
+ throw new RSInvalidStateException("Cannot set arrayNum when the adapter includes arrayNum.");
+ }
+ if ((mWindow.getArray(arrayNum) + arrayVal) >= mAdaptedAllocation.getType().getArray(arrayNum)) {
+ throw new RSInvalidStateException("Cannot set (arrayNum + window) which would be larger than dimension of allocation.");
+ }
+
+ mSelectedArray[arrayNum] = arrayVal;
+ updateOffsets();
}
static public AllocationAdapter create1D(RenderScript rs, Allocation a) {
rs.validate();
- AllocationAdapter aa = new AllocationAdapter(0, rs, a);
- aa.mConstrainedLOD = true;
- aa.mConstrainedFace = true;
- aa.mConstrainedY = true;
- aa.mConstrainedZ = true;
- aa.initLOD(0);
- return aa;
+ Type t = Type.createX(rs, a.getElement(), a.getType().getX());
+ return createTyped(rs, a, t);
}
+
static public AllocationAdapter create2D(RenderScript rs, Allocation a) {
rs.validate();
- AllocationAdapter aa = new AllocationAdapter(0, rs, a);
- aa.mConstrainedLOD = true;
- aa.mConstrainedFace = true;
- aa.mConstrainedY = false;
- aa.mConstrainedZ = true;
- aa.initLOD(0);
- return aa;
+ Type t = Type.createXY(rs, a.getElement(), a.getType().getX(), a.getType().getY());
+ return createTyped(rs, a, t);
}
+ /**
+ * @hide
+ *
+ * Create an arbitrary window into the base allocation
+ * The type describes the shape of the window.
+ *
+ * Any dimensions present in the type must be equal or smaller
+ * to the dimensions in the source allocation. A dimension
+ * present in the allocation that is not present in the type
+ * will be constrained away with the selectors
+ *
+ * If a dimension is present in the type and allcation one of
+ * two things will happen
+ *
+ * If the type is smaller than the allocation a window will be
+ * created, the selected value in the adapter for that dimension
+ * will act as the base address and the type will describe the
+ * size of the view starting at that point.
+ *
+ * If the type and allocation dimension are of the same size
+ * then setting the selector for the dimension will be an error.
+ */
+ static public AllocationAdapter createTyped(RenderScript rs, Allocation a, Type t) {
+ rs.validate();
+
+ if (a.mAdaptedAllocation != null) {
+ throw new RSInvalidStateException("Adapters cannot be nested.");
+ }
+
+ if (!a.getType().getElement().equals(t.getElement())) {
+ throw new RSInvalidStateException("Element must match Allocation type.");
+ }
+
+ if (t.hasFaces() || t.hasMipmaps()) {
+ throw new RSInvalidStateException("Adapters do not support window types with Mipmaps or Faces.");
+ }
+
+ Type at = a.getType();
+ if ((t.getX() > at.getX()) ||
+ (t.getY() > at.getY()) ||
+ (t.getZ() > at.getZ()) ||
+ (t.getArrayCount() > at.getArrayCount())) {
+
+ throw new RSInvalidStateException("Type cannot have dimension larger than the source allocation.");
+ }
+
+ if (t.getArrayCount() > 0) {
+ for (int i = 0; i < t.getArray(i); i++) {
+ if (t.getArray(i) > at.getArray(i)) {
+ throw new RSInvalidStateException("Type cannot have dimension larger than the source allocation.");
+ }
+ }
+ }
+
+ // Create the object
+ long id = rs.nAllocationAdapterCreate(a.getID(rs), t.getID(rs));
+ if (id == 0) {
+ throw new RSRuntimeException("AllocationAdapter creation failed.");
+ }
+ return new AllocationAdapter(id, rs, a, t);
+ }
/**
* Override the Allocation resize. Resizing adapters is not
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 94aa857..5e150e9 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -591,6 +591,20 @@
rsnAllocationResize1D(mContext, id, dimX);
}
+ native long rsnAllocationAdapterCreate(long con, long allocId, long typeId);
+ synchronized long nAllocationAdapterCreate(long allocId, long typeId) {
+ validate();
+ return rsnAllocationAdapterCreate(mContext, allocId, typeId);
+ }
+
+ native void rsnAllocationAdapterOffset(long con, long id, int x, int y, int z,
+ int mip, int face, int a1, int a2, int a3, int a4);
+ synchronized void nAllocationAdapterOffset(long id, int x, int y, int z,
+ int mip, int face, int a1, int a2, int a3, int a4) {
+ validate();
+ rsnAllocationAdapterOffset(mContext, id, x, y, z, mip, face, a1, a2, a3, a4);
+ }
+
native long rsnFileA3DCreateFromAssetStream(long con, long assetStream);
synchronized long nFileA3DCreateFromAssetStream(long assetStream) {
validate();
diff --git a/rs/java/android/renderscript/Type.java b/rs/java/android/renderscript/Type.java
index 98aeaa9..a58e42c 100644
--- a/rs/java/android/renderscript/Type.java
+++ b/rs/java/android/renderscript/Type.java
@@ -52,6 +52,9 @@
int mDimYuv;
int mElementCount;
Element mElement;
+ int mArrays[];
+
+ static final int mMaxArrays = 4;
public enum CubemapFace {
POSITIVE_X (0),
@@ -146,6 +149,30 @@
return mElementCount;
}
+ /**
+ * @hide
+ */
+ public int getArray(int dim) {
+ if ((dim < 0) || (dim >= mMaxArrays)) {
+ throw new RSIllegalArgumentException("Array dimension out of range.");
+ }
+
+ if (mArrays == null || dim >= mArrays.length) {
+ // Dimension in range but no array for that dimension allocated
+ return 0;
+ }
+
+ return mArrays[dim];
+ }
+
+ /**
+ * @hide
+ */
+ public int getArrayCount() {
+ if (mArrays != null) return mArrays.length;
+ return 0;
+ }
+
void calcElementCount() {
boolean hasLod = hasMipmaps();
int x = getX();
@@ -180,6 +207,13 @@
count += x * y * z * faces;
}
+
+ if (mArrays != null) {
+ for (int ct = 0; ct < mArrays.length; ct++) {
+ count *= mArrays[ct];
+ }
+ }
+
mElementCount = count;
}
@@ -296,6 +330,7 @@
boolean mDimMipmaps;
boolean mDimFaces;
int mYuv;
+ int[] mArray = new int[mMaxArrays];
Element mElement;
@@ -341,6 +376,22 @@
return this;
}
+ /**
+ * @hide
+ *
+ * @param dim
+ * @param value
+ *
+ * @return Builder
+ */
+ public Builder setArray(int dim, int value) {
+ if(dim < 0 || dim >= mMaxArrays) {
+ throw new RSIllegalArgumentException("Array dimension out of range.");
+ }
+ mArray[dim] = value;
+ return this;
+ }
+
public Builder setMipmaps(boolean value) {
mDimMipmaps = value;
return this;
@@ -405,6 +456,16 @@
}
}
+ int[] arrays = null;
+ for (int ct = mMaxArrays - 1; ct >= 0; ct--) {
+ if (mArray[ct] != 0 && arrays == null) {
+ arrays = new int[ct];
+ }
+ if ((mArray[ct] == 0) && (arrays != null)) {
+ throw new RSInvalidStateException("Array dimensions must be contigous from 0.");
+ }
+ }
+
long id = mRS.nTypeCreate(mElement.getID(mRS),
mDimX, mDimY, mDimZ, mDimMipmaps, mDimFaces, mYuv);
Type t = new Type(id, mRS);
@@ -415,6 +476,7 @@
t.mDimMipmaps = mDimMipmaps;
t.mDimFaces = mDimFaces;
t.mDimYuv = mYuv;
+ t.mArrays = arrays;
t.calcElementCount();
return t;
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index b25dd41..198cabe 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -1047,6 +1047,37 @@
rsAllocationResize1D((RsContext)con, (RsAllocation)alloc, dimX);
}
+
+static jlong
+nAllocationAdapterCreate(JNIEnv *_env, jobject _this, jlong con, jlong basealloc, jlong type)
+{
+ if (kLogApi) {
+ ALOGD("nAllocationAdapterCreate, con(%p), base(%p), type(%p)",
+ (RsContext)con, (RsAllocation)basealloc, (RsElement)type);
+ }
+ return (jlong)(uintptr_t) rsAllocationAdapterCreate((RsContext)con, (RsType)type,
+ (RsAllocation)basealloc);
+
+}
+
+static void
+nAllocationAdapterOffset(JNIEnv *_env, jobject _this, jlong con, jlong alloc,
+ jint x, jint y, jint z, jint face, jint lod,
+ jint a1, jint a2, jint a3, jint a4)
+{
+ uint32_t params[] = {
+ (uint32_t)x, (uint32_t)y, (uint32_t)z, (uint32_t)face,
+ (uint32_t)lod, (uint32_t)a1, (uint32_t)a2, (uint32_t)a3, (uint32_t)a4
+ };
+ if (kLogApi) {
+ ALOGD("nAllocationAdapterOffset, con(%p), alloc(%p), x(%i), y(%i), z(%i), face(%i), lod(%i), arrays(%i %i %i %i)",
+ (RsContext)con, (RsAllocation)alloc, x, y, z, face, lod, a1, a2, a3, a4);
+ }
+ rsAllocationAdapterOffset((RsContext)con, (RsAllocation)alloc,
+ params, sizeof(params));
+}
+
+
// -----------------------------------
static jlong
@@ -2028,6 +2059,9 @@
{"rsnAllocationResize1D", "(JJI)V", (void*)nAllocationResize1D },
{"rsnAllocationGenerateMipmaps", "(JJ)V", (void*)nAllocationGenerateMipmaps },
+{"rsnAllocationAdapterCreate", "(JJJ)J", (void*)nAllocationAdapterCreate },
+{"rsnAllocationAdapterOffset", "(JJIIIIIIIII)V", (void*)nAllocationAdapterOffset },
+
{"rsnScriptBindAllocation", "(JJJI)V", (void*)nScriptBindAllocation },
{"rsnScriptSetTimeZone", "(JJ[B)V", (void*)nScriptSetTimeZone },
{"rsnScriptInvoke", "(JJI)V", (void*)nScriptInvoke },
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index c1e4994..4d7ebed 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1865,7 +1865,8 @@
boolean tryBindTransport(ServiceInfo info) {
try {
PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0);
- if ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+ if ((packInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ != 0) {
return bindTransport(info);
} else {
Slog.w(TAG, "Transport package " + info.packageName + " not privileged");
@@ -3196,7 +3197,7 @@
final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
final boolean sendApk = mIncludeApks
&& !isSharedStorage
- && ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
+ && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0)
&& ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
(app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 5c45201..1a0fa34 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -9,6 +9,6 @@
java/com/android/server/EventLogTags.logtags \
java/com/android/server/am/EventLogTags.logtags
-LOCAL_JAVA_LIBRARIES := android.policy telephony-common
+LOCAL_JAVA_LIBRARIES := telephony-common
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 42a5195..17b4939 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -813,7 +813,8 @@
.getApplicationInfo(packageName, 0, UserHandle.getUserId(uid));
if (appInfo != null) {
pkgUid = appInfo.uid;
- isPrivileged = (appInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+ isPrivileged = (appInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
} else {
if ("media".equals(packageName)) {
pkgUid = Process.MEDIA_UID;
@@ -996,7 +997,8 @@
ApplicationInfo appInfo = ActivityThread.getPackageManager()
.getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
if (appInfo != null) {
- isPrivileged = (appInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+ isPrivileged = (appInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
} else {
// Could not load data, don't add to cache so it will be loaded later.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 944f1c0..551a5dc 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -832,6 +832,19 @@
}
};
+ private Network[] getVpnUnderlyingNetworks(int uid) {
+ if (!mLockdownEnabled) {
+ int user = UserHandle.getUserId(uid);
+ synchronized (mVpns) {
+ Vpn vpn = mVpns.get(user);
+ if (vpn != null && vpn.appliesToUid(uid)) {
+ return vpn.getUnderlyingNetworks();
+ }
+ }
+ }
+ return null;
+ }
+
private NetworkState getUnfilteredActiveNetworkState(int uid) {
NetworkInfo info = null;
LinkProperties lp = null;
@@ -841,25 +854,17 @@
NetworkAgentInfo nai = mNetworkForRequestId.get(mDefaultRequest.requestId);
- if (!mLockdownEnabled) {
- int user = UserHandle.getUserId(uid);
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(user);
- if (vpn != null && vpn.appliesToUid(uid)) {
- // getUnderlyingNetworks() returns:
- // null => the VPN didn't specify anything, so we use the default.
- // empty array => the VPN explicitly said "no default network".
- // non-empty array => the VPN specified one or more default networks; we use the
- // first one.
- Network[] networks = vpn.getUnderlyingNetworks();
- if (networks != null) {
- if (networks.length > 0) {
- nai = getNetworkAgentInfoForNetwork(networks[0]);
- } else {
- nai = null;
- }
- }
- }
+ final Network[] networks = getVpnUnderlyingNetworks(uid);
+ if (networks != null) {
+ // getUnderlyingNetworks() returns:
+ // null => there was no VPN, or the VPN didn't specify anything, so we use the default.
+ // empty array => the VPN explicitly said "no default network".
+ // non-empty array => the VPN specified one or more default networks; we use the
+ // first one.
+ if (networks.length > 0) {
+ nai = getNetworkAgentInfoForNetwork(networks[0]);
+ } else {
+ nai = null;
}
}
@@ -990,6 +995,15 @@
public NetworkInfo getNetworkInfo(int networkType) {
enforceAccessPermission();
final int uid = Binder.getCallingUid();
+ if (getVpnUnderlyingNetworks(uid) != null) {
+ // A VPN is active, so we may need to return one of its underlying networks. This
+ // information is not available in LegacyTypeTracker, so we have to get it from
+ // getUnfilteredActiveNetworkState.
+ NetworkState state = getUnfilteredActiveNetworkState(uid);
+ if (state.networkInfo != null && state.networkInfo.getType() == networkType) {
+ return getFilteredNetworkInfo(state.networkInfo, state.linkProperties, uid);
+ }
+ }
NetworkState state = getFilteredNetworkState(networkType, uid);
return state.networkInfo;
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index e52b2bf..9339b35 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3083,7 +3083,8 @@
try {
PackageInfo packageInfo = userPackageManager.getPackageInfo(name, 0 /* flags */);
if (packageInfo != null
- && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+ && (packageInfo.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
return true;
}
} catch (PackageManager.NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7a493c6..1eec141 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3731,6 +3731,10 @@
if (r == null) {
return;
}
+ if (r.task != null && r.task.mResizeable) {
+ // Fixed screen orientation isn't supported with resizeable activities.
+ return;
+ }
final long origId = Binder.clearCallingIdentity();
mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
Configuration config = mWindowManager.updateOrientationFromAppTokens(
@@ -6247,7 +6251,7 @@
"setProcessForeground()");
synchronized(this) {
boolean changed = false;
-
+
synchronized (mPidsSelfLocked) {
ProcessRecord pr = mPidsSelfLocked.get(pid);
if (pr == null && isForeground) {
@@ -6283,7 +6287,7 @@
}
}
}
-
+
if (changed) {
updateOomAdjLocked();
}
@@ -6378,7 +6382,7 @@
* permission is automatically denied. (Internally a null permission
* string is used when calling {@link #checkComponentPermission} in cases
* when only uid-based security is needed.)
- *
+ *
* This can be called with or without the global lock held.
*/
@Override
@@ -6655,12 +6659,12 @@
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Checking grant " + targetPkg + " permission to " + grantUri);
}
-
+
final IPackageManager pm = AppGlobals.getPackageManager();
// If this is not a content: uri, we can't do anything with it.
if (!ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Can't grant URI permission for non-content URI: " + grantUri);
return -1;
}
@@ -6788,7 +6792,7 @@
// to the uri, and the target doesn't. Let's now give this to
// the target.
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Granting " + targetPkg + "/" + targetUid + " permission to " + grantUri);
final String authority = grantUri.uri.getAuthority();
@@ -6990,7 +6994,7 @@
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
perm.targetUid);
if (perms != null) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Removing " + perm.targetUid + " permission to " + perm.uri);
perms.remove(perm.uri);
@@ -9120,7 +9124,7 @@
}
}
}
-
+
public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
if (providers == null) {
@@ -9703,7 +9707,7 @@
throw new SecurityException("Requires permission "
+ android.Manifest.permission.STOP_APP_SWITCHES);
}
-
+
synchronized(this) {
mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
+ APP_SWITCH_DELAY_TIME;
@@ -9713,14 +9717,14 @@
mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
}
}
-
+
public void resumeAppSwitches() {
if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
+ android.Manifest.permission.STOP_APP_SWITCHES);
}
-
+
synchronized(this) {
// Note that we don't execute any pending app switches... we will
// let those wait until either the timeout, or the next start
@@ -9728,7 +9732,7 @@
mAppSwitchesAllowedTime = 0;
}
}
-
+
boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
int callingPid, int callingUid, String name) {
if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
@@ -9756,7 +9760,7 @@
Slog.w(TAG, name + " request from " + sourceUid + " stopped");
return false;
}
-
+
public void setDebugApp(String packageName, boolean waitForDebugger,
boolean persistent) {
enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
@@ -10819,7 +10823,7 @@
}
}
}
-
+
synchronized(this) {
if (procsToKill != null) {
for (int i=procsToKill.size()-1; i>=0; i--) {
@@ -10828,20 +10832,20 @@
removeProcessLocked(proc, true, false, "system update done");
}
}
-
+
// Now that we have cleaned up any update processes, we
// are ready to start launching real processes and know that
// we won't trample on them any more.
mProcessesReady = true;
}
-
+
Slog.i(TAG, "System now ready");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
SystemClock.uptimeMillis());
synchronized(this) {
// Make sure we have no pre-ready processes sitting around.
-
+
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
ResolveInfo ri = mContext.getPackageManager()
.resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
@@ -10925,7 +10929,7 @@
} catch (RemoteException e) {
}
- if (!Build.isFingerprintConsistent()) {
+ if (!Build.isBuildConsistent()) {
Slog.e(TAG, "Build fingerprint is not consistent, warning user");
mHandler.obtainMessage(SHOW_FINGERPRINT_ERROR_MSG).sendToTarget();
}
@@ -10981,12 +10985,12 @@
startAppProblemLocked(app);
app.stopFreezingAllLocked();
}
-
+
/**
* Generate a process error record, suitable for attachment to a ProcessRecord.
- *
+ *
* @param app The ProcessRecord in which the error occurred.
- * @param condition Crashing, Application Not Responding, etc. Values are defined in
+ * @param condition Crashing, Application Not Responding, etc. Values are defined in
* ActivityManager.AppErrorStateInfo
* @param activity The activity associated with the crash, if known.
* @param shortMsg Short message describing the crash.
@@ -10995,7 +10999,7 @@
*
* @return Returns a fully-formed AppErrorStateInfo record.
*/
- private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
+ private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
@@ -12407,12 +12411,12 @@
}
}
}
-
+
if (mForegroundProcesses.size() > 0) {
synchronized (mPidsSelfLocked) {
boolean printed = false;
for (int i=0; i<mForegroundProcesses.size(); i++) {
- ProcessRecord r = mPidsSelfLocked.get(
+ ProcessRecord r = mPidsSelfLocked.get(
mForegroundProcesses.valueAt(i).pid);
if (dumpPackage != null && (r == null
|| !r.pkgList.containsKey(dumpPackage))) {
@@ -12430,7 +12434,7 @@
}
}
}
-
+
if (mPersistentStartingProcesses.size() > 0) {
if (needSep) pw.println();
needSep = true;
@@ -12448,7 +12452,7 @@
dumpProcessList(pw, this, mRemovedProcesses, " ",
"Removed Norm", "Removed PERS", dumpPackage);
}
-
+
if (mProcessesOnHold.size() > 0) {
if (needSep) pw.println();
needSep = true;
@@ -12459,7 +12463,7 @@
}
needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, dumpPackage);
-
+
if (mProcessCrashTimes.getMap().size() > 0) {
boolean printed = false;
long now = SystemClock.uptimeMillis();
@@ -12831,7 +12835,7 @@
ArrayList<String> strings;
ArrayList<Integer> objects;
boolean all;
-
+
ItemMatcher() {
all = true;
}
@@ -12916,7 +12920,7 @@
protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
int opti, boolean dumpAll) {
ArrayList<ActivityRecord> activities;
-
+
synchronized (this) {
activities = mStackSupervisor.getDumpActivitiesLocked(name);
}
@@ -13039,7 +13043,7 @@
}
needSep = true;
-
+
if (!onlyHistory && mStickyBroadcasts != null && dumpPackage == null) {
for (int user=0; user<mStickyBroadcasts.size(); user++) {
if (needSep) {
@@ -13074,7 +13078,7 @@
}
}
}
-
+
if (!onlyHistory && dumpAll) {
pw.println();
for (BroadcastQueue queue : mBroadcastQueues) {
@@ -13086,7 +13090,7 @@
needSep = true;
printedAnything = true;
}
-
+
if (!printedAnything) {
pw.println(" (nothing)");
}
@@ -13426,7 +13430,7 @@
long realtime = SystemClock.elapsedRealtime();
pw.println("Applications Graphics Acceleration Info:");
pw.println("Uptime: " + uptime + " Realtime: " + realtime);
-
+
for (int i = procs.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = procs.get(i);
if (r.thread != null) {
@@ -13651,7 +13655,7 @@
boolean isCompact = false;
boolean localOnly = false;
boolean packages = false;
-
+
int opti = 0;
while (opti < args.length) {
String opt = args[opti];
@@ -13689,7 +13693,7 @@
pw.println("Unknown argument: " + opt + "; use -h for help");
}
}
-
+
final boolean isCheckinRequest = scanArgs(args, "--checkin");
long uptime = SystemClock.uptimeMillis();
long realtime = SystemClock.elapsedRealtime();
@@ -14643,7 +14647,7 @@
}
return restart;
}
-
+
// =========================================================
// SERVICES
// =========================================================
@@ -14725,7 +14729,7 @@
return mServices.peekServiceLocked(service, resolvedType);
}
}
-
+
@Override
public boolean stopServiceToken(ComponentName className, IBinder token,
int startId) {
@@ -14948,11 +14952,11 @@
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
-
+
// =========================================================
// BACKUP AND RESTORE
// =========================================================
-
+
// Cause the target app to be launched if necessary and its backup agent
// instantiated. The backup agent will invoke backupAgentCreated() on the
// activity manager to announce its creation.
@@ -15015,7 +15019,7 @@
// mBackupAppName describe the app, so that when it binds back to the AM we
// know that it's scheduled for a backup-agent operation.
}
-
+
return true;
}
@@ -15322,7 +15326,7 @@
mReceiverResolver.removeFilter(rl.get(i));
}
}
-
+
private final void sendPackageBroadcastLocked(int cmd, String[] packages, int userId) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = mLruProcesses.get(i);
@@ -15746,10 +15750,10 @@
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
-
+
if (DEBUG_BROADCAST) Slog.v(TAG, "Enqueing broadcast: " + intent.getAction()
+ " replacePending=" + replacePending);
-
+
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
// If we are not serializing this broadcast, then send the
@@ -16014,7 +16018,7 @@
Binder.restoreCallingIdentity(origId);
}
}
-
+
// =========================================================
// INSTRUMENTATION
// =========================================================
@@ -16084,17 +16088,17 @@
return true;
}
-
+
/**
- * Report errors that occur while attempting to start Instrumentation. Always writes the
+ * Report errors that occur while attempting to start Instrumentation. Always writes the
* error to the logs, but if somebody is watching, send the report there too. This enables
* the "am" command to report errors with more information.
- *
+ *
* @param watcher The IInstrumentationWatcher. Null if there isn't one.
* @param cn The component name of the instrumentation.
* @param report The error report.
*/
- private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
+ private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
ComponentName cn, String report) {
Slog.w(TAG, report);
try {
@@ -16164,7 +16168,7 @@
// =========================================================
// CONFIGURATION
// =========================================================
-
+
public ConfigurationInfo getDeviceConfigurationInfo() {
ConfigurationInfo config = new ConfigurationInfo();
synchronized (this) {
@@ -16264,11 +16268,11 @@
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
Slog.i(TAG, "Updating configuration to: " + values);
}
-
+
EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
if (values.locale != null && !initLocale) {
- saveLocaleLocked(values.locale,
+ saveLocaleLocked(values.locale,
!values.locale.equals(mConfiguration.locale),
values.userSetLocale);
}
@@ -16284,7 +16288,7 @@
//mUsageStatsService.noteStartConfig(newConfig);
final Configuration configCopy = new Configuration(mConfiguration);
-
+
// TODO: If our config changes, should we auto dismiss any currently
// showing dialogs?
mShowDialogs = shouldShowDialogs(newConfig);
@@ -17148,7 +17152,7 @@
}
app.curRawAdj = adj;
-
+
//Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
// " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
if (adj > app.maxAdj) {
@@ -17261,7 +17265,7 @@
// whatever.
}
}
-
+
/**
* Returns true if things are idle enough to perform GCs.
*/
@@ -17275,7 +17279,7 @@
return !processingBroadcasts
&& (isSleeping() || mStackSupervisor.allResumedActivitiesIdle());
}
-
+
/**
* Perform GCs on all processes that are waiting for it, but only
* if things are idle.
@@ -17304,11 +17308,11 @@
}
}
}
-
+
scheduleAppGcsLocked();
}
}
-
+
/**
* If all looks good, perform GCs on all processes waiting for them.
*/
@@ -17326,12 +17330,12 @@
*/
final void scheduleAppGcsLocked() {
mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
-
+
if (mProcessesToGc.size() > 0) {
// Schedule a GC for the time to the next process.
ProcessRecord proc = mProcessesToGc.get(0);
Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
-
+
long when = proc.lastRequestedGc + GC_MIN_INTERVAL;
long now = SystemClock.uptimeMillis();
if (when < (now+GC_TIMEOUT)) {
@@ -17340,7 +17344,7 @@
mHandler.sendMessageAtTime(msg, when);
}
}
-
+
/**
* Add a process to the array of processes waiting to be GCed. Keeps the
* list in sorted order by the last GC time. The process can't already be
@@ -17360,7 +17364,7 @@
mProcessesToGc.add(0, proc);
}
}
-
+
/**
* Set up to ask a process to GC itself. This will either do it
* immediately, or put it on the list of processes to gc the next
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 19f6e5a..4d7305d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3730,10 +3730,19 @@
// we just want to leave the official config object now in the
// activity and do nothing else.
int stackChanges = oldStackOverride.diff(mOverrideConfig);
- if (stackChanges == 0 && !oldStackOverride.equals(mOverrideConfig)) {
- // Assume size change if diff didn't report any changes,
- // but configurations are not equal.
- stackChanges = ActivityInfo.CONFIG_SCREEN_SIZE;
+ if (stackChanges == 0) {
+ // {@link Configuration#diff} doesn't catch changes from unset values.
+ // Check for changes we care about.
+ if (oldStackOverride.orientation != mOverrideConfig.orientation) {
+ stackChanges |= ActivityInfo.CONFIG_ORIENTATION;
+ }
+ if (oldStackOverride.screenHeightDp != mOverrideConfig.screenHeightDp
+ || oldStackOverride.screenWidthDp != mOverrideConfig.screenWidthDp) {
+ stackChanges |= ActivityInfo.CONFIG_SCREEN_SIZE;
+ }
+ if (oldStackOverride.smallestScreenWidthDp != mOverrideConfig.smallestScreenWidthDp) {
+ stackChanges |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+ }
}
final int changes = oldConfig.diff(newConfig) | stackChanges;
if (changes == 0 && !r.forceNewConfig) {
@@ -3797,15 +3806,15 @@
return false;
}
- // Default case: the activity can handle this new configuration, so
- // hand it over. Note that we don't need to give it the new
- // configuration, since we always send configuration changes to all
- // process when they happen so it can just use whatever configuration
- // it last got.
+ // Default case: the activity can handle this new configuration, so hand it over.
+ // NOTE: We only forward the stack override configuration as the system level configuration
+ // changes is always sent to all processes when they happen so it can just use whatever
+ // system level configuration it last got.
if (r.app != null && r.app.thread != null) {
try {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
- r.app.thread.scheduleActivityConfigurationChanged(r.appToken);
+ r.app.thread.scheduleActivityConfigurationChanged(
+ r.appToken, new Configuration(mOverrideConfig));
} catch (RemoteException e) {
// If process died, whatever.
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 58104a8..1aa2a10 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -882,7 +882,8 @@
final long origId = Binder.clearCallingIdentity();
if (aInfo != null &&
- (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+ (aInfo.applicationInfo.privateFlags
+ &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
// This may be a heavy-weight process! Check to see if we already
// have another, different heavy-weight process running.
if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
@@ -1053,8 +1054,8 @@
aInfo = mService.getActivityInfoForUser(aInfo, userId);
if (aInfo != null &&
- (aInfo.applicationInfo.flags & ApplicationInfo.FLAG_CANT_SAVE_STATE)
- != 0) {
+ (aInfo.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
throw new IllegalArgumentException(
"FLAG_CANT_SAVE_STATE not supported here");
}
@@ -1185,7 +1186,7 @@
r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
- if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+ if ((app.info.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
// This may be a heavy-weight process! Note that the package
// manager will ensure that only activity can run in the main
// process of the .apk, which is the only thing that will be
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 36263ec..5a66f4a 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -19,6 +19,8 @@
import android.app.AlertDialog;
import android.content.Context;
import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver;
@@ -26,6 +28,7 @@
import android.widget.TextView;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
/**
* Dialog to show when a user switch it about to happen. The intent is to snapshot the screen
@@ -37,8 +40,14 @@
implements ViewTreeObserver.OnWindowShownListener {
private static final String TAG = "ActivityManagerUserSwitchingDialog";
+ // Time to wait for the onWindowShown() callback before continuing the user switch
+ private static final int WINDOW_SHOWN_TIMEOUT_MS = 3000;
+
private final ActivityManagerService mService;
private final int mUserId;
+ private static final int MSG_START_USER = 1;
+ @GuardedBy("this")
+ private boolean mStartedUser;
public UserSwitchingDialog(ActivityManagerService service, Context context,
int userId, String userName, boolean aboveSystem) {
@@ -73,15 +82,40 @@
if (decorView != null) {
decorView.getViewTreeObserver().addOnWindowShownListener(this);
}
+ // Add a timeout as a safeguard, in case a race in screen on/off causes the window
+ // callback to never come.
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_USER),
+ WINDOW_SHOWN_TIMEOUT_MS);
}
@Override
public void onWindowShown() {
// Slog.v(TAG, "onWindowShown called");
- mService.startUserInForeground(mUserId, this);
- final View decorView = getWindow().getDecorView();
- if (decorView != null) {
- decorView.getViewTreeObserver().removeOnWindowShownListener(this);
+ startUser();
+ }
+
+ void startUser() {
+ synchronized (this) {
+ if (!mStartedUser) {
+ mService.startUserInForeground(mUserId, this);
+ mStartedUser = true;
+ final View decorView = getWindow().getDecorView();
+ if (decorView != null) {
+ decorView.getViewTreeObserver().removeOnWindowShownListener(this);
+ }
+ mHandler.removeMessages(MSG_START_USER);
+ }
}
}
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_START_USER:
+ startUser();
+ break;
+ }
+ }
+ };
}
diff --git a/media/java/android/media/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
similarity index 97%
rename from media/java/android/media/AudioService.java
rename to services/core/java/com/android/server/audio/AudioService.java
index edb6923..eaece09 100644
--- a/media/java/android/media/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.media;
+package com.android.server.audio;
import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
import static android.media.AudioManager.RINGER_MODE_NORMAL;
@@ -46,8 +46,30 @@
import android.hardware.hdmi.HdmiPlaybackClient;
import android.hardware.hdmi.HdmiTvClient;
import android.hardware.usb.UsbManager;
+import android.media.AudioAttributes;
+import android.media.AudioDevicePort;
+import android.media.AudioSystem;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioManagerInternal;
+import android.media.AudioPort;
+import android.media.AudioRoutesInfo;
+import android.media.AudioSystem;
+import android.media.IAudioFocusDispatcher;
+import android.media.IAudioRoutesObserver;
+import android.media.IAudioService;
+import android.media.IRemoteControlDisplay;
+import android.media.IRingtonePlayer;
+import android.media.IVolumeController;
+import android.media.MediaPlayer;
+import android.media.SoundPool;
+import android.media.AudioAttributes.Builder;
+import android.media.AudioManagerInternal.RingerModeDelegate;
+import android.media.AudioSystem.ErrorCallback;
+import android.media.IAudioService.Stub;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
+import android.media.SoundPool.OnLoadCompleteListener;
import android.media.audiopolicy.AudioMix;
import android.media.audiopolicy.AudioPolicy;
import android.media.audiopolicy.AudioPolicyConfig;
@@ -139,14 +161,6 @@
private static final int UNMUTE_STREAM_DELAY = 350;
/**
- * The delay before playing a sound. This small period exists so the user
- * can press another key (non-volume keys, too) to have it NOT be audible.
- * <p>
- * PhoneWindow will implement this part.
- */
- public static final int PLAY_SOUND_DELAY = 300;
-
- /**
* Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
*/
private static final int FLAG_ADJUST_VOLUME = 1;
@@ -155,21 +169,15 @@
private final ContentResolver mContentResolver;
private final AppOpsManager mAppOps;
- // the platform has no specific capabilities
- public static final int PLATFORM_DEFAULT = 0;
- // the platform is voice call capable (a phone)
- public static final int PLATFORM_VOICE = 1;
- // the platform is a television or a set-top box
- public static final int PLATFORM_TELEVISION = 2;
// the platform type affects volume and silent mode behavior
private final int mPlatformType;
private boolean isPlatformVoice() {
- return mPlatformType == PLATFORM_VOICE;
+ return mPlatformType == AudioSystem.PLATFORM_VOICE;
}
private boolean isPlatformTelevision() {
- return mPlatformType == PLATFORM_TELEVISION;
+ return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
}
/** The controller for the volume UI. */
@@ -267,19 +275,6 @@
15 // STREAM_TTS
};
- private static int[] DEFAULT_STREAM_VOLUME = new int[] {
- 4, // STREAM_VOICE_CALL
- 7, // STREAM_SYSTEM
- 5, // STREAM_RING
- 11, // STREAM_MUSIC
- 6, // STREAM_ALARM
- 5, // STREAM_NOTIFICATION
- 7, // STREAM_BLUETOOTH_SCO
- 7, // STREAM_SYSTEM_ENFORCED
- 11, // STREAM_DTMF
- 11 // STREAM_TTS
- };
-
/* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
* of another stream: This avoids multiplying the volume settings for hidden
* stream types that follow other stream behavior for volume settings
@@ -346,26 +341,6 @@
private final boolean mUseFixedVolume;
- // stream names used by dumpStreamStates()
- private static final String[] STREAM_NAMES = new String[] {
- "STREAM_VOICE_CALL",
- "STREAM_SYSTEM",
- "STREAM_RING",
- "STREAM_MUSIC",
- "STREAM_ALARM",
- "STREAM_NOTIFICATION",
- "STREAM_BLUETOOTH_SCO",
- "STREAM_SYSTEM_ENFORCED",
- "STREAM_DTMF",
- "STREAM_TTS"
- };
-
- public static final int DEFAULT_MUTE_STREAMS_AFFECTED =
- (1 << AudioSystem.STREAM_MUSIC) |
- (1 << AudioSystem.STREAM_RING) |
- (1 << AudioSystem.STREAM_NOTIFICATION) |
- (1 << AudioSystem.STREAM_SYSTEM);
-
private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
public void onError(int error) {
switch (error) {
@@ -570,7 +545,7 @@
mContentResolver = context.getContentResolver();
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
- mPlatformType = getPlatformType(context);
+ mPlatformType = AudioSystem.getPlatformType(context);
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
@@ -583,13 +558,13 @@
MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
- DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
+ AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
}
maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
- DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
+ AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
}
sSoundEffectVolumeDb = context.getResources().getInteger(
@@ -683,26 +658,6 @@
LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
}
- /**
- * Return the platform type that this is running on. One of:
- * <ul>
- * <li>{@link #PLATFORM_VOICE}</li>
- * <li>{@link #PLATFORM_TELEVISION}</li>
- * <li>{@link #PLATFORM_DEFAULT}</li>
- * </ul>
- */
- public static int getPlatformType(Context context) {
- if (context.getResources().getBoolean(
- com.android.internal.R.bool.config_voice_capable)) {
- return PLATFORM_VOICE;
- } else if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_LEANBACK)) {
- return PLATFORM_TELEVISION;
- } else {
- return PLATFORM_DEFAULT;
- }
- }
-
public void systemReady() {
sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
0, 0, null, 0);
@@ -819,7 +774,7 @@
pw.println("\nStream volumes (device: index)");
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int i = 0; i < numStreamTypes; i++) {
- pw.println("- "+STREAM_NAMES[i]+":");
+ pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
mStreamStates[i].dump(pw);
pw.println("");
}
@@ -827,22 +782,15 @@
pw.println(Integer.toHexString(mMuteAffectedStreams));
}
- /** @hide */
- public static String streamToString(int stream) {
- if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
- if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
- return "UNKNOWN_STREAM_" + stream;
- }
-
private void updateStreamVolumeAlias(boolean updateVolumes) {
int dtmfStreamAlias;
switch (mPlatformType) {
- case PLATFORM_VOICE:
+ case AudioSystem.PLATFORM_VOICE:
mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
dtmfStreamAlias = AudioSystem.STREAM_RING;
break;
- case PLATFORM_TELEVISION:
+ case AudioSystem.PLATFORM_TELEVISION:
mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
break;
@@ -921,11 +869,11 @@
// System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
// are still needed while setVibrateSetting() and getVibrateSetting() are being
// deprecated.
- mVibrateSetting = getValueForVibrateSetting(0,
+ mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
AudioManager.VIBRATE_TYPE_NOTIFICATION,
mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
: AudioManager.VIBRATE_SETTING_OFF);
- mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
+ mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
AudioManager.VIBRATE_TYPE_RINGER,
mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
: AudioManager.VIBRATE_SETTING_OFF);
@@ -935,7 +883,7 @@
}
mMuteAffectedStreams = System.getIntForUser(cr,
- System.MUTE_STREAMS_AFFECTED, DEFAULT_MUTE_STREAMS_AFFECTED,
+ System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
UserHandle.USER_CURRENT);
boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
@@ -1746,10 +1694,6 @@
return MAX_STREAM_VOLUME[streamType];
}
- public static int getDefaultStreamVolume(int streamType) {
- return DEFAULT_STREAM_VOLUME[streamType];
- }
-
/** @see AudioManager#getStreamVolume(int) */
public int getStreamVolume(int streamType) {
ensureValidStreamType(streamType);
@@ -2044,29 +1988,14 @@
if (!mHasVibrator) return;
- mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
+ mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
+ vibrateSetting);
// Broadcast change
broadcastVibrateSetting(vibrateType);
}
- /**
- * @see #setVibrateSetting(int, int)
- */
- public static int getValueForVibrateSetting(int existingValue, int vibrateType,
- int vibrateSetting) {
-
- // First clear the existing setting. Each vibrate type has two bits in
- // the value. Note '3' is '11' in binary.
- existingValue &= ~(3 << (vibrateType * 2));
-
- // Set into the old value
- existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
-
- return existingValue;
- }
-
private class SetModeDeathHandler implements IBinder.DeathRecipient {
private IBinder mCb; // To be notified of client's death
private int mPid;
@@ -3245,7 +3174,7 @@
(1 << AudioSystem.STREAM_SYSTEM);
switch (mPlatformType) {
- case PLATFORM_TELEVISION:
+ case AudioSystem.PLATFORM_TELEVISION:
ringerModeAffectedStreams = 0;
break;
default:
@@ -3338,7 +3267,7 @@
private int getActiveStreamType(int suggestedStreamType) {
switch (mPlatformType) {
- case PLATFORM_VOICE:
+ case AudioSystem.PLATFORM_VOICE:
if (isInCommunication()) {
if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
== AudioSystem.FORCE_BT_SCO) {
@@ -3364,7 +3293,7 @@
return AudioSystem.STREAM_MUSIC;
}
break;
- case PLATFORM_TELEVISION:
+ case AudioSystem.PLATFORM_TELEVISION:
if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
// TV always defaults to STREAM_MUSIC
return AudioSystem.STREAM_MUSIC;
@@ -3599,7 +3528,7 @@
// only be stale values
if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
(mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
- int index = 10 * DEFAULT_STREAM_VOLUME[mStreamType];
+ int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
synchronized (mCameraSoundForced) {
if (mCameraSoundForced) {
index = mIndexMax;
@@ -3623,7 +3552,7 @@
// if no volume stored for current stream and device, use default volume if default
// device, continue otherwise
int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
- DEFAULT_STREAM_VOLUME[mStreamType] : -1;
+ AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
int index = Settings.System.getIntForUser(
mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
if (index == -1) {
@@ -4497,8 +4426,8 @@
mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
synchronized (mCurAudioRoutes) {
// Remove A2DP routes as well
- if (mCurAudioRoutes.mBluetoothName != null) {
- mCurAudioRoutes.mBluetoothName = null;
+ if (mCurAudioRoutes.bluetoothName != null) {
+ mCurAudioRoutes.bluetoothName = null;
sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
SENDMSG_NOOP, 0, 0, null, 0);
}
@@ -4578,8 +4507,8 @@
makeA2dpDeviceUnavailableNow(address);
}
synchronized (mCurAudioRoutes) {
- if (mCurAudioRoutes.mBluetoothName != null) {
- mCurAudioRoutes.mBluetoothName = null;
+ if (mCurAudioRoutes.bluetoothName != null) {
+ mCurAudioRoutes.bluetoothName = null;
sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
SENDMSG_NOOP, 0, 0, null, 0);
}
@@ -4600,8 +4529,8 @@
makeA2dpDeviceAvailable(address);
synchronized (mCurAudioRoutes) {
String name = btDevice.getAliasName();
- if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
- mCurAudioRoutes.mBluetoothName = name;
+ if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
+ mCurAudioRoutes.bluetoothName = name;
sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
SENDMSG_NOOP, 0, 0, null, 0);
}
@@ -4757,14 +4686,14 @@
synchronized (mCurAudioRoutes) {
if (connType != 0) {
- int newConn = mCurAudioRoutes.mMainType;
+ int newConn = mCurAudioRoutes.mainType;
if (state != 0) {
newConn |= connType;
} else {
newConn &= ~connType;
}
- if (newConn != mCurAudioRoutes.mMainType) {
- mCurAudioRoutes.mMainType = newConn;
+ if (newConn != mCurAudioRoutes.mainType) {
+ mCurAudioRoutes.mainType = newConn;
sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
SENDMSG_NOOP, 0, 0, null, 0);
}
@@ -5096,7 +5025,7 @@
IAudioPolicyCallback pcb) {
// permission checks
if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
- if (mMediaFocusControl.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
+ if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MODIFY_PHONE_STATE)) {
Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
@@ -5564,8 +5493,8 @@
dumpStreamStates(pw);
dumpRingerMode(pw);
pw.println("\nAudio routes:");
- pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
- pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
+ pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
+ pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
pw.println("\nOther state:");
pw.print(" mVolumeController="); pw.println(mVolumeController);
diff --git a/media/java/android/media/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
similarity index 97%
rename from media/java/android/media/FocusRequester.java
rename to services/core/java/com/android/server/audio/FocusRequester.java
index bbe5fd2..49be879 100644
--- a/media/java/android/media/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -14,13 +14,18 @@
* limitations under the License.
*/
-package android.media;
+package com.android.server.audio;
import android.annotation.NonNull;
-import android.media.MediaFocusControl.AudioFocusDeathHandler;
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.media.IAudioFocusDispatcher;
import android.os.IBinder;
import android.util.Log;
+import com.android.server.audio.MediaFocusControl.AudioFocusDeathHandler;
+
import java.io.PrintWriter;
/**
@@ -29,7 +34,7 @@
* instance is managed by android.media.MediaFocusControl, from its addition to the audio focus
* stack to its release.
*/
-class FocusRequester {
+public class FocusRequester {
// on purpose not using this classe's name, as it will only be used from MediaFocusControl
private static final String TAG = "MediaFocusControl";
diff --git a/media/java/android/media/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
similarity index 98%
rename from media/java/android/media/MediaFocusControl.java
rename to services/core/java/com/android/server/audio/MediaFocusControl.java
index 6518bd1..24e1ace 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.media;
+package com.android.server.audio;
import android.app.Activity;
import android.app.ActivityManager;
@@ -32,7 +32,17 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
-import android.media.PlayerRecord.RemotePlaybackState;
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.media.IAudioFocusDispatcher;
+import android.media.IAudioService;
+import android.media.IRemoteControlClient;
+import android.media.IRemoteControlDisplay;
+import android.media.IRemoteVolumeObserver;
+import android.media.RemoteControlClient;
+import android.media.AudioManager.OnAudioFocusChangeListener;
import android.media.audiopolicy.IAudioPolicyCallback;
import android.net.Uri;
import android.os.Binder;
@@ -53,6 +63,8 @@
import android.util.Slog;
import android.view.KeyEvent;
+import com.android.server.audio.PlayerRecord.RemotePlaybackState;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
@@ -391,13 +403,6 @@
// AudioFocus
//==========================================================================================
- /**
- * Constant to identify a focus stack entry that is used to hold the focus while the phone
- * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
- * entering and exiting calls.
- */
- protected final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
-
private final static Object mAudioFocusLock = new Object();
private final static Object mRingingLock = new Object();
@@ -565,7 +570,7 @@
}
private boolean isLockedFocusOwner(FocusRequester fr) {
- return (fr.hasSameClient(IN_VOICE_COMM_FOCUS_ID) || fr.isLockedFocusOwner());
+ return (fr.hasSameClient(AudioSystem.IN_VOICE_COMM_FOCUS_ID) || fr.isLockedFocusOwner());
}
/**
diff --git a/media/java/android/media/PlayerRecord.java b/services/core/java/com/android/server/audio/PlayerRecord.java
similarity index 97%
rename from media/java/android/media/PlayerRecord.java
rename to services/core/java/com/android/server/audio/PlayerRecord.java
index 664ddcf..a7dbbd1 100644
--- a/media/java/android/media/PlayerRecord.java
+++ b/services/core/java/com/android/server/audio/PlayerRecord.java
@@ -14,10 +14,14 @@
* limitations under the License.
*/
-package android.media;
+package com.android.server.audio;
import android.app.PendingIntent;
import android.content.ComponentName;
+import android.media.AudioManager;
+import android.media.IRemoteControlClient;
+import android.media.IRemoteVolumeObserver;
+import android.media.RemoteControlClient;
import android.os.Binder;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index bd0e587..709ca4b 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -847,9 +847,29 @@
/**
* Start legacy VPN, controlling native daemons as needed. Creates a
* secondary thread to perform connection work, returning quickly.
+ *
+ * Should only be called to respond to Binder requests as this enforces caller permission. Use
+ * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, LinkProperties)} to skip the
+ * permission check only when the caller is trusted (or the call is initiated by the system).
*/
public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
enforceControlPermission();
+ long token = Binder.clearCallingIdentity();
+ try {
+ startLegacyVpnPrivileged(profile, keyStore, egress);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Like {@link #startLegacyVpn(VpnProfile, KeyStore, LinkProperties)}, but does not check
+ * permissions under the assumption that the caller is the system.
+ *
+ * Callers are responsible for checking permissions if needed.
+ */
+ public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore,
+ LinkProperties egress) {
if (!keyStore.isUnlocked()) {
throw new IllegalStateException("KeyStore isn't unlocked");
}
@@ -960,10 +980,10 @@
}
private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
- stopLegacyVpn();
+ stopLegacyVpnPrivileged();
- // Prepare for the new request. This also checks the caller.
- prepare(null, VpnConfig.LEGACY_VPN);
+ // Prepare for the new request.
+ prepareInternal(VpnConfig.LEGACY_VPN);
updateState(DetailedState.CONNECTING, "startLegacyVpn");
// Start a new LegacyVpnRunner and we are done!
@@ -971,7 +991,8 @@
mLegacyVpnRunner.start();
}
- public synchronized void stopLegacyVpn() {
+ /** Stop legacy VPN. Permissions must be checked by callers. */
+ public synchronized void stopLegacyVpnPrivileged() {
if (mLegacyVpnRunner != null) {
mLegacyVpnRunner.exit();
mLegacyVpnRunner = null;
diff --git a/services/core/java/com/android/server/firewall/SenderFilter.java b/services/core/java/com/android/server/firewall/SenderFilter.java
index c0eee69..0074119 100644
--- a/services/core/java/com/android/server/firewall/SenderFilter.java
+++ b/services/core/java/com/android/server/firewall/SenderFilter.java
@@ -45,7 +45,8 @@
IPackageManager pm = AppGlobals.getPackageManager();
try {
- return (pm.getFlagsForUid(callerUid) & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+ return (pm.getPrivateFlagsForUid(callerUid) & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ != 0;
} catch (RemoteException ex) {
Slog.e(IntentFirewall.TAG, "Remote exception while retrieving uid flags",
ex);
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 0c86aed..e434f39 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -214,6 +214,10 @@
// values which denotes the device type in HDMI Spec 1.4.
static final String PROPERTY_DEVICE_TYPE = "ro.hdmi.device_type";
+ // Set to false to allow playback device to go to suspend mode even
+ // when it's an active source. True by default.
+ static final String PROPERTY_KEEP_AWAKE = "persist.sys.hdmi.keep_awake";
+
static final int RECORDING_TYPE_DIGITAL_RF = 1;
static final int RECORDING_TYPE_ANALOGUE_RF = 2;
static final int RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 3;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index a8f6954..1e43670 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -38,9 +38,11 @@
// Used to keep the device awake while it is the active source. For devices that
// cannot wake up via CEC commands, this address the inconvenience of having to
- // turn them on.
+ // turn them on. True by default, and can be disabled (i.e. device can go to sleep
+ // in active device status) by explicitly setting the system property
+ // persist.sys.hdmi.keep_awake to false.
// Lazily initialized - should call getWakeLock() to get the instance.
- private WakeLock mWakeLock;
+ private ActiveWakeLock mWakeLock;
HdmiCecLocalDevicePlayback(HdmiControlService service) {
super(service, HdmiDeviceInfo.DEVICE_PLAYBACK);
@@ -142,19 +144,30 @@
mIsActiveSource = on;
if (on) {
getWakeLock().acquire();
- HdmiLogger.debug("active source: %b. Wake lock acquired", mIsActiveSource);
} else {
getWakeLock().release();
- HdmiLogger.debug("Wake lock released");
}
}
@ServiceThreadOnly
- private WakeLock getWakeLock() {
+ private ActiveWakeLock getWakeLock() {
assertRunOnServiceThread();
if (mWakeLock == null) {
- mWakeLock = mService.getPowerManager().newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mWakeLock.setReferenceCounted(false);
+ if (SystemProperties.getBoolean(Constants.PROPERTY_KEEP_AWAKE, true)) {
+ mWakeLock = new SystemWakeLock();
+ } else {
+ // Create a dummy lock object that doesn't do anything about wake lock,
+ // hence allows the device to go to sleep even if it's the active source.
+ mWakeLock = new ActiveWakeLock() {
+ @Override
+ public void acquire() { }
+ @Override
+ public void release() { }
+ @Override
+ public boolean isHeld() { return false; }
+ };
+ HdmiLogger.debug("No wakelock is used to keep the display on.");
+ }
}
return mWakeLock;
}
@@ -258,4 +271,36 @@
super.dump(pw);
pw.println("mIsActiveSource: " + mIsActiveSource);
}
+
+ // Wrapper interface over PowerManager.WakeLock
+ private interface ActiveWakeLock {
+ void acquire();
+ void release();
+ boolean isHeld();
+ }
+
+ private class SystemWakeLock implements ActiveWakeLock {
+ private final WakeLock mWakeLock;
+ public SystemWakeLock() {
+ mWakeLock = mService.getPowerManager().newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ mWakeLock.setReferenceCounted(false);
+ }
+
+ @Override
+ public void acquire() {
+ mWakeLock.acquire();
+ HdmiLogger.debug("active source: %b. Wake lock acquired", mIsActiveSource);
+ }
+
+ @Override
+ public void release() {
+ mWakeLock.release();
+ HdmiLogger.debug("Wake lock released");
+ }
+
+ @Override
+ public boolean isHeld() {
+ return mWakeLock.isHeld();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index e41b3da..65693b4 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -785,9 +785,7 @@
}
if (info != null) {
- boolean dataEnabled = TelephonyManager.getIntWithSubId(mContext.getContentResolver(),
- Settings.Global.MOBILE_DATA, SubscriptionManager.getDefaultSubId(),
- 1) == 1;
+ boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
boolean networkAvailable = info.isAvailable() && dataEnabled;
String defaultApn = getSelectedApn();
if (defaultApn == null) {
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index e9b3f8b..bfdc400 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -98,6 +98,11 @@
@Override
public void onSwitchUser(int userId) {
mMediaRouter.rebindAsUser(userId);
+ synchronized (mLock) {
+ if (mProjectionGrant != null) {
+ mProjectionGrant.stop();
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 3a1e4a4..752614f 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -140,7 +140,7 @@
if (egressDisconnected || egressChanged) {
clearSourceRulesLocked();
mAcceptedEgressIface = null;
- mVpn.stopLegacyVpn();
+ mVpn.stopLegacyVpnPrivileged();
}
if (egressDisconnected) {
hideNotification();
@@ -163,7 +163,9 @@
mAcceptedEgressIface = egressProp.getInterfaceName();
try {
- mVpn.startLegacyVpn(mProfile, KeyStore.getInstance(), egressProp);
+ // Use the privileged method because Lockdown VPN is initiated by the system, so
+ // no additional permission checks are necessary.
+ mVpn.startLegacyVpnPrivileged(mProfile, KeyStore.getInstance(), egressProp);
} catch (IllegalStateException e) {
mAcceptedEgressIface = null;
Slog.e(TAG, "Failed to start VPN", e);
@@ -250,7 +252,7 @@
mAcceptedEgressIface = null;
mErrorCount = 0;
- mVpn.stopLegacyVpn();
+ mVpn.stopLegacyVpnPrivileged();
try {
mNetService.setFirewallEgressDestRule(mProfile.server, 500, false);
mNetService.setFirewallEgressDestRule(mProfile.server, 4500, false);
diff --git a/services/core/java/com/android/server/pm/GrantedPermissions.java b/services/core/java/com/android/server/pm/GrantedPermissions.java
index 8f0f935..e87546c 100644
--- a/services/core/java/com/android/server/pm/GrantedPermissions.java
+++ b/services/core/java/com/android/server/pm/GrantedPermissions.java
@@ -21,13 +21,15 @@
class GrantedPermissions {
int pkgFlags;
+ int pkgPrivateFlags;
ArraySet<String> grantedPermissions = new ArraySet<String>();
int[] gids;
- GrantedPermissions(int pkgFlags) {
+ GrantedPermissions(int pkgFlags, int pkgPrivateFlags) {
setFlags(pkgFlags);
+ setPrivateFlags(pkgPrivateFlags);
}
@SuppressWarnings("unchecked")
@@ -43,8 +45,12 @@
void setFlags(int pkgFlags) {
this.pkgFlags = pkgFlags
& (ApplicationInfo.FLAG_SYSTEM
- | ApplicationInfo.FLAG_PRIVILEGED
- | ApplicationInfo.FLAG_FORWARD_LOCK
| ApplicationInfo.FLAG_EXTERNAL_STORAGE);
}
+
+ void setPrivateFlags(int pkgPrivateFlags) {
+ this.pkgPrivateFlags = pkgPrivateFlags
+ & (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
+ | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK);
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 12c4315..c3f1418 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1299,17 +1299,17 @@
mMetrics = new DisplayMetrics();
mSettings = new Settings(context);
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
- ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+ ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
- ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+ ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
- ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+ ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
- ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+ ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
- ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+ ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
- ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+ ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
// TODO: add a property to control this?
long dexOptLRUThresholdInMinutes;
@@ -2124,6 +2124,7 @@
pkg = new PackageParser.Package(packageName);
pkg.applicationInfo.packageName = packageName;
pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
+ pkg.applicationInfo.privateFlags = ps.pkgPrivateFlags;
pkg.applicationInfo.dataDir =
getDataPathForPackage(packageName, 0).getPath();
pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
@@ -2966,7 +2967,7 @@
}
// reader
synchronized (mPackages) {
- final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, false);
+ final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, 0, false);
if (suid == null) {
return -1;
}
@@ -2990,6 +2991,21 @@
}
@Override
+ public int getPrivateFlagsForUid(int uid) {
+ synchronized (mPackages) {
+ Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
+ if (obj instanceof SharedUserSetting) {
+ final SharedUserSetting sus = (SharedUserSetting) obj;
+ return sus.pkgPrivateFlags;
+ } else if (obj instanceof PackageSetting) {
+ final PackageSetting ps = (PackageSetting) obj;
+ return ps.pkgPrivateFlags;
+ }
+ }
+ return 0;
+ }
+
+ @Override
public boolean isUidPrivileged(int uid) {
uid = UserHandle.getAppId(uid);
// reader
@@ -4309,9 +4325,9 @@
// If new package is not located in "/system/priv-app" (e.g. due to an OTA),
// it needs to drop FLAG_PRIVILEGED.
if (locationIsPrivileged(scanFile)) {
- updatedPkg.pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
+ updatedPkg.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
} else {
- updatedPkg.pkgFlags &= ~ApplicationInfo.FLAG_PRIVILEGED;
+ updatedPkg.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
if (ps != null && !ps.codePath.equals(scanFile)) {
@@ -4375,7 +4391,7 @@
// An updated privileged app will not have the PARSE_IS_PRIVILEGED
// flag set initially
- if ((updatedPkg.pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+ if ((updatedPkg.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
}
}
@@ -5315,7 +5331,7 @@
}
if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_PRIVILEGED;
+ pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
if (mCustomResolverComponentName != null &&
@@ -5389,7 +5405,7 @@
// writer
synchronized (mPackages) {
if (pkg.mSharedUserId != null) {
- suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, true);
+ suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, true);
if (suid == null) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Creating application package " + pkg.packageName
@@ -5463,7 +5479,8 @@
destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
pkg.applicationInfo.primaryCpuAbi,
pkg.applicationInfo.secondaryCpuAbi,
- pkg.applicationInfo.flags, user, false);
+ pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
+ user, false);
if (pkgSetting == null) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Creating application package " + pkg.packageName + " failed");
@@ -10358,7 +10375,8 @@
boolean disabledSystem = false;
boolean updatedSettings = false;
parseFlags |= PackageParser.PARSE_IS_SYSTEM;
- if ((deletedPackage.applicationInfo.flags&ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+ if ((deletedPackage.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ != 0) {
parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
}
String packageName = deletedPackage.packageName;
@@ -10716,15 +10734,15 @@
}
private static boolean isForwardLocked(PackageParser.Package pkg) {
- return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
+ return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
}
private static boolean isForwardLocked(ApplicationInfo info) {
- return (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
+ return (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
}
private boolean isForwardLocked(PackageSetting ps) {
- return (ps.pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
+ return (ps.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
}
private static boolean isMultiArch(PackageSetting ps) {
@@ -10752,7 +10770,7 @@
}
private static boolean isPrivilegedApp(PackageParser.Package pkg) {
- return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+ return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
private static boolean isSystemApp(ApplicationInfo info) {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 696aa34..8ea0bee 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -32,10 +32,10 @@
PackageSetting(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
- int pVersionCode, int pkgFlags) {
+ int pVersionCode, int pkgFlags, int privateFlags) {
super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
- pVersionCode, pkgFlags);
+ pVersionCode, pkgFlags, privateFlags);
}
/**
@@ -62,6 +62,6 @@
}
public boolean isPrivileged() {
- return (pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+ return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 1dcadb4..4b8ca42 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -112,8 +112,8 @@
PackageSettingBase(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
- int pVersionCode, int pkgFlags) {
- super(pkgFlags);
+ int pVersionCode, int pkgFlags, int pkgPrivateFlags) {
+ super(pkgFlags, pkgPrivateFlags);
this.name = name;
this.realName = realName;
init(codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString,
diff --git a/services/core/java/com/android/server/pm/PendingPackage.java b/services/core/java/com/android/server/pm/PendingPackage.java
index 5d30e76..bb0dba1 100644
--- a/services/core/java/com/android/server/pm/PendingPackage.java
+++ b/services/core/java/com/android/server/pm/PendingPackage.java
@@ -24,10 +24,10 @@
PendingPackage(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString, int sharedId,
- int pVersionCode, int pkgFlags) {
+ int pVersionCode, int pkgFlags, int pkgPrivateFlags) {
super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
- pVersionCode, pkgFlags);
+ pVersionCode, pkgFlags, pkgPrivateFlags);
this.sharedId = sharedId;
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 524f638..d353494 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -281,11 +281,11 @@
PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbi, String secondaryCpuAbi,
- int pkgFlags, UserHandle user, boolean add) {
+ int pkgFlags, int pkgPrivateFlags, UserHandle user, boolean add) {
final String name = pkg.packageName;
PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
resourcePath, legacyNativeLibraryPathString, primaryCpuAbi, secondaryCpuAbi,
- pkg.mVersionCode, pkgFlags, user, add, true /* allowInstall */);
+ pkg.mVersionCode, pkgFlags, pkgPrivateFlags, user, add, true /* allowInstall */);
return p;
}
@@ -311,13 +311,13 @@
}
SharedUserSetting getSharedUserLPw(String name,
- int pkgFlags, boolean create) {
+ int pkgFlags, int pkgPrivateFlags, boolean create) {
SharedUserSetting s = mSharedUsers.get(name);
if (s == null) {
if (!create) {
return null;
}
- s = new SharedUserSetting(name, pkgFlags);
+ s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
s.userId = newUserIdLPw(s);
Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
// < 0 means we couldn't assign a userid; fall out and return
@@ -373,7 +373,7 @@
PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
p.secondaryCpuAbiString, p.secondaryCpuAbiString,
- p.appId, p.versionCode, p.pkgFlags);
+ p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags);
mDisabledSysPackages.remove(name);
return ret;
}
@@ -388,7 +388,7 @@
PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
- String cpuAbiOverrideString, int uid, int vc, int pkgFlags) {
+ String cpuAbiOverrideString, int uid, int vc, int pkgFlags, int pkgPrivateFlags) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (p.appId == uid) {
@@ -400,7 +400,7 @@
}
p = new PackageSetting(name, realName, codePath, resourcePath,
legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
- cpuAbiOverrideString, vc, pkgFlags);
+ cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags);
p.appId = uid;
if (addUserIdLPw(uid, p, name)) {
mPackages.put(name, p);
@@ -409,7 +409,7 @@
return null;
}
- SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {
+ SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
SharedUserSetting s = mSharedUsers.get(name);
if (s != null) {
if (s.userId == uid) {
@@ -419,7 +419,7 @@
"Adding duplicate shared user, keeping first: " + name);
return null;
}
- s = new SharedUserSetting(name, pkgFlags);
+ s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
s.userId = uid;
if (addUserIdLPw(uid, s, name)) {
mSharedUsers.put(name, s);
@@ -469,7 +469,7 @@
private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
- int vc, int pkgFlags, UserHandle installUser, boolean add,
+ int vc, int pkgFlags, int pkgPrivateFlags, UserHandle installUser, boolean add,
boolean allowInstall) {
PackageSetting p = mPackages.get(name);
UserManagerService userManager = UserManagerService.getInstance();
@@ -511,9 +511,8 @@
// If what we are scanning is a system (and possibly privileged) package,
// then make it so, regardless of whether it was previously installed only
// in the data partition.
- final int sysPrivFlags = pkgFlags
- & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PRIVILEGED);
- p.pkgFlags |= sysPrivFlags;
+ p.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM;
+ p.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
}
if (p == null) {
@@ -521,7 +520,7 @@
// We are consuming the data from an existing package.
p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
- null /* cpuAbiOverrideString */, vc, pkgFlags);
+ null /* cpuAbiOverrideString */, vc, pkgFlags, pkgPrivateFlags);
if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
+ name + " is adopting original package " + origPackage.name);
// Note that we will retain the new package's signature so
@@ -539,7 +538,7 @@
} else {
p = new PackageSetting(name, realName, codePath, resourcePath,
legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
- null /* cpuAbiOverrideString */, vc, pkgFlags);
+ null /* cpuAbiOverrideString */, vc, pkgFlags, pkgPrivateFlags);
p.setTimeStamp(codePath.lastModified());
p.sharedUser = sharedUser;
// If this is not a system app, it starts out stopped.
@@ -1818,7 +1817,8 @@
serializer.attribute(null, "cpuAbiOverride", pkg.cpuAbiOverrideString);
}
- serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags));
+ serializer.attribute(null, "publicFlags", Integer.toString(pkg.pkgFlags));
+ serializer.attribute(null, "privateFlags", Integer.toString(pkg.pkgPrivateFlags));
serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
@@ -2127,8 +2127,8 @@
PackageSetting p = getPackageLPw(pp.name, null, pp.realName,
(SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
pp.legacyNativeLibraryPathString, pp.primaryCpuAbiString,
- pp.secondaryCpuAbiString, pp.versionCode, pp.pkgFlags, null,
- true /* add */, false /* allowInstall */);
+ pp.secondaryCpuAbiString, pp.versionCode, pp.pkgFlags, pp.pkgPrivateFlags,
+ null, true /* add */, false /* allowInstall */);
if (p == null) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unable to create application package for " + pp.name);
@@ -2596,14 +2596,15 @@
}
int pkgFlags = 0;
+ int pkgPrivateFlags = 0;
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
final File codePathFile = new File(codePathStr);
if (PackageManagerService.locationIsPrivileged(codePathFile)) {
- pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
PackageSetting ps = new PackageSetting(name, realName, codePathFile,
new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
- secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags);
+ secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags);
String timeStampStr = parser.getAttributeValue(null, "ft");
if (timeStampStr != null) {
try {
@@ -2662,6 +2663,11 @@
mDisabledSysPackages.put(name, ps);
}
+ private static int PRE_M_APP_INFO_FLAG_HIDDEN = 1<<27;
+ private static int PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE = 1<<28;
+ private static int PRE_M_APP_INFO_FLAG_FORWARD_LOCK = 1<<29;
+ private static int PRE_M_APP_INFO_FLAG_PRIVILEGED = 1<<30;
+
private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
String name = null;
String realName = null;
@@ -2678,6 +2684,7 @@
String installerPackageName = null;
String uidError = null;
int pkgFlags = 0;
+ int pkgPrivateFlags = 0;
long timeStamp = 0;
long firstInstallTime = 0;
long lastUpdateTime = 0;
@@ -2713,22 +2720,54 @@
}
installerPackageName = parser.getAttributeValue(null, "installer");
- systemStr = parser.getAttributeValue(null, "flags");
+ systemStr = parser.getAttributeValue(null, "publicFlags");
if (systemStr != null) {
try {
pkgFlags = Integer.parseInt(systemStr);
} catch (NumberFormatException e) {
}
- } else {
- // For backward compatibility
- systemStr = parser.getAttributeValue(null, "system");
+ systemStr = parser.getAttributeValue(null, "privateFlags");
if (systemStr != null) {
- pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM
- : 0;
+ try {
+ pkgPrivateFlags = Integer.parseInt(systemStr);
+ } catch (NumberFormatException e) {
+ }
+ }
+ } else {
+ // Pre-M -- both public and private flags were stored in one "flags" field.
+ systemStr = parser.getAttributeValue(null, "flags");
+ if (systemStr != null) {
+ try {
+ pkgFlags = Integer.parseInt(systemStr);
+ } catch (NumberFormatException e) {
+ }
+ if ((pkgFlags & PRE_M_APP_INFO_FLAG_HIDDEN) != 0) {
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+ }
+ if ((pkgFlags & PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE) != 0) {
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
+ }
+ if ((pkgFlags & PRE_M_APP_INFO_FLAG_FORWARD_LOCK) != 0) {
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
+ }
+ if ((pkgFlags & PRE_M_APP_INFO_FLAG_PRIVILEGED) != 0) {
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+ }
+ pkgFlags &= ~(PRE_M_APP_INFO_FLAG_HIDDEN
+ | PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE
+ | PRE_M_APP_INFO_FLAG_FORWARD_LOCK
+ | PRE_M_APP_INFO_FLAG_PRIVILEGED);
} else {
- // Old settings that don't specify system... just treat
- // them as system, good enough.
- pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ // For backward compatibility
+ systemStr = parser.getAttributeValue(null, "system");
+ if (systemStr != null) {
+ pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM
+ : 0;
+ } else {
+ // Old settings that don't specify system... just treat
+ // them as system, good enough.
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ }
}
}
String timeStampStr = parser.getAttributeValue(null, "ft");
@@ -2781,7 +2820,8 @@
} else if (userId > 0) {
packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
- secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags);
+ secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,
+ pkgPrivateFlags);
if (PackageManagerService.DEBUG_SETTINGS)
Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
+ userId + " pkg=" + packageSetting);
@@ -2800,7 +2840,7 @@
packageSetting = new PendingPackage(name.intern(), realName, new File(
codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
- userId, versionCode, pkgFlags);
+ userId, versionCode, pkgFlags, pkgPrivateFlags);
packageSetting.setTimeStamp(timeStamp);
packageSetting.firstInstallTime = firstInstallTime;
packageSetting.lastUpdateTime = lastUpdateTime;
@@ -2967,6 +3007,7 @@
String name = null;
String idStr = null;
int pkgFlags = 0;
+ int pkgPrivateFlags = 0;
SharedUserSetting su = null;
try {
name = parser.getAttributeValue(null, ATTR_NAME);
@@ -2985,7 +3026,8 @@
+ " has bad userId " + idStr + " at "
+ parser.getPositionDescription());
} else {
- if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags)) == null) {
+ if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags, pkgPrivateFlags))
+ == null) {
PackageManagerService
.reportSettingsProblem(Log.ERROR, "Occurred while parsing settings at "
+ parser.getPositionDescription());
@@ -3302,9 +3344,12 @@
ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
- ApplicationInfo.FLAG_PRIVILEGED, "PRIVILEGED",
- ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
- ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
+ };
+
+ static final Object[] PRIVATE_FLAG_DUMP_SPEC = new Object[] {
+ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED",
+ ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+ ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
};
void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag, PackageSetting ps,
@@ -3391,6 +3436,8 @@
pw.println(ps.pkg.applicationInfo.toString());
pw.print(prefix); pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
FLAG_DUMP_SPEC); pw.println();
+ pw.print(prefix); pw.print(" priavateFlags="); printFlags(pw,
+ ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
if (ps.pkg.mOperationPending) {
pw.print(prefix); pw.println(" mOperationPending=true");
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 2b406f7..d95739c 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -28,14 +28,16 @@
// flags that are associated with this uid, regardless of any package flags
int uidFlags;
+ int uidPrivateFlags;
final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>();
final PackageSignatures signatures = new PackageSignatures();
- SharedUserSetting(String _name, int _pkgFlags) {
- super(_pkgFlags);
+ SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) {
+ super(_pkgFlags, _pkgPrivateFlags);
uidFlags = _pkgFlags;
+ uidPrivateFlags = _pkgPrivateFlags;
name = _name;
}
@@ -55,12 +57,20 @@
}
setFlags(aggregatedFlags);
}
+ if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) {
+ int aggregatedPrivateFlags = uidPrivateFlags;
+ for (PackageSetting ps : packages) {
+ aggregatedPrivateFlags |= ps.pkgPrivateFlags;
+ }
+ setPrivateFlags(aggregatedPrivateFlags);
+ }
}
}
void addPackage(PackageSetting packageSetting) {
if (packages.add(packageSetting)) {
setFlags(this.pkgFlags | packageSetting.pkgFlags);
+ setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
}
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f85b195..69a1ac9 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1592,7 +1592,8 @@
try {
for (ApplicationInfo appInfo : apps) {
if ((appInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0
- && (appInfo.flags & ApplicationInfo.FLAG_HIDDEN) != 0) {
+ && (appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HIDDEN)
+ != 0) {
mPm.setApplicationHiddenSettingAsUser(appInfo.packageName, false,
userHandle);
}
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/services/core/java/com/android/server/policy/BarController.java
similarity index 99%
rename from policy/src/com/android/internal/policy/impl/BarController.java
rename to services/core/java/com/android/server/policy/BarController.java
index bfbd60d..bca2c16 100644
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import android.app.StatusBarManager;
import android.os.Handler;
diff --git a/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
similarity index 99%
rename from policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java
rename to services/core/java/com/android/server/policy/EnableAccessibilityController.java
index 6f79f58..da9c001 100644
--- a/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java
+++ b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
@@ -14,7 +14,7 @@
* the License.
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.ActivityManager;
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
similarity index 99%
rename from policy/src/com/android/internal/policy/impl/GlobalActions.java
rename to services/core/java/com/android/server/policy/GlobalActions.java
index 20a2c9f..d768fe3 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import com.android.internal.app.AlertController;
import com.android.internal.app.AlertController.AlertParams;
@@ -67,7 +67,6 @@
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import android.view.WindowManagerInternal;
import android.view.WindowManagerPolicy.WindowManagerFuncs;
import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView;
diff --git a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java b/services/core/java/com/android/server/policy/GlobalKeyManager.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/GlobalKeyManager.java
rename to services/core/java/com/android/server/policy/GlobalKeyManager.java
index fc65793..e08c004 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java
+++ b/services/core/java/com/android/server/policy/GlobalKeyManager.java
@@ -13,7 +13,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import android.content.ComponentName;
import android.content.Context;
diff --git a/policy/src/com/android/internal/policy/impl/IconUtilities.java b/services/core/java/com/android/server/policy/IconUtilities.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/IconUtilities.java
rename to services/core/java/com/android/server/policy/IconUtilities.java
index 82f26ad..4658344 100644
--- a/policy/src/com/android/internal/policy/impl/IconUtilities.java
+++ b/services/core/java/com/android/server/policy/IconUtilities.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
diff --git a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
rename to services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index 8fc4647..e511346 100644
--- a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -28,7 +27,6 @@
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.os.Message;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.DisplayMetrics;
diff --git a/policy/src/com/android/internal/policy/impl/LogDecelerateInterpolator.java b/services/core/java/com/android/server/policy/LogDecelerateInterpolator.java
similarity index 96%
rename from policy/src/com/android/internal/policy/impl/LogDecelerateInterpolator.java
rename to services/core/java/com/android/server/policy/LogDecelerateInterpolator.java
index 1f3e1de..ed5dc6f 100644
--- a/policy/src/com/android/internal/policy/impl/LogDecelerateInterpolator.java
+++ b/services/core/java/com/android/server/policy/LogDecelerateInterpolator.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import android.view.animation.Interpolator;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
similarity index 99%
rename from policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
rename to services/core/java/com/android/server/policy/PhoneWindowManager.java
index dca7db1..ec8a77513 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -13,7 +13,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -43,7 +43,7 @@
import android.graphics.Rect;
import android.media.AudioAttributes;
import android.media.AudioManager;
-import android.media.AudioService;
+import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.Ringtone;
import android.media.RingtoneManager;
@@ -89,6 +89,7 @@
import android.view.KeyCharacterMap.FallbackAction;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.PhoneWindow;
import android.view.Surface;
import android.view.View;
import android.view.ViewConfiguration;
@@ -104,12 +105,11 @@
import android.view.animation.AnimationUtils;
import com.android.internal.R;
-import com.android.internal.policy.PolicyManager;
-import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate;
-import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate.ShowListener;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.widget.PointerLocationView;
import com.android.server.LocalServices;
+import com.android.server.policy.keyguard.KeyguardServiceDelegate;
+import com.android.server.policy.keyguard.KeyguardServiceDelegate.ShowListener;
import java.io.File;
import java.io.FileReader;
@@ -1269,7 +1269,7 @@
mTriplePressOnPowerBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_triplePressOnPowerBehavior);
- mUseTvRouting = AudioService.getPlatformType(mContext) == AudioService.PLATFORM_TELEVISION;
+ mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
mUseMasterVolume = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_useMasterVolume);
@@ -2041,7 +2041,7 @@
}
}
- Window win = PolicyManager.makeNewWindow(context);
+ Window win = new PhoneWindow(context);
final TypedArray ta = win.getWindowStyle();
if (ta.getBoolean(
com.android.internal.R.styleable.Window_windowDisablePreview, false)
@@ -5334,20 +5334,11 @@
}
void sendCloseSystemWindows() {
- sendCloseSystemWindows(mContext, null);
+ PhoneWindow.sendCloseSystemWindows(mContext, null);
}
void sendCloseSystemWindows(String reason) {
- sendCloseSystemWindows(mContext, reason);
- }
-
- static void sendCloseSystemWindows(Context context, String reason) {
- if (ActivityManagerNative.isSystemReady()) {
- try {
- ActivityManagerNative.getDefault().closeSystemDialogs(reason);
- } catch (RemoteException e) {
- }
- }
+ PhoneWindow.sendCloseSystemWindows(mContext, reason);
}
@Override
diff --git a/policy/src/com/android/internal/policy/impl/PolicyControl.java b/services/core/java/com/android/server/policy/PolicyControl.java
similarity index 99%
rename from policy/src/com/android/internal/policy/impl/PolicyControl.java
rename to services/core/java/com/android/server/policy/PolicyControl.java
index 9abd906..dbafc42 100644
--- a/policy/src/com/android/internal/policy/impl/PolicyControl.java
+++ b/services/core/java/com/android/server/policy/PolicyControl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import android.app.ActivityManager;
import android.content.Context;
diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java b/services/core/java/com/android/server/policy/RecentApplicationsBackground.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java
rename to services/core/java/com/android/server/policy/RecentApplicationsBackground.java
index 3490bd4..694a110 100644
--- a/policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java
+++ b/services/core/java/com/android/server/policy/RecentApplicationsBackground.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import android.content.Context;
import android.graphics.Canvas;
diff --git a/policy/src/com/android/internal/policy/impl/ShortcutManager.java b/services/core/java/com/android/server/policy/ShortcutManager.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/ShortcutManager.java
rename to services/core/java/com/android/server/policy/ShortcutManager.java
index bb898f7..6a0136a 100644
--- a/policy/src/com/android/internal/policy/impl/ShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ShortcutManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import android.content.Context;
import android.content.Intent;
diff --git a/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
rename to services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
index 4ff9315..cfa631f 100644
--- a/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import android.content.Context;
import android.util.Slog;
diff --git a/policy/src/com/android/internal/policy/impl/WakeGestureListener.java b/services/core/java/com/android/server/policy/WakeGestureListener.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/WakeGestureListener.java
rename to services/core/java/com/android/server/policy/WakeGestureListener.java
index 9396c2c..1d5d7ba 100644
--- a/policy/src/com/android/internal/policy/impl/WakeGestureListener.java
+++ b/services/core/java/com/android/server/policy/WakeGestureListener.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import android.os.Handler;
import android.content.Context;
diff --git a/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
similarity index 99%
rename from policy/src/com/android/internal/policy/impl/WindowOrientationListener.java
rename to services/core/java/com/android/server/policy/WindowOrientationListener.java
index 2f60d55..0118127 100644
--- a/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl;
+package com.android.server.policy;
import android.content.Context;
import android.hardware.Sensor;
@@ -25,7 +25,6 @@
import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
-import android.util.TimeUtils;
import java.io.PrintWriter;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
similarity index 99%
rename from policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
rename to services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 6e8f550..c3fc195 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -1,4 +1,4 @@
-package com.android.internal.policy.impl.keyguard;
+package com.android.server.policy.keyguard;
import android.content.ComponentName;
import android.content.Context;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
rename to services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index b3b7684..2dc685b 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl.keyguard;
+package com.android.server.policy.keyguard;
import android.content.Context;
import android.os.Bundle;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
similarity index 97%
rename from policy/src/com/android/internal/policy/impl/keyguard/KeyguardStateMonitor.java
rename to services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 6f9c617..926090e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy.impl.keyguard;
+package com.android.server.policy.keyguard;
import android.app.ActivityManager;
import android.content.Context;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 1c9dfe0c..c677e2c 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -185,6 +185,9 @@
Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
mOverrideConfig.smallestScreenWidthDp =
Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
+ mOverrideConfig.orientation =
+ (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
+ ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
}
void updateDisplayInfo() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8214026..71fddfb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -29,8 +29,6 @@
import android.view.IWindowSessionCallback;
import android.view.WindowContentFrameStats;
import com.android.internal.app.IBatteryStats;
-import com.android.internal.policy.PolicyManager;
-import com.android.internal.policy.impl.PhoneWindowManager;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -45,6 +43,7 @@
import com.android.server.am.BatteryStatsService;
import com.android.server.input.InputManagerService;
import com.android.server.power.ShutdownThread;
+import com.android.server.policy.PhoneWindowManager;
import android.Manifest;
import android.app.ActivityManagerNative;
@@ -338,7 +337,7 @@
final boolean mLimitedAlphaCompositing;
- final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
+ final WindowManagerPolicy mPolicy = new PhoneWindowManager();
final IActivityManager mActivityManager;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index bb95305..e88dace 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -232,7 +232,8 @@
final Rect mParentFrame = new Rect();
- // The entire screen area of the device.
+ // The entire screen area of the {@link TaskStack} this window is in. Usually equal to the
+ // screen area of the device.
final Rect mDisplayFrame = new Rect();
// The region of the display frame that the display type supports displaying content on. This
@@ -509,12 +510,12 @@
if (stack.mUnderStatusBar) {
mContainingFrame.top = pf.top;
}
+ mDisplayFrame.set(mContainingFrame);
} else {
mContainingFrame.set(pf);
+ mDisplayFrame.set(df);
}
- mDisplayFrame.set(df);
-
final int pw = mContainingFrame.width();
final int ph = mContainingFrame.height();
@@ -572,9 +573,6 @@
final int fw = mFrame.width();
final int fh = mFrame.height();
- //System.out.println("In: w=" + w + " h=" + h + " container=" +
- // container + " x=" + mAttrs.x + " y=" + mAttrs.y);
-
float x, y;
if (mEnforceSizeCompat) {
x = mAttrs.x * mGlobalScale;
@@ -591,8 +589,8 @@
(int) (x + mAttrs.horizontalMargin * pw),
(int) (y + mAttrs.verticalMargin * ph), mFrame);
- // Now make sure the window fits in the overall display.
- Gravity.applyDisplay(mAttrs.gravity, df, mFrame);
+ // Now make sure the window fits in the overall display frame.
+ Gravity.applyDisplay(mAttrs.gravity, mDisplayFrame, mFrame);
// Make sure the content and visible frames are inside of the
// final window frame.
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b8f0d072..fbb6f7c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5045,15 +5045,14 @@
if (activitiesToEnable != null) {
for (ResolveInfo info : activitiesToEnable) {
if (info.activityInfo != null) {
-
- if (!isSystemApp(pm, info.activityInfo.packageName, primaryUser.id)) {
- throw new IllegalArgumentException(
- "Only system apps can be enabled this way.");
+ String packageName = info.activityInfo.packageName;
+ if (isSystemApp(pm, packageName, primaryUser.id)) {
+ numberOfAppsInstalled++;
+ pm.installExistingPackageAsUser(packageName, userId);
+ } else {
+ Slog.d(LOG_TAG, "Not enabling " + packageName + " since is not a"
+ + " system app");
}
-
-
- numberOfAppsInstalled++;
- pm.installExistingPackageAsUser(info.activityInfo.packageName, userId);
}
}
}
@@ -5072,6 +5071,10 @@
throws RemoteException {
ApplicationInfo appInfo = pm.getApplicationInfo(packageName, GET_UNINSTALLED_PACKAGES,
userId);
+ if (appInfo == null) {
+ throw new IllegalArgumentException("The application " + packageName +
+ " is not present on this device");
+ }
return (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7f9af31..875d395 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -29,7 +29,6 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.media.AudioService;
import android.media.tv.TvInputManager;
import android.os.Build;
import android.os.Environment;
@@ -60,6 +59,7 @@
import com.android.server.accounts.AccountManagerService;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.BatteryStatsService;
+import com.android.server.audio.AudioService;
import com.android.server.clipboard.ClipboardService;
import com.android.server.content.ContentService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 9d13d3c..c6f6b85 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -24,7 +24,6 @@
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbInterface;
-import android.media.AudioService;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.midi.MidiDeviceInfo;
@@ -38,6 +37,8 @@
import android.provider.Settings;
import android.util.Slog;
+import com.android.server.audio.AudioService;
+
import libcore.io.IoUtils;
import java.io.File;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ba5a679..94691c0 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3665,12 +3665,12 @@
/** @hide */
@SystemApi
public boolean getDataEnabled(int subId) {
- boolean retVal;
+ boolean retVal = false;
try {
retVal = getITelephony().getDataEnabled(subId);
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#getDataEnabled", e);
- retVal = false;
+ } catch (NullPointerException e) {
}
Log.d(TAG, "getDataEnabled: retVal=" + retVal);
return retVal;
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 2d35129..871e04f 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -345,7 +345,8 @@
return ++currentIndex;
} else {
- if ((part.length() == 2 || part.length() == 3) && isAlpha(part)) {
+ if ((part.length() == 2 || part.length() == 3)
+ && isAlpha(part) && strcmp("car", part.string())) {
setLanguage(part);
if (++currentIndex == size) {
return size;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index f4581d0..8a0a39c 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -2531,22 +2531,17 @@
int runInDaemonMode(Bundle* bundle) {
std::cout << "Ready" << std::endl;
- for (std::string line; std::getline(std::cin, line);) {
- if (line == "quit") {
+ for (std::string cmd; std::getline(std::cin, cmd);) {
+ if (cmd == "quit") {
return NO_ERROR;
- }
- std::stringstream ss;
- ss << line;
- std::string s;
-
- std::string command, parameterOne, parameterTwo;
- std::getline(ss, command, ' ');
- std::getline(ss, parameterOne, ' ');
- std::getline(ss, parameterTwo, ' ');
- if (command[0] == 's') {
- bundle->setSingleCrunchInputFile(parameterOne.c_str());
- bundle->setSingleCrunchOutputFile(parameterTwo.c_str());
- std::cout << "Crunching " << parameterOne << std::endl;
+ } else if (cmd == "s") {
+ // Two argument crunch
+ std::string inputFile, outputFile;
+ std::getline(std::cin, inputFile);
+ std::getline(std::cin, outputFile);
+ bundle->setSingleCrunchInputFile(inputFile.c_str());
+ bundle->setSingleCrunchOutputFile(outputFile.c_str());
+ std::cout << "Crunching " << inputFile << std::endl;
if (doSingleCrunch(bundle) != NO_ERROR) {
std::cout << "Error" << std::endl;
}
diff --git a/tools/aapt/tests/AaptConfig_test.cpp b/tools/aapt/tests/AaptConfig_test.cpp
index e795d818..ef3860c 100644
--- a/tools/aapt/tests/AaptConfig_test.cpp
+++ b/tools/aapt/tests/AaptConfig_test.cpp
@@ -76,3 +76,9 @@
EXPECT_TRUE(TestParse("sw600dp-v8", &config));
EXPECT_EQ(String8("sw600dp-v13"), config.toString());
}
+
+TEST(AaptConfigTest, TestParsingOfCarAttribute) {
+ ConfigDescription config;
+ EXPECT_TRUE(TestParse("car", &config));
+ EXPECT_EQ(android::ResTable_config::UI_MODE_TYPE_CAR, config.uiMode);
+}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java b/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java
deleted file mode 100644
index 0100dc5..0000000
--- a/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy;
-
-import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.RenderAction;
-
-import android.content.Context;
-import android.view.BridgeInflater;
-import android.view.FallbackEventHandler;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-/**
- * Custom implementation of PolicyManager that does nothing to run in LayoutLib.
- *
- */
-public class PolicyManager {
-
- public static Window makeNewWindow(Context context) {
- // this will likely crash somewhere beyond so we log it.
- Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
- "Call to PolicyManager.makeNewWindow is not supported", null);
- return null;
- }
-
- public static LayoutInflater makeNewLayoutInflater(Context context) {
- return new BridgeInflater(context, RenderAction.getCurrentContext().getProjectCallback());
- }
-
- public static WindowManagerPolicy makeNewWindowManager() {
- // this will likely crash somewhere beyond so we log it.
- Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
- "Call to PolicyManager.makeNewWindowManager is not supported", null);
- return null;
- }
-
- public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
- return new FallbackEventHandler() {
- @Override
- public void setView(View v) {
- }
-
- @Override
- public void preDispatchKeyEvent(KeyEvent event) {
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- return false;
- }
- };
- }
-}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 8f50c5d..f5e8292 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -254,7 +254,6 @@
"android.view.SurfaceView", "android.view._Original_SurfaceView",
"android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager",
"android.webkit.WebView", "android.webkit._Original_WebView",
- "com.android.internal.policy.PolicyManager", "com.android.internal.policy._Original_PolicyManager",
};
/**