Merge "Fix permissions on cloned data dirs" into jb-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 8a7fb79..d053109 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6532,6 +6532,7 @@
method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
method public abstract void verifyPendingInstall(int, int);
+ method public abstract void extendVerificationTimeout(int, int, long);
field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0
field public static final int COMPONENT_ENABLED_STATE_DISABLED = 2; // 0x2
field public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3; // 0x3
@@ -6602,6 +6603,7 @@
field public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; // 0xfffffffc
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
+ field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80
}
public static class PackageManager.NameNotFoundException extends android.util.AndroidException {
@@ -20056,6 +20058,7 @@
method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public void setInteractive(boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.dreams.Dream";
+ field public static final java.lang.String METADATA_NAME_CONFIG_ACTIVITY = "android.service.dreams.config_activity";
}
}
@@ -21370,6 +21373,7 @@
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
method public void verifyPendingInstall(int, int);
+ method public void extendVerificationTimeout(int, int, long);
}
public class MockResources extends android.content.res.Resources {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 395a79c..d5580b7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -48,6 +48,7 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.StrictMode;
+import android.os.UserHandle;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -3384,6 +3385,31 @@
}
/**
+ * @hide Implement to provide correct calling token.
+ */
+ public void startActivityAsUser(Intent intent, UserHandle user) {
+ startActivityAsUser(intent, null, user);
+ }
+
+ /**
+ * @hide Implement to provide correct calling token.
+ */
+ public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
+ if (mParent != null) {
+ throw new RuntimeException("Called be called from a child");
+ }
+ Instrumentation.ActivityResult ar =
+ mInstrumentation.execStartActivity(
+ this, mMainThread.getApplicationThread(), mToken, this,
+ intent, -1, options, user);
+ if (ar != null) {
+ mMainThread.sendActivityResult(
+ mToken, mEmbeddedID, -1, ar.getResultCode(),
+ ar.getResultData());
+ }
+ }
+
+ /**
* Same as calling {@link #startIntentSenderForResult(IntentSender, int,
* Intent, int, int, int, Bundle)} with no options.
*
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 28c5abd..b8e16c5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4070,10 +4070,14 @@
if (!Process.isIsolated()) {
final File cacheDir = appContext.getCacheDir();
- // Provide a usable directory for temporary files
- System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
-
- setupGraphicsSupport(data.info, cacheDir);
+ 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");
+ }
}
/**
* For system applications on userdebug/eng builds, log stack
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 86ee8a0..f3f75ce 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1006,6 +1006,16 @@
}
@Override
+ public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
+ long millisecondsToDelay) {
+ try {
+ mPM.extendVerificationTimeout(id, verificationCodeAtTimeout, millisecondsToDelay);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
public void setInstallerPackageName(String targetPackage,
String installerPackageName) {
try {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 0543f05..0ae4d06 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -769,7 +769,7 @@
}
if (!mCacheDir.exists()) {
if(!mCacheDir.mkdirs()) {
- Log.w(TAG, "Unable to create cache directory");
+ Log.w(TAG, "Unable to create cache directory " + mCacheDir.getAbsolutePath());
return null;
}
FileUtils.setPermissions(
@@ -909,14 +909,7 @@
/** @hide */
@Override
public void startActivityAsUser(Intent intent, UserHandle user) {
- try {
- ActivityManagerNative.getDefault().startActivityAsUser(
- mMainThread.getApplicationThread(), intent,
- intent.resolveTypeIfNeeded(getContentResolver()),
- null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null, null,
- user.getIdentifier());
- } catch (RemoteException re) {
- }
+ startActivityAsUser(intent, null, user);
}
@Override
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index cad4b01..ee4e964 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -33,6 +33,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.view.IWindowManager;
@@ -1518,6 +1519,66 @@
return null;
}
+ /**
+ * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int)},
+ * but for starting as a particular user.
+ *
+ * @param who The Context from which the activity is being started.
+ * @param contextThread The main thread of the Context from which the activity
+ * is being started.
+ * @param token Internal token identifying to the system who is starting
+ * the activity; may be null.
+ * @param target Which fragment is performing the start (and thus receiving
+ * any result).
+ * @param intent The actual Intent to start.
+ * @param requestCode Identifier for this request's result; less than zero
+ * if the caller is not expecting a result.
+ *
+ * @return To force the return of a particular result, return an
+ * ActivityResult object containing the desired data; otherwise
+ * return null. The default implementation always returns null.
+ *
+ * @throws android.content.ActivityNotFoundException
+ *
+ * @see Activity#startActivity(Intent)
+ * @see Activity#startActivityForResult(Intent, int)
+ * @see Activity#startActivityFromChild
+ *
+ * {@hide}
+ */
+ public ActivityResult execStartActivity(
+ Context who, IBinder contextThread, IBinder token, Activity target,
+ Intent intent, int requestCode, Bundle options, UserHandle user) {
+ IApplicationThread whoThread = (IApplicationThread) contextThread;
+ if (mActivityMonitors != null) {
+ synchronized (mSync) {
+ final int N = mActivityMonitors.size();
+ for (int i=0; i<N; i++) {
+ final ActivityMonitor am = mActivityMonitors.get(i);
+ if (am.match(who, null, intent)) {
+ am.mHits++;
+ if (am.isBlocking()) {
+ return requestCode >= 0 ? am.getResult() : null;
+ }
+ break;
+ }
+ }
+ }
+ }
+ try {
+ intent.setAllowFds(false);
+ intent.migrateExtraStreamToClipData();
+ int result = ActivityManagerNative.getDefault()
+ .startActivityAsUser(whoThread, intent,
+ intent.resolveTypeIfNeeded(who.getContentResolver()),
+ token, target != null ? target.mEmbeddedID : null,
+ requestCode, 0, null, null, options, user.getIdentifier());
+ checkStartActivityResult(result, intent);
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
/*package*/ final void init(ActivityThread thread,
Context instrContext, Context appContext, ComponentName component,
IInstrumentationWatcher watcher) {
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 3f4b994..0be8b83 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -370,6 +370,7 @@
in ContainerEncryptionParams encryptionParams);
void verifyPendingInstall(int id, int verificationCode);
+ void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay);
VerifierDeviceIdentity getVerifierDeviceIdentity();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0461dd1..b3e98e7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -762,6 +762,14 @@
public static final int VERIFICATION_REJECT = -1;
/**
+ * Can be used as the {@code millisecondsToDelay} argument for
+ * {@link PackageManager#extendVerificationTimeout}. This is the
+ * maximum time {@code PackageManager} waits for the verification
+ * agent to return (in milliseconds).
+ */
+ public static final long MAXIMUM_VERIFICATION_TIMEOUT = 60*60*1000;
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device's
* audio pipeline is low-latency, more suitable for audio applications sensitive to delays or
* lag in sound input or output.
@@ -2274,6 +2282,33 @@
public abstract void verifyPendingInstall(int id, int verificationCode);
/**
+ * Allows a package listening to the
+ * {@link Intent#ACTION_PACKAGE_NEEDS_VERIFICATION package verification
+ * broadcast} to extend the default timeout for a response and declare what
+ * action to perform after the timeout occurs. The response must include
+ * the {@code verificationCodeAtTimeout} which is one of
+ * {@link PackageManager#VERIFICATION_ALLOW} or
+ * {@link PackageManager#VERIFICATION_REJECT}.
+ *
+ * This method may only be called once per package id. Additional calls
+ * will have no effect.
+ *
+ * @param id pending package identifier as passed via the
+ * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra
+ * @param verificationCodeAtTimeout either
+ * {@link PackageManager#VERIFICATION_ALLOW} or
+ * {@link PackageManager#VERIFICATION_REJECT}.
+ * @param millisecondsToDelay the amount of time requested for the timeout.
+ * Must be positive and less than
+ * {@link PackageManager#MAXIMUM_VERIFICATION_TIMEOUT}.
+ *
+ * @throws IllegalArgumentException if {@code millisecondsToDelay} is out
+ * of bounds or {@code verificationCodeAtTimeout} is unknown.
+ */
+ public abstract void extendVerificationTimeout(int id,
+ int verificationCodeAtTimeout, long millisecondsToDelay);
+
+ /**
* Change the installer associated with a given package. There are limitations
* on how the installer package can be changed; in particular:
* <ul>
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index a73115c..98d2f69 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -24,7 +24,6 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
-import android.util.SparseArray;
import android.view.CompatibilityInfoHolder;
import android.view.Display;
import android.view.DisplayInfo;
diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java
new file mode 100644
index 0000000..99bd647
--- /dev/null
+++ b/core/java/android/net/BaseNetworkStateTracker.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.content.Context;
+import android.os.Handler;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Interface to control and observe state of a specific network, hiding
+ * network-specific details from {@link ConnectivityManager}. Surfaces events
+ * through the registered {@link Handler} to enable {@link ConnectivityManager}
+ * to respond to state changes over time.
+ *
+ * @hide
+ */
+public abstract class BaseNetworkStateTracker implements NetworkStateTracker {
+ // TODO: better document threading expectations
+ // TODO: migrate to make NetworkStateTracker abstract class
+
+ public static final String PROP_TCP_BUFFER_UNKNOWN = "net.tcp.buffersize.unknown";
+ public static final String PROP_TCP_BUFFER_WIFI = "net.tcp.buffersize.wifi";
+
+ protected Context mContext;
+ private Handler mTarget;
+
+ protected NetworkInfo mNetworkInfo;
+ protected LinkProperties mLinkProperties;
+ protected LinkCapabilities mLinkCapabilities;
+
+ private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
+ private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
+ private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
+
+ public BaseNetworkStateTracker(int networkType) {
+ mNetworkInfo = new NetworkInfo(
+ networkType, -1, ConnectivityManager.getNetworkTypeName(networkType), null);
+ mLinkProperties = new LinkProperties();
+ mLinkCapabilities = new LinkCapabilities();
+ }
+
+ @Deprecated
+ protected Handler getTargetHandler() {
+ return mTarget;
+ }
+
+ protected final void dispatchStateChanged() {
+ // TODO: include snapshot of other fields when sending
+ mTarget.obtainMessage(EVENT_STATE_CHANGED, getNetworkInfo()).sendToTarget();
+ }
+
+ protected final void dispatchConfigurationChanged() {
+ // TODO: include snapshot of other fields when sending
+ mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, getNetworkInfo()).sendToTarget();
+ }
+
+ @Override
+ public final void startMonitoring(Context context, Handler target) {
+ mContext = Preconditions.checkNotNull(context);
+ mTarget = Preconditions.checkNotNull(target);
+ startMonitoringInternal();
+ }
+
+ protected abstract void startMonitoringInternal();
+
+ @Override
+ public final NetworkInfo getNetworkInfo() {
+ return new NetworkInfo(mNetworkInfo);
+ }
+
+ @Override
+ public final LinkProperties getLinkProperties() {
+ return new LinkProperties(mLinkProperties);
+ }
+
+ @Override
+ public final LinkCapabilities getLinkCapabilities() {
+ return new LinkCapabilities(mLinkCapabilities);
+ }
+
+ @Override
+ public boolean setRadio(boolean turnOn) {
+ // Base tracker doesn't handle radios
+ return true;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return mNetworkInfo.isAvailable();
+ }
+
+ @Override
+ public void setUserDataEnable(boolean enabled) {
+ // Base tracker doesn't handle enabled flags
+ }
+
+ @Override
+ public void setPolicyDataEnable(boolean enabled) {
+ // Base tracker doesn't handle enabled flags
+ }
+
+ @Override
+ public boolean isPrivateDnsRouteSet() {
+ return mPrivateDnsRouteSet.get();
+ }
+
+ @Override
+ public void privateDnsRouteSet(boolean enabled) {
+ mPrivateDnsRouteSet.set(enabled);
+ }
+
+ @Override
+ public boolean isDefaultRouteSet() {
+ return mDefaultRouteSet.get();
+ }
+
+ @Override
+ public void defaultRouteSet(boolean enabled) {
+ mDefaultRouteSet.set(enabled);
+ }
+
+ @Override
+ public boolean isTeardownRequested() {
+ return mTeardownRequested.get();
+ }
+
+ @Override
+ public void setTeardownRequested(boolean isRequested) {
+ mTeardownRequested.set(isRequested);
+ }
+
+ @Override
+ public void setDependencyMet(boolean met) {
+ // Base tracker doesn't handle dependencies
+ }
+}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 92aeff2..dea25dd 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -26,6 +26,7 @@
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
/**
* Interface that answers queries about, and allows changing, the
@@ -118,7 +119,7 @@
ParcelFileDescriptor establishVpn(in VpnConfig config);
- void startLegacyVpn(in VpnConfig config, in String[] racoon, in String[] mtpd);
+ void startLegacyVpn(in VpnProfile profile);
LegacyVpnInfo getLegacyVpnInfo();
}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 20d3ec3..2179fa1 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -362,4 +362,11 @@
* Flush the DNS cache associated with the specified interface.
*/
void flushInterfaceDnsCache(String iface);
+
+ void setFirewallEnabled(boolean enabled);
+ boolean isFirewallEnabled();
+ void setFirewallInterfaceRule(String iface, boolean allow);
+ void setFirewallEgressSourceRule(String addr, boolean allow);
+ void setFirewallEgressDestRule(String addr, int port, boolean allow);
+ void setFirewallUidRule(int uid, boolean allow);
}
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 43cf74e..0d11ab4 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -40,6 +40,7 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -326,7 +327,8 @@
throws IOException {
String filename = packageFile.getCanonicalPath();
Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
- String arg = "--update_package=" + filename;
+ String arg = "--update_package=" + filename +
+ "\n--locale=" + Locale.getDefault().toString();
bootCommand(context, arg);
}
@@ -357,7 +359,7 @@
// Block until the ordered broadcast has completed.
condition.block();
- bootCommand(context, "--wipe_data");
+ bootCommand(context, "--wipe_data\n--locale=" + Locale.getDefault().toString());
}
/**
@@ -365,7 +367,7 @@
* @throws IOException if something goes wrong.
*/
public static void rebootWipeCache(Context context) throws IOException {
- bootCommand(context, "--wipe_cache");
+ bootCommand(context, "--wipe_cache\n--locale=" + Locale.getDefault().toString());
}
/**
diff --git a/core/java/android/os/SystemService.java b/core/java/android/os/SystemService.java
index db58012..f345271 100644
--- a/core/java/android/os/SystemService.java
+++ b/core/java/android/os/SystemService.java
@@ -16,6 +16,8 @@
package android.os;
+import android.util.Slog;
+
import com.google.android.collect.Maps;
import java.util.HashMap;
@@ -81,7 +83,7 @@
if (state != null) {
return state;
} else {
- throw new IllegalStateException("Service " + service + " in unknown state " + rawState);
+ return State.STOPPED;
}
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
old mode 100644
new mode 100755
index 0c16565..08621ea
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -8362,7 +8362,7 @@
// Line contains the query string - now search for it at the start of tokens.
List<String> lineTokens = new ArrayList<String>();
List<Integer> tokenOffsets = new ArrayList<Integer>();
- split(contentLine.trim(), lineTokens, tokenOffsets);
+ split(contentLine, lineTokens, tokenOffsets);
// As we find matches against the query, we'll populate this list with the marked
// (or unchanged) tokens.
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 79d0144..48d84c1 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -120,7 +120,7 @@
*/
public static final String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH =
"android.media.action.MEDIA_PLAY_FROM_SEARCH";
-
+
/**
* The name of the Intent-extra used to define the artist
*/
@@ -173,6 +173,23 @@
public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
/**
+ * The name of the Intent action used to launch a camera in still image mode
+ * for use when the device is secured (e.g. with a pin, password, pattern,
+ * or face unlock). Applications responding to this intent must not expose
+ * any personal content like existing photos or videos on the device. The
+ * applications should be careful not to share any photo or video with other
+ * applications or internet. The activity should use {@link
+ * android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} to display
+ * on top of the lock screen while secured. There is no activity stack when
+ * this flag is used, so launching more than one activity is strongly
+ * discouraged.
+ *
+ * @hide
+ */
+ public static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE =
+ "android.media.action.STILL_IMAGE_CAMERA_SECURE";
+
+ /**
* The name of the Intent action used to launch a camera in video mode.
*/
public static final String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 28273f0..1f6f0dd 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4248,27 +4248,40 @@
"setup_prepaid_detection_redir_host";
/**
- * Whether the screensaver is enabled.
+ * Whether screensavers are enabled.
* @hide
*/
public static final String SCREENSAVER_ENABLED = "screensaver_enabled";
/**
- * The user's chosen screensaver component.
+ * The user's chosen screensaver components.
*
- * This component will be launched by the PhoneWindowManager after a timeout when not on
+ * These will be launched by the PhoneWindowManager after a timeout when not on
* battery, or upon dock insertion (if SCREENSAVER_ACTIVATE_ON_DOCK is set to 1).
* @hide
*/
- public static final String SCREENSAVER_COMPONENT = "screensaver_component";
+ public static final String SCREENSAVER_COMPONENTS = "screensaver_components";
/**
- * Whether the screensaver should be automatically launched when the device is inserted
- * into a (desk) dock.
+ * If screensavers are enabled, whether the screensaver should be automatically launched
+ * when the device is inserted into a (desk) dock.
* @hide
*/
public static final String SCREENSAVER_ACTIVATE_ON_DOCK = "screensaver_activate_on_dock";
+ /**
+ * If screensavers are enabled, whether the screensaver should be automatically launched
+ * when the screen times out when not on battery.
+ * @hide
+ */
+ public static final String SCREENSAVER_ACTIVATE_ON_SLEEP = "screensaver_activate_on_sleep";
+
+ /**
+ * If screensavers are enabled, the default screensaver component.
+ * @hide
+ */
+ public static final String SCREENSAVER_DEFAULT_COMPONENT = "screensaver_default_component";
+
/** {@hide} */
public static final String NETSTATS_ENABLED = "netstats_enabled";
/** {@hide} */
diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java
index 69db97c..ba2ac67 100644
--- a/core/java/android/service/dreams/Dream.java
+++ b/core/java/android/service/dreams/Dream.java
@@ -56,6 +56,10 @@
public static final String SERVICE_INTERFACE =
"android.service.dreams.Dream";
+ /** Service meta-data key for declaring an optional configuration activity. */
+ public static final String METADATA_NAME_CONFIG_ACTIVITY =
+ "android.service.dreams.config_activity";
+
private Window mWindow;
private WindowManager mWindowManager;
diff --git a/core/java/android/service/dreams/DreamManagerService.java b/core/java/android/service/dreams/DreamManagerService.java
index 5d6b17e..4b0f7c5 100644
--- a/core/java/android/service/dreams/DreamManagerService.java
+++ b/core/java/android/service/dreams/DreamManagerService.java
@@ -1,7 +1,7 @@
package android.service.dreams;
-import static android.provider.Settings.Secure.SCREENSAVER_COMPONENT;
-
+import static android.provider.Settings.Secure.SCREENSAVER_COMPONENTS;
+import static android.provider.Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -58,7 +58,8 @@
// IDreamManager method
@Override
public void dream() {
- ComponentName name = getDreamComponent();
+ ComponentName[] dreams = getDreamComponents();
+ ComponentName name = dreams != null && dreams.length > 0 ? dreams[0] : null;
if (name != null) {
synchronized (mLock) {
final long ident = Binder.clearCallingIdentity();
@@ -73,21 +74,45 @@
// IDreamManager method
@Override
- public void setDreamComponent(ComponentName name) {
- Settings.Secure.putString(mContext.getContentResolver(), SCREENSAVER_COMPONENT, name.flattenToString());
+ public void setDreamComponents(ComponentName[] componentNames) {
+ Settings.Secure.putString(mContext.getContentResolver(),
+ SCREENSAVER_COMPONENTS,
+ componentsToString(componentNames));
+ }
+
+ private static String componentsToString(ComponentName[] componentNames) {
+ StringBuilder names = new StringBuilder();
+ if (componentNames != null) {
+ for (ComponentName componentName : componentNames) {
+ if (names.length() > 0)
+ names.append(',');
+ names.append(componentName.flattenToString());
+ }
+ }
+ return names.toString();
+ }
+
+ private static ComponentName[] componentsFromString(String names) {
+ String[] namesArray = names.split(",");
+ ComponentName[] componentNames = new ComponentName[namesArray.length];
+ for (int i = 0; i < namesArray.length; i++)
+ componentNames[i] = ComponentName.unflattenFromString(namesArray[i]);
+ return componentNames;
}
// IDreamManager method
@Override
- public ComponentName getDreamComponent() {
+ public ComponentName[] getDreamComponents() {
// TODO(dsandler) don't load this every time, watch the value
- String component = Settings.Secure.getString(mContext.getContentResolver(), SCREENSAVER_COMPONENT);
- if (component != null) {
- return ComponentName.unflattenFromString(component);
- } else {
- // We rely on DatabaseHelper to set a sane default for us when the settings DB is upgraded
- return null;
- }
+ String names = Settings.Secure.getString(mContext.getContentResolver(), SCREENSAVER_COMPONENTS);
+ return componentsFromString(names);
+ }
+
+ // IDreamManager method
+ @Override
+ public ComponentName getDefaultDreamComponent() {
+ String name = Settings.Secure.getString(mContext.getContentResolver(), SCREENSAVER_DEFAULT_COMPONENT);
+ return name == null ? null : ComponentName.unflattenFromString(name);
}
// IDreamManager method
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index b64dd8f..b6fcdf0 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -24,8 +24,9 @@
interface IDreamManager {
void dream();
void awaken();
- void setDreamComponent(in ComponentName componentName);
- ComponentName getDreamComponent();
+ void setDreamComponents(in ComponentName[] componentNames);
+ ComponentName[] getDreamComponents();
+ ComponentName getDefaultDreamComponent();
void testDream(in ComponentName componentName);
boolean isDreaming();
}
\ No newline at end of file
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 517b514..a6d1a3f 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -388,8 +388,8 @@
/** Free all server-side state associated with this surface and
* release this object's reference. @hide */
public native void destroy();
-
- private native Canvas lockCanvasNative(Rect dirty);
+
+ private native Canvas lockCanvasNative(Rect dirty) throws OutOfResourcesException;
/**
* set the orientation of the given display.
@@ -497,10 +497,10 @@
}
private native void init(SurfaceSession s,
- int pid, String name, int displayId, int w, int h, int format, int flags)
+ int pid, String name, int layerStack, int w, int h, int format, int flags)
throws OutOfResourcesException;
- private native void init(Parcel source);
+ private native void init(Parcel source) throws OutOfResourcesException;
private native void initFromSurfaceTexture(SurfaceTexture surfaceTexture);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 548d4ad9..e754adc 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1577,8 +1577,8 @@
try {
if (DEBUG) Log.v(TAG, "DISPATCH KEY: " + mCurMethod);
final long startTime = SystemClock.uptimeMillis();
- mCurMethod.dispatchKeyEvent(seq, key, mInputMethodCallback);
enqueuePendingEventLocked(startTime, seq, mCurId, callback);
+ mCurMethod.dispatchKeyEvent(seq, key, mInputMethodCallback);
return;
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId + " dropping: " + key, e);
@@ -1602,8 +1602,8 @@
try {
if (DEBUG) Log.v(TAG, "DISPATCH TRACKBALL: " + mCurMethod);
final long startTime = SystemClock.uptimeMillis();
- mCurMethod.dispatchTrackballEvent(seq, motion, mInputMethodCallback);
enqueuePendingEventLocked(startTime, seq, mCurId, callback);
+ mCurMethod.dispatchTrackballEvent(seq, motion, mInputMethodCallback);
return;
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId + " dropping trackball: " + motion, e);
diff --git a/core/java/android/webkit/HttpAuthHandler.java b/core/java/android/webkit/HttpAuthHandler.java
index b3571aa..296d960 100644
--- a/core/java/android/webkit/HttpAuthHandler.java
+++ b/core/java/android/webkit/HttpAuthHandler.java
@@ -28,9 +28,9 @@
public class HttpAuthHandler extends Handler {
/**
- * Package-private constructor needed for API compatibility.
+ * @hide Only for use by WebViewProvider implementations.
*/
- HttpAuthHandler() {
+ public HttpAuthHandler() {
}
/**
diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java
index 426145a..3a43950 100644
--- a/core/java/android/webkit/SslErrorHandler.java
+++ b/core/java/android/webkit/SslErrorHandler.java
@@ -26,9 +26,9 @@
public class SslErrorHandler extends Handler {
/**
- * Package-private constructor needed for API compatibility.
+ * @hide Only for use by WebViewProvider implementations.
*/
- SslErrorHandler() {}
+ public SslErrorHandler() {}
/**
* Proceed with the SSL certificate.
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 18c4fe6..ff0579c 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -22,6 +22,7 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.FocusFinder;
import android.view.InputDevice;
import android.view.KeyEvent;
@@ -62,6 +63,7 @@
private static final float MAX_SCROLL_FACTOR = ScrollView.MAX_SCROLL_FACTOR;
+ private static final String TAG = "HorizontalScrollView";
private long mLastScroll;
@@ -456,6 +458,12 @@
}
final int pointerIndex = ev.findPointerIndex(activePointerId);
+ if (pointerIndex == -1) {
+ Log.e(TAG, "Invalid pointerId=" + activePointerId
+ + " in onInterceptTouchEvent");
+ break;
+ }
+
final int x = (int) ev.getX(pointerIndex);
final int xDiff = (int) Math.abs(x - mLastMotionX);
if (xDiff > mTouchSlop) {
@@ -557,6 +565,11 @@
}
case MotionEvent.ACTION_MOVE:
final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (activePointerIndex == -1) {
+ Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
+ break;
+ }
+
final int x = (int) ev.getX(activePointerIndex);
int deltaX = mLastMotionX - x;
if (!mIsBeingDragged && Math.abs(deltaX) > mTouchSlop) {
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 1711154..bc41931 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -25,6 +25,7 @@
import android.os.Bundle;
import android.os.StrictMode;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.FocusFinder;
import android.view.InputDevice;
import android.view.KeyEvent;
@@ -69,6 +70,8 @@
static final float MAX_SCROLL_FACTOR = 0.5f;
+ private static final String TAG = "ScrollView";
+
private long mLastScroll;
private final Rect mTempRect = new Rect();
@@ -485,6 +488,12 @@
}
final int pointerIndex = ev.findPointerIndex(activePointerId);
+ if (pointerIndex == -1) {
+ Log.e(TAG, "Invalid pointerId=" + activePointerId
+ + " in onInterceptTouchEvent");
+ break;
+ }
+
final int y = (int) ev.getY(pointerIndex);
final int yDiff = Math.abs(y - mLastMotionY);
if (yDiff > mTouchSlop) {
@@ -592,6 +601,11 @@
}
case MotionEvent.ACTION_MOVE:
final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (activePointerIndex == -1) {
+ Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
+ break;
+ }
+
final int y = (int) ev.getY(activePointerIndex);
int deltaY = mLastMotionY - y;
if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
diff --git a/core/java/android/widget/TableLayout.java b/core/java/android/widget/TableLayout.java
index b8ffe8d..113299a 100644
--- a/core/java/android/widget/TableLayout.java
+++ b/core/java/android/widget/TableLayout.java
@@ -184,6 +184,10 @@
mShrinkableColumns = new SparseBooleanArray();
}
+ // TableLayouts are always in vertical orientation; keep this tracked
+ // for shared LinearLayout code.
+ setOrientation(VERTICAL);
+
mPassThroughListener = new PassThroughHierarchyChangeListener();
// make sure to call the parent class method to avoid potential
// infinite loops
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index ff1dd11..7c8196d 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -284,6 +284,7 @@
mVideoHeight = mp.getVideoHeight();
if (mVideoWidth != 0 && mVideoHeight != 0) {
getHolder().setFixedSize(mVideoWidth, mVideoHeight);
+ requestLayout();
}
}
};
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 52cb679..7d1231e 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -28,9 +28,12 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
+import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
+import android.widget.TextView;
import java.text.Collator;
import java.util.Arrays;
@@ -86,7 +89,7 @@
}
public static ArrayAdapter<LocaleInfo> constructAdapter(Context context,
- int layoutId, int fieldId) {
+ final int layoutId, final int fieldId) {
final Resources resources = context.getResources();
final String[] locales = Resources.getSystem().getAssets().getLocales();
final String[] specialLocaleCodes = resources.getStringArray(R.array.special_locale_codes);
@@ -154,7 +157,29 @@
localeInfos[i] = preprocess[i];
}
Arrays.sort(localeInfos);
- return new ArrayAdapter<LocaleInfo>(context, layoutId, fieldId, localeInfos);
+
+ final LayoutInflater inflater =
+ (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ return new ArrayAdapter<LocaleInfo>(context, layoutId, fieldId, localeInfos) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view;
+ TextView text;
+ if (convertView == null) {
+ view = inflater.inflate(layoutId, parent, false);
+ text = (TextView) view.findViewById(fieldId);
+ view.setTag(text);
+ } else {
+ view = convertView;
+ text = (TextView) view.getTag();
+ }
+ LocaleInfo item = getItem(position);
+ text.setText(item.toString());
+ text.setTextLocale(item.getLocale());
+
+ return view;
+ }
+ };
}
private static String toTitleCase(String s) {
@@ -230,4 +255,4 @@
// Intentionally left blank
}
}
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/net/LegacyVpnInfo.java b/core/java/com/android/internal/net/LegacyVpnInfo.java
index b620abac..d6f6d0b 100644
--- a/core/java/com/android/internal/net/LegacyVpnInfo.java
+++ b/core/java/com/android/internal/net/LegacyVpnInfo.java
@@ -17,8 +17,10 @@
package com.android.internal.net;
import android.app.PendingIntent;
+import android.net.NetworkInfo;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
/**
* A simple container used to carry information of the ongoing legacy VPN.
@@ -27,6 +29,8 @@
* @hide
*/
public class LegacyVpnInfo implements Parcelable {
+ private static final String TAG = "LegacyVpnInfo";
+
public static final int STATE_DISCONNECTED = 0;
public static final int STATE_INITIALIZING = 1;
public static final int STATE_CONNECTING = 2;
@@ -66,4 +70,25 @@
return new LegacyVpnInfo[size];
}
};
+
+ /**
+ * Return best matching {@link LegacyVpnInfo} state based on given
+ * {@link NetworkInfo}.
+ */
+ public static int stateFromNetworkInfo(NetworkInfo info) {
+ switch (info.getDetailedState()) {
+ case CONNECTING:
+ return STATE_CONNECTING;
+ case CONNECTED:
+ return STATE_CONNECTED;
+ case DISCONNECTED:
+ return STATE_DISCONNECTED;
+ case FAILED:
+ return STATE_FAILED;
+ default:
+ Log.w(TAG, "Unhandled state " + info.getDetailedState()
+ + " ; treating as disconnected");
+ return STATE_DISCONNECTED;
+ }
+ }
}
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index d6f9e07..956653b 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -22,6 +22,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
import java.util.List;
/**
@@ -45,13 +47,14 @@
}
public static PendingIntent getIntentForStatusPanel(Context context, VpnConfig config) {
+ Preconditions.checkNotNull(config);
+
Intent intent = new Intent();
intent.setClassName(DIALOGS_PACKAGE, DIALOGS_PACKAGE + ".ManageDialog");
intent.putExtra("config", config);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY |
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- return PendingIntent.getActivity(context, 0, intent, (config == null) ?
- PendingIntent.FLAG_NO_CREATE : PendingIntent.FLAG_CANCEL_CURRENT);
+ return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
}
public String user;
@@ -64,6 +67,7 @@
public List<String> searchDomains;
public PendingIntent configureIntent;
public long startTime = -1;
+ public boolean legacy;
@Override
public int describeContents() {
@@ -82,6 +86,7 @@
out.writeStringList(searchDomains);
out.writeParcelable(configureIntent, flags);
out.writeLong(startTime);
+ out.writeInt(legacy ? 1 : 0);
}
public static final Parcelable.Creator<VpnConfig> CREATOR =
@@ -99,6 +104,7 @@
config.searchDomains = in.createStringArrayList();
config.configureIntent = in.readParcelable(null);
config.startTime = in.readLong();
+ config.legacy = in.readInt() != 0;
return config;
}
diff --git a/core/java/com/android/internal/net/VpnProfile.aidl b/core/java/com/android/internal/net/VpnProfile.aidl
new file mode 100644
index 0000000..a072160
--- /dev/null
+++ b/core/java/com/android/internal/net/VpnProfile.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.net;
+
+parcelable VpnProfile;
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 154b16b..d6c5702 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -16,6 +16,9 @@
package com.android.internal.net;
+import android.os.Parcel;
+import android.os.Parcelable;
+
import java.nio.charset.Charsets;
/**
@@ -27,7 +30,7 @@
*
* @hide
*/
-public class VpnProfile implements Cloneable {
+public class VpnProfile implements Cloneable, Parcelable {
// Match these constants with R.array.vpn_types.
public static final int TYPE_PPTP = 0;
public static final int TYPE_L2TP_IPSEC_PSK = 1;
@@ -120,4 +123,28 @@
builder.append('\0').append(ipsecServerCert);
return builder.toString().getBytes(Charsets.UTF_8);
}
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(key);
+ out.writeByteArray(encode());
+ }
+
+ public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() {
+ @Override
+ public VpnProfile createFromParcel(Parcel in) {
+ final String key = in.readString();
+ return decode(key, in.createByteArray());
+ }
+
+ @Override
+ public VpnProfile[] newArray(int size) {
+ return new VpnProfile[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
}
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index a53a9c0..a327adc 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -54,4 +54,16 @@
return reference;
}
+ /**
+ * Ensures the truth of an expression involving the state of the calling
+ * instance, but not involving any parameters to the calling method.
+ *
+ * @param expression a boolean expression
+ * @throws IllegalStateException if {@code expression} is false
+ */
+ public static void checkState(boolean expression) {
+ if (!expression) {
+ throw new IllegalStateException();
+ }
+ }
}
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index ad03dd2..560a6a8 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -224,10 +224,8 @@
<string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Laat die program toe om aksies vir verskillende gebruikers op die toestel uit te voer. Kwaadwillige programme kan dit gebruik om die beskerming tussen gebruikers te skend."</string>
<string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"volle lisensie vir interaksie tussen gebruikers"</string>
<string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Laat alle moontlike interaksies tussen gebruikers toe."</string>
- <!-- no translation found for permlab_manageUsers (1676150911672282428) -->
- <skip />
- <!-- no translation found for permdesc_manageUsers (8409306667645355638) -->
- <skip />
+ <string name="permlab_manageUsers" msgid="1676150911672282428">"bestuur gebruikers"</string>
+ <string name="permdesc_manageUsers" msgid="8409306667645355638">"Laat programme toe om gebruikers op die toestel te bestuur, insluitend navrae, skepping en uitvee."</string>
<string name="permlab_getDetailedTasks" msgid="6229468674753529501">"haal besonderhede van lopende programme op"</string>
<string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Laat die program toe om inligting op te haal oor huidige en onlangse lopende take. Kwaadwillige programme kan dalk private inligting oor ander programme ontdek."</string>
<string name="permlab_reorderTasks" msgid="2018575526934422779">"herrangskik lopende programme"</string>
@@ -1313,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-oudio"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klaar"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Ingeboude skerm"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 14d95a5..d3b8f04 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"صوت بلوتوث"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"تم"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"المنفذ الإعلامي"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"شاشة مدمجة"</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 81ba8a7..7e7c4e6 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Звук през Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Изходяща мултимедия"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Вграден екран"</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 4e7da84..50cd013 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth Audio"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Integrovaná obrazovka"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 9108337..00d8617 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Listo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Pantalla integrada"</string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 872f485..8280b61 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-heli"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Valmis"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Meediaväljund"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Sisseehitatud ekraan"</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index ecdebe8..0dba1bd 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوتوثهای صوتی"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"انجام شد"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"خروجی رسانه"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"صفحه نمایش از خود"</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index c35fe8d..d4d938b 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"OK"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Sortie multimédia"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Écran intégré"</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 6ea8f7b..b491e97 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ऑडियो"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"पूर्ण"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"मीडिया आउटपुट"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"अंतर्निहित स्क्रीन"</string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 26bc6ec..aef3bdf 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth zvuk"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotovo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medijski izlaz"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Ugrađeni zaslon"</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 42e7888..90bd85e 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth hang"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kész"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Médiakimenet"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Beépített képernyő"</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index dc0c139..b7a9c3b 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth音声"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完了"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"メディア出力"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"内蔵画面"</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index f6ae2af..0193ca2 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"블루투스 오디오"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"완료"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"미디어 출력"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"기본으로 제공되는 화면"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 7692620..cfc9b9b 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"„Bluetooth“ garsas"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Atlikta"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medijos išvestis"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Integruotas ekranas"</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d63c45b..4b78bd4 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gatavs"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Multivides izeja"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Iebūvēts ekrāns"</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index a22ff51..782c2a7 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Output media"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Skrin Terbina Dalam"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e16d308..f0dcc2f 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Dźwięk Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotowe"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Wyjście multimediów"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Wbudowany ekran"</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 996be49..18c25a3 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Concluído"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de som multimédia"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Ecrã Integrado"</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 7d7672f..794af68 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Concluído"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de mídia"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Tela integrada"</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 6300a1f4..6f6272d 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Terminat"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Rezultate media"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Ecran încorporat"</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 004b2b6..a9c0701 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Воспроизведение звука через Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Перенаправлять поток мультимедиа"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Встроенный экран"</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 15c359c..6240be3 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Vstavaná obrazovka"</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index e4cf347..4ddde21 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Излаз медија"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Уграђени екран"</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index c25e6db..efb1d6f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"เสียงบลูทูธ"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"เสร็จสิ้น"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"เอาต์พุตสื่อ"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"หน้าจอในตัว"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index ab4ff29..261a0b9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio sa Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tapos na"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Output ng media"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Built-in na Screen"</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 95637dc..c60535f 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ses"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tamamlandı"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medya çıkışı"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Yerleşik Ekran"</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 384a1ee..012a47a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Âm thanh Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Xong"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Đầu ra phương tiện"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Màn hình tích hợp"</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 289dcf8..e982c75 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"蓝牙音频"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"媒体输出线路"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"内置屏幕"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 96ba8c1..36eba9f 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音訊"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"媒體輸出"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"內建畫面"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 2a17f8f..78b287c 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Umsindo we-Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Qedile"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Okukhiphayo kwemidiya"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Okwakhelwe ngaphakathi kwesikrini"</string>
</resources>
diff --git a/docs/downloads/training/TabCompat.zip b/docs/downloads/training/TabCompat.zip
index b70b442..b907b42 100644
--- a/docs/downloads/training/TabCompat.zip
+++ b/docs/downloads/training/TabCompat.zip
Binary files differ
diff --git a/docs/html/guide/google/gcm/adv.jd b/docs/html/guide/google/gcm/adv.jd
index 5cb433f..2174128 100644
--- a/docs/html/guide/google/gcm/adv.jd
+++ b/docs/html/guide/google/gcm/adv.jd
@@ -175,7 +175,8 @@
<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, which returns a "package not found" error.</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>
diff --git a/docs/html/guide/google/gcm/client-javadoc/allclasses-frame.html b/docs/html/guide/google/gcm/client-javadoc/allclasses-frame.html
index 26916d5..e1bed36 100644
--- a/docs/html/guide/google/gcm/client-javadoc/allclasses-frame.html
+++ b/docs/html/guide/google/gcm/client-javadoc/allclasses-frame.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
All Classes
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/allclasses-noframe.html b/docs/html/guide/google/gcm/client-javadoc/allclasses-noframe.html
index 6ae9fe0..dc34021 100644
--- a/docs/html/guide/google/gcm/client-javadoc/allclasses-noframe.html
+++ b/docs/html/guide/google/gcm/client-javadoc/allclasses-noframe.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
All Classes
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBaseIntentService.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBaseIntentService.html
index eed1aea..ff15218 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBaseIntentService.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBaseIntentService.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:36 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
GCMBaseIntentService
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBroadcastReceiver.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBroadcastReceiver.html
index 2a1c676..ae80bf7 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBroadcastReceiver.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBroadcastReceiver.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:36 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
GCMBroadcastReceiver
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMConstants.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMConstants.html
index f778f06..205bcf0 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMConstants.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMConstants.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:36 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
GCMConstants
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
@@ -177,8 +177,8 @@
<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_APPLICATION_PENDING_INTENT">EXTRA_APPLICATION_PENDING_INTENT</A></B></CODE>
<BR>
- Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION"><CODE>INTENT_TO_GCM_REGISTRATION</CODE></A> to get the application
- id.</TD>
+ Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION">"com.google.android.c2dm.intent.REGISTER"</A> to get the
+ application info.</TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
@@ -186,16 +186,25 @@
<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_ERROR">EXTRA_ERROR</A></B></CODE>
<BR>
- Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+ Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
an error when the registration fails.</TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
<CODE>static java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_FROM">EXTRA_FROM</A></B></CODE>
+
+<BR>
+ Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A> to indicate which
+ sender (Google API project id) sent the message.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static java.lang.String</CODE></FONT></TD>
<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_REGISTRATION_ID">EXTRA_REGISTRATION_ID</A></B></CODE>
<BR>
- Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+ Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
the registration id when the registration succeeds.</TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
@@ -204,8 +213,8 @@
<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_SENDER">EXTRA_SENDER</A></B></CODE>
<BR>
- Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION"><CODE>INTENT_TO_GCM_REGISTRATION</CODE></A> to indicate the sender
- account (a Google email) that owns the application.</TD>
+ Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION">"com.google.android.c2dm.intent.REGISTER"</A> to indicate which
+ senders (Google API project ids) can send messages to the application.</TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
@@ -213,7 +222,7 @@
<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_SPECIAL_MESSAGE">EXTRA_SPECIAL_MESSAGE</A></B></CODE>
<BR>
- Type of message present in the <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE"><CODE>INTENT_FROM_GCM_MESSAGE</CODE></A> intent.</TD>
+ Type of message present in the <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A> intent.</TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
@@ -229,7 +238,7 @@
<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_UNREGISTERED">EXTRA_UNREGISTERED</A></B></CODE>
<BR>
- Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+ Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
that the application has been unregistered.</TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
@@ -388,8 +397,8 @@
<PRE>
public static final java.lang.String <B>EXTRA_SENDER</B></PRE>
<DL>
-<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION"><CODE>INTENT_TO_GCM_REGISTRATION</CODE></A> to indicate the sender
- account (a Google email) that owns the application.
+<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION">"com.google.android.c2dm.intent.REGISTER"</A> to indicate which
+ senders (Google API project ids) can send messages to the application.
<P>
<DL>
<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.google.android.gcm.GCMConstants.EXTRA_SENDER">Constant Field Values</A></DL>
@@ -401,8 +410,8 @@
<PRE>
public static final java.lang.String <B>EXTRA_APPLICATION_PENDING_INTENT</B></PRE>
<DL>
-<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION"><CODE>INTENT_TO_GCM_REGISTRATION</CODE></A> to get the application
- id.
+<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION">"com.google.android.c2dm.intent.REGISTER"</A> to get the
+ application info.
<P>
<DL>
<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.google.android.gcm.GCMConstants.EXTRA_APPLICATION_PENDING_INTENT">Constant Field Values</A></DL>
@@ -414,7 +423,7 @@
<PRE>
public static final java.lang.String <B>EXTRA_UNREGISTERED</B></PRE>
<DL>
-<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
that the application has been unregistered.
<P>
<DL>
@@ -427,7 +436,7 @@
<PRE>
public static final java.lang.String <B>EXTRA_ERROR</B></PRE>
<DL>
-<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
an error when the registration fails. See constants starting with ERROR_
for possible values.
<P>
@@ -441,7 +450,7 @@
<PRE>
public static final java.lang.String <B>EXTRA_REGISTRATION_ID</B></PRE>
<DL>
-<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
the registration id when the registration succeeds.
<P>
<DL>
@@ -454,7 +463,7 @@
<PRE>
public static final java.lang.String <B>EXTRA_SPECIAL_MESSAGE</B></PRE>
<DL>
-<DD>Type of message present in the <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE"><CODE>INTENT_FROM_GCM_MESSAGE</CODE></A> intent.
+<DD>Type of message present in the <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A> intent.
This extra is only set for special messages sent from GCM, not for
messages originated from the application.
<P>
@@ -482,13 +491,26 @@
<DL>
<DD>Number of messages deleted by the server because the device was idle.
Present only on messages of special type
- <A HREF="../../../../com/google/android/gcm/GCMConstants.html#VALUE_DELETED_MESSAGES"><CODE>VALUE_DELETED_MESSAGES</CODE></A>
+ <A HREF="../../../../com/google/android/gcm/GCMConstants.html#VALUE_DELETED_MESSAGES">"deleted_messages"</A>
<P>
<DL>
<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.google.android.gcm.GCMConstants.EXTRA_TOTAL_DELETED">Constant Field Values</A></DL>
</DL>
<HR>
+<A NAME="EXTRA_FROM"><!-- --></A><H3>
+EXTRA_FROM</H3>
+<PRE>
+public static final java.lang.String <B>EXTRA_FROM</B></PRE>
+<DL>
+<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A> to indicate which
+ sender (Google API project id) sent the message.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.google.android.gcm.GCMConstants.EXTRA_FROM">Constant Field Values</A></DL>
+</DL>
+<HR>
+
<A NAME="PERMISSION_GCM_INTENTS"><!-- --></A><H3>
PERMISSION_GCM_INTENTS</H3>
<PRE>
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMRegistrar.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMRegistrar.html
index bb486ff..c29bf90 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMRegistrar.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMRegistrar.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:36 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
GCMRegistrar
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
@@ -308,11 +308,12 @@
<li>It defines at least one <CODE>BroadcastReceiver</CODE> with category
<code>PACKAGE_NAME</code>.
<li>The <CODE>BroadcastReceiver</CODE>(s) uses the
- permission.
- <li>The <CODE>BroadcastReceiver</CODE>(s) handles the 3 GCM intents
- (,
- ,
- and ).
+ <A HREF="../../../../com/google/android/gcm/GCMConstants.html#PERMISSION_GCM_INTENTS">"com.google.android.c2dm.permission.SEND"</A>
+ permission.
+ <li>The <CODE>BroadcastReceiver</CODE>(s) handles the 2 GCM intents
+ (<A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A>
+ and
+ <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A>).
</ol>
...where <code>PACKAGE_NAME</code> is the application package.
<p>
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-frame.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-frame.html
index 4828eea..a2a599d 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-frame.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-frame.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
com.google.android.gcm
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-summary.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-summary.html
index 877248b..c8e0341 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-summary.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-summary.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
com.google.android.gcm
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-tree.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-tree.html
index bf6fce3..0e27efe 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-tree.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-tree.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
com.google.android.gcm Class Hierarchy
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/constant-values.html b/docs/html/guide/google/gcm/client-javadoc/constant-values.html
index 6ccd123..796d196 100644
--- a/docs/html/guide/google/gcm/client-javadoc/constant-values.html
+++ b/docs/html/guide/google/gcm/client-javadoc/constant-values.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
Constant Field Values
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style">
@@ -173,6 +173,12 @@
<TD ALIGN="right"><CODE>"error"</CODE></TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.google.android.gcm.GCMConstants.EXTRA_FROM"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public static final java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/google/android/gcm/GCMConstants.html#EXTRA_FROM">EXTRA_FROM</A></CODE></TD>
+<TD ALIGN="right"><CODE>"from"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
<A NAME="com.google.android.gcm.GCMConstants.EXTRA_REGISTRATION_ID"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
<CODE>public static final java.lang.String</CODE></FONT></TD>
<TD ALIGN="left"><CODE><A HREF="com/google/android/gcm/GCMConstants.html#EXTRA_REGISTRATION_ID">EXTRA_REGISTRATION_ID</A></CODE></TD>
diff --git a/docs/html/guide/google/gcm/client-javadoc/default.css b/docs/html/guide/google/gcm/client-javadoc/default.css
index 2513e69..f11daf7 100644
--- a/docs/html/guide/google/gcm/client-javadoc/default.css
+++ b/docs/html/guide/google/gcm/client-javadoc/default.css
@@ -530,12 +530,12 @@
}
.design ol {
counter-reset: item; }
- .design ol li {
+ .design ol>li {
font-size: 14px;
line-height: 20px;
list-style-type: none;
position: relative; }
- .design ol li:before {
+ .design ol>li:before {
content: counter(item) ". ";
counter-increment: item;
position: absolute;
@@ -561,16 +561,18 @@
content: "9. "; }
.design ol li.value-10:before {
content: "10. "; }
-.design .with-callouts ol li {
+.design .with-callouts ol>li {
list-style-position: inside;
margin-left: 0; }
- .design .with-callouts ol li:before {
+ .design .with-callouts ol>li:before {
display: inline;
left: -20px;
float: left;
width: 17px;
color: #33b5e5;
font-weight: 500; }
+.design .with-callouts ul>li {
+ list-style-position: outside; }
/* special list items */
li.no-bullet {
@@ -1079,22 +1081,71 @@
Print Only
========================================================================== */
@media print {
-a {
- color: inherit;
-}
-.nav-x, .nav-y {
- display: none;
-}
-.str { color: #060; }
-.kwd { color: #006; font-weight: bold; }
-.com { color: #600; font-style: italic; }
-.typ { color: #404; font-weight: bold; }
-.lit { color: #044; }
-.pun { color: #440; }
-.pln { color: #000; }
-.tag { color: #006; font-weight: bold; }
-.atn { color: #404; }
-.atv { color: #060; }
+ /* configure printed page */
+ @page {
+ margin: 0.75in 1in;
+ widows: 4;
+ orphans: 4;
+ }
+
+ /* reset spacing metrics */
+ html, body, .wrap {
+ margin: 0 !important;
+ padding: 0 !important;
+ width: auto !important;
+ }
+
+ /* leave enough space on the left for bullets */
+ body {
+ padding-left: 20px !important;
+ }
+ #doc-col {
+ margin-left: 0;
+ }
+
+ /* hide a bunch of non-content elements */
+ #header, #footer, #nav-x, #side-nav,
+ .training-nav-top, .training-nav-bottom,
+ #doc-col .content-footer,
+ .nav-x, .nav-y,
+ .paging-links,
+ a.totop {
+ display: none !important;
+ }
+
+ /* remove extra space above page titles */
+ #doc-col .content-header {
+ margin-top: 0;
+ }
+
+ /* bump up spacing above subheadings */
+ h2 {
+ margin-top: 40px !important;
+ }
+
+ /* print link URLs where possible and give links default text color */
+ p a:after {
+ content: " (" attr(href) ")";
+ font-size: 80%;
+ }
+ p a {
+ word-wrap: break-word;
+ }
+ a {
+ color: inherit;
+ }
+
+ /* syntax highlighting rules */
+ .str { color: #060; }
+ .kwd { color: #006; font-weight: bold; }
+ .com { color: #600; font-style: italic; }
+ .typ { color: #404; font-weight: bold; }
+ .lit { color: #044; }
+ .pun { color: #440; }
+ .pln { color: #000; }
+ .tag { color: #006; font-weight: bold; }
+ .atn { color: #404; }
+ .atv { color: #060; }
}
/* =============================================================================
@@ -2033,8 +2084,11 @@
#jd-content img.toggle-content-img {
margin:0 5px 5px 0;
}
-div.toggle-content > p {
- padding:0 0 5px;
+div.toggle-content p {
+ margin:10px 0 0;
+}
+div.toggle-content-toggleme {
+ padding:0 0 0 15px;
}
@@ -2145,14 +2199,9 @@
.nolist {
list-style:none;
- padding:0;
- margin:0 0 1em 1em;
+ margin-left:0;
}
-.nolist li {
- padding:0 0 2px;
- margin:0;
-}
pre.classic {
background-color:transparent;
@@ -2180,6 +2229,12 @@
color:#666;
}
+div.note,
+div.caution,
+div.warning {
+ margin: 0 0 15px;
+}
+
p.note, div.note,
p.caution, div.caution,
p.warning, div.warning {
@@ -2898,10 +2953,6 @@
/* SEARCH RESULTS */
-/* disable twiddle and size selectors for left column */
-#leftSearchControl div {
- padding:0;
-}
#leftSearchControl .gsc-twiddle {
background-image : none;
@@ -3475,7 +3526,7 @@
.morehover:hover {
opacity:1;
- height:345px;
+ height:385px;
width:268px;
-webkit-transition-property:height, -webkit-opacity;
}
@@ -3489,7 +3540,7 @@
.morehover .mid {
width:228px;
background:url(../images/more_mid.png) repeat-y;
- padding:10px 20px 10px 20px;
+ padding:10px 20px 0 20px;
}
.morehover .mid .header {
@@ -3598,15 +3649,19 @@
padding-top: 14px;
}
+#nav-x .wrap {
+ min-height:34px;
+}
+
#nav-x .wrap,
#searchResults.wrap {
max-width:940px;
border-bottom:1px solid #CCC;
- min-height:34px;
-
}
-
+#searchResults.wrap #leftSearchControl {
+ min-height:700px
+}
.nav-x {
margin-left:0;
margin-bottom:0;
@@ -3762,7 +3817,8 @@
height: 300px;
}
.slideshow-develop img.play {
- width:350px;
+ max-width:350px;
+ max-height:240px;
margin:20px 0 0 90px;
-webkit-transform: perspective(800px ) rotateY( 35deg );
box-shadow: -16px 20px 40px rgba(0, 0, 0, 0.3);
@@ -3817,6 +3873,7 @@
.feed .feed-nav li {
list-style: none;
float: left;
+ height: 21px; /* +4px bottom border = 25px; same as .feed-nav */
margin-right: 25px;
cursor: pointer;
}
@@ -3969,21 +4026,24 @@
.landing-docs {
margin:20px 0 0;
}
-.landing-banner {
- height:280px;
-}
.landing-banner .col-6:first-child,
-.landing-docs .col-6:first-child {
+.landing-docs .col-6:first-child,
+.landing-docs .col-12 {
margin-left:0;
+ min-height:280px;
}
.landing-banner .col-6:last-child,
-.landing-docs .col-6:last-child {
+.landing-docs .col-6:last-child,
+.landing-docs .col-12 {
margin-right:0;
}
.landing-banner h1 {
margin-top:0;
}
+.landing-docs {
+ clear:left;
+}
.landing-docs h3 {
font-size:14px;
line-height:21px;
@@ -4002,4 +4062,99 @@
.plusone {
float:right;
-}
\ No newline at end of file
+}
+
+
+
+/************* HOME/LANDING PAGE *****************/
+
+.slideshow-home {
+ height: 500px;
+ width: 940px;
+ border-bottom: 1px solid #CCC;
+ position: relative;
+ margin: 0;
+}
+.slideshow-home .frame {
+ width: 940px;
+ height: 500px;
+}
+.slideshow-home .content-left {
+ float: left;
+ text-align: center;
+ vertical-align: center;
+ margin: 0 0 0 35px;
+}
+.slideshow-home .content-right {
+ margin: 80px 0 0 0;
+}
+.slideshow-home .content-right p {
+ margin-bottom: 10px;
+}
+.slideshow-home .content-right p:last-child {
+ margin-top: 15px;
+}
+.slideshow-home .content-right h1 {
+ padding:0;
+}
+.slideshow-home .item {
+ height: 500px;
+ width: 940px;
+}
+.home-sections {
+ padding: 30px 20px 20px;
+ margin: 20px 0;
+ background: -webkit-linear-gradient(top, #F6F6F6,#F9F9F9);
+}
+.home-sections ul {
+ margin: 0;
+}
+.home-sections ul li {
+ float: left;
+ display: block;
+ list-style: none;
+ width: 170px;
+ height: 35px;
+ border: 1px solid #ccc;
+ background: white;
+ margin-right: 10px;
+ border-radius: 1px;
+ -webkit-border-radius: 1px;
+ -moz-border-radius: 1px;
+ box-shadow: 1px 1px 5px #EEE;
+ -webkit-box-shadow: 1px 1px 5px #EEE;
+ -moz-box-shadow: 1px 1px 5px #EEE;
+ background: white;
+}
+.home-sections ul li:hover {
+ background: #F9F9F9;
+ border: 1px solid #CCC;
+}
+.home-sections ul li a,
+.home-sections ul li a:hover {
+ font-weight: bold;
+ margin-top: 8px;
+ line-height: 18px;
+ float: left;
+ width: 100%;
+ text-align: center;
+ color: #09c !important;
+}
+.home-sections ul li a {
+ font-weight: bold;
+ margin-top: 8px;
+ line-height: 18px;
+ float: left;
+ width:100%;
+ text-align:center;
+}
+.home-sections ul li img {
+ float: left;
+ margin: -8px 0 0 10px;
+}
+.home-sections ul li.last {
+ margin-right: 0px;
+}
+#footer {
+ margin-top: -40px;
+}
diff --git a/docs/html/guide/google/gcm/client-javadoc/deprecated-list.html b/docs/html/guide/google/gcm/client-javadoc/deprecated-list.html
index 6b86bfe..d9a63c5 100644
--- a/docs/html/guide/google/gcm/client-javadoc/deprecated-list.html
+++ b/docs/html/guide/google/gcm/client-javadoc/deprecated-list.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
Deprecated List
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/help-doc.html b/docs/html/guide/google/gcm/client-javadoc/help-doc.html
index ffd1f77..af1bca8 100644
--- a/docs/html/guide/google/gcm/client-javadoc/help-doc.html
+++ b/docs/html/guide/google/gcm/client-javadoc/help-doc.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
API Help
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/index-all.html b/docs/html/guide/google/gcm/client-javadoc/index-all.html
index 74e6095..408edee 100644
--- a/docs/html/guide/google/gcm/client-javadoc/index-all.html
+++ b/docs/html/guide/google/gcm/client-javadoc/index-all.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
Index
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="./default.css" TITLE="Style">
@@ -124,29 +124,33 @@
server that can be retried later.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_APPLICATION_PENDING_INTENT"><B>EXTRA_APPLICATION_PENDING_INTENT</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
-<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION"><CODE>GCMConstants.INTENT_TO_GCM_REGISTRATION</CODE></A> to get the application
- id.
+<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION">"com.google.android.c2dm.intent.REGISTER"</A> to get the
+ application info.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_ERROR"><B>EXTRA_ERROR</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
-<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>GCMConstants.INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
an error when the registration fails.
+<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_FROM"><B>EXTRA_FROM</B></A> -
+Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
+<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A> to indicate which
+ sender (Google API project id) sent the message.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_REGISTRATION_ID"><B>EXTRA_REGISTRATION_ID</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
-<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>GCMConstants.INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
the registration id when the registration succeeds.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_SENDER"><B>EXTRA_SENDER</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
-<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION"><CODE>GCMConstants.INTENT_TO_GCM_REGISTRATION</CODE></A> to indicate the sender
- account (a Google email) that owns the application.
+<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION">"com.google.android.c2dm.intent.REGISTER"</A> to indicate which
+ senders (Google API project ids) can send messages to the application.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_SPECIAL_MESSAGE"><B>EXTRA_SPECIAL_MESSAGE</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
-<DD>Type of message present in the <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE"><CODE>GCMConstants.INTENT_FROM_GCM_MESSAGE</CODE></A> intent.
+<DD>Type of message present in the <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A> intent.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_TOTAL_DELETED"><B>EXTRA_TOTAL_DELETED</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
<DD>Number of messages deleted by the server because the device was idle.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_UNREGISTERED"><B>EXTRA_UNREGISTERED</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
-<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>GCMConstants.INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
that the application has been unregistered.
</DL>
<HR>
diff --git a/docs/html/guide/google/gcm/client-javadoc/index.html b/docs/html/guide/google/gcm/client-javadoc/index.html
index 26e57f6..fa7af90 100644
--- a/docs/html/guide/google/gcm/client-javadoc/index.html
+++ b/docs/html/guide/google/gcm/client-javadoc/index.html
@@ -2,7 +2,7 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc on Mon Jul 16 14:13:37 PDT 2012-->
+<!-- Generated by javadoc on Wed Aug 22 13:22:47 PDT 2012-->
<TITLE>
Generated Documentation (Untitled)
</TITLE>
diff --git a/docs/html/guide/google/gcm/client-javadoc/overview-tree.html b/docs/html/guide/google/gcm/client-javadoc/overview-tree.html
index c9076f1..392f3e0 100644
--- a/docs/html/guide/google/gcm/client-javadoc/overview-tree.html
+++ b/docs/html/guide/google/gcm/client-javadoc/overview-tree.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
Class Hierarchy
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/gcm.jd b/docs/html/guide/google/gcm/gcm.jd
index 827edaa..72c3f23 100644
--- a/docs/html/guide/google/gcm/gcm.jd
+++ b/docs/html/guide/google/gcm/gcm.jd
@@ -203,7 +203,7 @@
<p>The registration ID lasts until the Android application explicitly unregisters
itself, or until Google refreshes the registration ID for your Android application.</p>
-<p class="note"><strong>Note:</strong> When users uninstall an application, it is not automatically unregistered on GCM. It is only unregistered when the GCM server tries to send a message to the device and the device answers that the application is uninstalled. At that point, you server should mark the device as unregistered (the server will receive a <code><a href="#unreg_device">NotRegistered</a></code> error).
+<p class="note"><strong>Note:</strong> When users uninstall an application, it is not automatically unregistered on GCM. It is only unregistered when the GCM server tries to send a message to the device and the device answers that the application is uninstalled or it does not have a broadcast receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> intents. At that point, you server should mark the device as unregistered (the server will receive a <code><a href="#unreg_device">NotRegistered</a></code> error).
<p>
Note that it might take a few minutes for the registration ID to be completed removed from the GCM server. So if the 3rd party server sends a message during this time, it will get a valid message ID, even though the message will not be delivered to the device.</p>
</p>
@@ -546,7 +546,7 @@
deliver the messages sent by the 3rd-party server to the application running in the device.
If the server included key-pair values in the <code>data</code> parameter, they are available as
extras in this intent, with the keys being the extra names. GCM also includes an extra called
-<code>from</code> which contains the sender ID as an string.
+<code>from</code> which contains the sender ID as an string, and another called <code>collapse_key</code> containing the collapse key (when in use).
<p>Here is an example, again using the <code>MyIntentReceiver</code> class:</p>
@@ -654,7 +654,8 @@
<td>A JSON object whose fields represents the key-value pairs of the message's payload data. If present, the payload data it 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). Note that the values <em>must be enclosed by strings</em>. 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 ("from" or any word starting with "google."). Optional.</td>
+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>). To complicate things slightly, there are some reserved words (such as <code>collapse_key</code>) that are technically allowed in payload data. However, if the request also contains the word, the value in the request will overwrite the value in the payload data. Hence using words that are defined as field names in this table is not recommended, even in cases where they are technically allowed. Optional.</td>
+
</tr>
<tr>
@@ -686,7 +687,10 @@
</tr>
<tr>
<td><code>data.<key></code></td>
- <td>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. Note that the key cannot be a reserved word ("from" or any word starting with "google."). Optional.</td>
+
+ <td>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>). To complicate things slightly, there are some reserved words (such as <code>collapse_key</code>) that are technically allowed in payload data. However, if the request also contains the word, the value in the request will overwrite the value in the payload data. Hence using words that are defined as field names in this table is not recommended, even in cases where they are technically allowed. Optional.</td>
+
</tr>
<tr>
<td><code>delay_while_idle</code></td>
@@ -817,7 +821,7 @@
<li>Otherwise, get the value of <code>error</code>:
<ul>
<li>If it is <code>Unavailable</code>, you could retry to send it in another 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.</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>
<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 an error response</a> for all possible error values.</li>
</ul>
</li>
@@ -851,6 +855,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 not truncating it or adding additional characters.
<br/>Happens when error code is <code>InvalidRegistration</code>.</dd>
+
<dt id="mismatched_sender"><strong>Mismatched Sender</strong></dt>
<dd>A registration ID is tied to a certain group of senders. When an application registers for GCM usage, it must specify which senders are allowed to send messages. Make sure you're using one of those when trying to send messages to the device. If you switch to a different sender, the existing registration IDs won't work.
Happens when error code is <code>MismatchSenderId</code>.</dd>
@@ -861,15 +866,21 @@
<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 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>
</ul>
For all these cases, you should remove this registration ID from the 3rd-party server and stop using it to send
messages.
<br/>Happens when error code is <code>NotRegistered</code>.</dd>
- <dt id="big_msg"><strong>Message Too Big</strong></dt>
+<dt id="big_msg"><strong>Message Too Big</strong></dt>
<dd>The total size of the payload data that is included in a message can't exceed 4096 bytes. Note that this includes both the size of the keys as well as the values.
<br/>Happens when error code is <code>MessageTooBig</code>.</dd>
+<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. 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.
+<br />
+Happens when the error code is <code>InvalidDataKey</code>.</dd>
+
<dt id="ttl_error"><strong>Invalid Time To Live</strong></dt>
<dd>The value for the Time to Live field must be an integer representing a duration in seconds between 0 and 2,419,200 (4 weeks). Happens when error code is <code>InvalidTtl</code>.
</dd>
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index e19217f..7b6e540 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -16,7 +16,9 @@
package android.security;
+import org.apache.harmony.xnet.provider.jsse.OpenSSLDSAPrivateKey;
import org.apache.harmony.xnet.provider.jsse.OpenSSLEngine;
+import org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey;
import android.util.Log;
@@ -193,17 +195,41 @@
private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain)
throws KeyStoreException {
- // Make sure the PrivateKey format is the one we support.
- final String keyFormat = key.getFormat();
- if ((keyFormat == null) || (!"PKCS#8".equals(keyFormat))) {
- throw new KeyStoreException(
- "Only PrivateKeys that can be encoded into PKCS#8 are supported");
+ byte[] keyBytes = null;
+
+ final String pkeyAlias;
+ if (key instanceof OpenSSLRSAPrivateKey) {
+ pkeyAlias = ((OpenSSLRSAPrivateKey) key).getPkeyAlias();
+ } else if (key instanceof OpenSSLDSAPrivateKey) {
+ pkeyAlias = ((OpenSSLDSAPrivateKey) key).getPkeyAlias();
+ } else {
+ pkeyAlias = null;
}
- // Make sure we can actually encode the key.
- final byte[] keyBytes = key.getEncoded();
- if (keyBytes == null) {
- throw new KeyStoreException("PrivateKey has no encoding");
+ final boolean shouldReplacePrivateKey;
+ if (pkeyAlias != null && pkeyAlias.startsWith(Credentials.USER_PRIVATE_KEY)) {
+ final String keySubalias = pkeyAlias.substring(Credentials.USER_PRIVATE_KEY.length());
+ if (!alias.equals(keySubalias)) {
+ throw new KeyStoreException("Can only replace keys with same alias: " + alias
+ + " != " + keySubalias);
+ }
+
+ shouldReplacePrivateKey = false;
+ } else {
+ // Make sure the PrivateKey format is the one we support.
+ final String keyFormat = key.getFormat();
+ if ((keyFormat == null) || (!"PKCS#8".equals(keyFormat))) {
+ throw new KeyStoreException(
+ "Only PrivateKeys that can be encoded into PKCS#8 are supported");
+ }
+
+ // Make sure we can actually encode the key.
+ keyBytes = key.getEncoded();
+ if (keyBytes == null) {
+ throw new KeyStoreException("PrivateKey has no encoding");
+ }
+
+ shouldReplacePrivateKey = true;
}
// Make sure the chain exists since this is a PrivateKey
@@ -273,17 +299,25 @@
}
/*
- * Make sure we clear out all the types we know about before trying to
+ * Make sure we clear out all the appropriate types before trying to
* write.
*/
- Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+ if (shouldReplacePrivateKey) {
+ Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+ } else {
+ Credentials.deleteCertificateTypesForAlias(mKeyStore, alias);
+ }
- if (!mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, keyBytes)) {
+ if (shouldReplacePrivateKey
+ && !mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, keyBytes)) {
+ Credentials.deleteAllTypesForAlias(mKeyStore, alias);
throw new KeyStoreException("Couldn't put private key in keystore");
} else if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertBytes)) {
+ Credentials.deleteAllTypesForAlias(mKeyStore, alias);
throw new KeyStoreException("Couldn't put certificate #1 in keystore");
} else if (chainBytes != null
&& !mKeyStore.put(Credentials.CA_CERTIFICATE + alias, chainBytes)) {
+ Credentials.deleteAllTypesForAlias(mKeyStore, alias);
throw new KeyStoreException("Couldn't put certificate chain in keystore");
}
}
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 72332eb..f6bf432 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -197,7 +197,20 @@
* don't use a conditional here.
*/
return keystore.delKey(Credentials.USER_PRIVATE_KEY + alias)
- | keystore.delete(Credentials.USER_CERTIFICATE + alias)
+ | deleteCertificateTypesForAlias(keystore, alias);
+ }
+
+ /**
+ * Delete all types (private key, certificate, CA certificate) for a
+ * particular {@code alias}. All three can exist for any given alias.
+ * Returns {@code true} if there was at least one of those types.
+ */
+ static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias) {
+ /*
+ * Make sure every certificate type is deleted. There can be two types,
+ * so don't use a conditional here.
+ */
+ return keystore.delete(Credentials.USER_CERTIFICATE + alias)
| keystore.delete(Credentials.CA_CERTIFICATE + alias);
}
}
diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk
index 95604c6..61cf640 100644
--- a/keystore/tests/Android.mk
+++ b/keystore/tests/Android.mk
@@ -5,7 +5,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/keystore/tests/src/android/security/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
index bff01b8..49e2f12 100644
--- a/keystore/tests/src/android/security/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
@@ -16,12 +16,17 @@
package android.security;
+import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
+
+import org.apache.harmony.xnet.provider.jsse.OpenSSLEngine;
+
import android.test.AndroidTestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.IOException;
import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyStore.Entry;
@@ -30,12 +35,14 @@
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
+import java.security.PublicKey;
import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
@@ -44,6 +51,8 @@
import java.util.Iterator;
import java.util.Set;
+import javax.security.auth.x500.X500Principal;
+
public class AndroidKeyStoreTest extends AndroidTestCase {
private android.security.KeyStore mAndroidKeyStore;
@@ -55,6 +64,22 @@
private static final String TEST_ALIAS_3 = "test3";
+ private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
+
+ private static final X500Principal TEST_DN_2 = new X500Principal("CN=test2");
+
+ private static final BigInteger TEST_SERIAL_1 = BigInteger.ONE;
+
+ private static final BigInteger TEST_SERIAL_2 = BigInteger.valueOf(2L);
+
+ private static final long NOW_MILLIS = System.currentTimeMillis();
+
+ /* We have to round this off because X509v3 doesn't store milliseconds. */
+ private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L));
+
+ @SuppressWarnings("deprecation")
+ private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1);
+
/*
* The keys and certificates below are generated with:
*
@@ -759,17 +784,31 @@
assertPrivateKeyEntryEquals(keyEntry, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
}
+ @SuppressWarnings("unchecked")
private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, byte[] key, byte[] cert,
byte[] ca) throws Exception {
KeyFactory keyFact = KeyFactory.getInstance("RSA");
PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(key));
- assertEquals("Returned PrivateKey should be what we inserted", expectedKey,
- keyEntry.getPrivateKey());
-
CertificateFactory certFact = CertificateFactory.getInstance("X.509");
Certificate expectedCert = certFact.generateCertificate(new ByteArrayInputStream(cert));
+ final Collection<Certificate> expectedChain;
+ if (ca != null) {
+ expectedChain = (Collection<Certificate>) certFact
+ .generateCertificates(new ByteArrayInputStream(ca));
+ } else {
+ expectedChain = null;
+ }
+
+ assertPrivateKeyEntryEquals(keyEntry, expectedKey, expectedCert, expectedChain);
+ }
+
+ private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, PrivateKey expectedKey,
+ Certificate expectedCert, Collection<Certificate> expectedChain) throws Exception {
+ assertEquals("Returned PrivateKey should be what we inserted", expectedKey,
+ keyEntry.getPrivateKey());
+
assertEquals("Returned Certificate should be what we inserted", expectedCert,
keyEntry.getCertificate());
@@ -777,13 +816,9 @@
assertEquals("First certificate in chain should be user cert", expectedCert, actualChain[0]);
- if (ca == null) {
+ if (expectedChain == null) {
assertEquals("Certificate chain should not include CAs", 1, actualChain.length);
} else {
- @SuppressWarnings("unchecked")
- Collection<Certificate> expectedChain = (Collection<Certificate>) certFact
- .generateCertificates(new ByteArrayInputStream(ca));
-
int i = 1;
final Iterator<Certificate> it = expectedChain.iterator();
while (it.hasNext()) {
@@ -1306,6 +1341,142 @@
}
}
+ @SuppressWarnings("deprecation")
+ private static X509Certificate generateCertificate(android.security.KeyStore keyStore,
+ String alias, BigInteger serialNumber, X500Principal subjectDN, Date notBefore,
+ Date notAfter) throws Exception {
+ final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
+
+ final PrivateKey privKey;
+ final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
+ try {
+ privKey = engine.getPrivateKeyById(privateKeyAlias);
+ } catch (InvalidKeyException e) {
+ throw new RuntimeException("Can't get key", e);
+ }
+
+ final byte[] pubKeyBytes = keyStore.getPubkey(privateKeyAlias);
+
+ final PublicKey pubKey;
+ try {
+ final KeyFactory keyFact = KeyFactory.getInstance("RSA");
+ pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException("Can't instantiate RSA key generator", e);
+ } catch (InvalidKeySpecException e) {
+ throw new IllegalStateException("keystore returned invalid key encoding", e);
+ }
+
+ final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+ certGen.setPublicKey(pubKey);
+ certGen.setSerialNumber(serialNumber);
+ certGen.setSubjectDN(subjectDN);
+ certGen.setIssuerDN(subjectDN);
+ certGen.setNotBefore(notBefore);
+ certGen.setNotAfter(notAfter);
+ certGen.setSignatureAlgorithm("sha1WithRSA");
+
+ final X509Certificate cert = certGen.generate(privKey);
+
+ return cert;
+ }
+
+ public void testKeyStore_SetKeyEntry_ReplacedChain_Success() throws Exception {
+ mKeyStore.load(null, null);
+
+ // Create key #1
+ {
+ final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
+ assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
+
+ Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
+
+ assertTrue(key instanceof PrivateKey);
+
+ PrivateKey expectedKey = (PrivateKey) key;
+
+ X509Certificate expectedCert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1,
+ TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
+
+ assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
+ expectedCert.getEncoded()));
+
+ Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+
+ assertTrue(entry instanceof PrivateKeyEntry);
+
+ PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
+
+ assertPrivateKeyEntryEquals(keyEntry, expectedKey, expectedCert, null);
+ }
+
+ // Replace key #1 with new chain
+ {
+ Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
+
+ assertTrue(key instanceof PrivateKey);
+
+ PrivateKey expectedKey = (PrivateKey) key;
+
+ X509Certificate expectedCert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1,
+ TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS);
+
+ mKeyStore.setKeyEntry(TEST_ALIAS_1, expectedKey, null,
+ new Certificate[] { expectedCert });
+
+ Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+
+ assertTrue(entry instanceof PrivateKeyEntry);
+
+ PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
+
+ assertPrivateKeyEntryEquals(keyEntry, expectedKey, expectedCert, null);
+ }
+ }
+
+ public void testKeyStore_SetKeyEntry_ReplacedChain_DifferentPrivateKey_Failure()
+ throws Exception {
+ mKeyStore.load(null, null);
+
+ // Create key #1
+ {
+ final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
+ assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
+
+ X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1,
+ TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
+
+ assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
+ cert.getEncoded()));
+ }
+
+ // Create key #2
+ {
+ final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_2;
+ assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
+
+ X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_2,
+ TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS);
+
+ assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_2,
+ cert.getEncoded()));
+ }
+
+ // Replace key #1 with key #2
+ {
+ Key key1 = mKeyStore.getKey(TEST_ALIAS_2, null);
+
+ X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_2,
+ TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS);
+
+ try {
+ mKeyStore.setKeyEntry(TEST_ALIAS_1, key1, null, new Certificate[] { cert });
+ fail("Should not allow setting of KeyEntry with wrong PrivaetKey");
+ } catch (KeyStoreException success) {
+ }
+ }
+ }
+
public void testKeyStore_Size_Success() throws Exception {
mKeyStore.load(null, null);
diff --git a/media/java/android/media/DataSource.java b/media/java/android/media/DataSource.java
new file mode 100644
index 0000000..347bd5f
--- /dev/null
+++ b/media/java/android/media/DataSource.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.media;
+
+import java.io.Closeable;
+
+/**
+ * An abstraction for a media data source, e.g. a file or an http stream
+ * {@hide}
+ */
+public interface DataSource extends Closeable {
+ /**
+ * Reads data from the data source at the requested position
+ *
+ * @param offset where in the source to read
+ * @param buffer the buffer to read the data into
+ * @param size how many bytes to read
+ * @return the number of bytes read, or -1 if there was an error
+ */
+ public int readAt(long offset, byte[] buffer, int size);
+
+ /**
+ * Gets the size of the data source.
+ *
+ * @return size of data source, or -1 if the length is unknown
+ */
+ public long getSize();
+}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 687d3a5..4b8d3cb 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -22,6 +22,7 @@
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.net.Uri;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -60,6 +61,12 @@
}
/**
+ * Sets the DataSource object to be used as the data source for this extractor
+ * {@hide}
+ */
+ public native final void setDataSource(DataSource source);
+
+ /**
* Sets the data source as a content Uri.
*
* @param context the Context to use when resolving the Uri
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 351ff04..23949fa 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -44,6 +44,72 @@
static fields_t gFields;
+class JavaDataSourceBridge : public DataSource {
+ jmethodID mReadMethod;
+ jmethodID mGetSizeMethod;
+ jmethodID mCloseMethod;
+ jobject mDataSource;
+ public:
+ JavaDataSourceBridge(JNIEnv *env, jobject source) {
+ mDataSource = env->NewGlobalRef(source);
+
+ jclass datasourceclass = env->GetObjectClass(mDataSource);
+ CHECK(datasourceclass != NULL);
+
+ mReadMethod = env->GetMethodID(datasourceclass, "readAt", "(J[BI)I");
+ CHECK(mReadMethod != NULL);
+
+ mGetSizeMethod = env->GetMethodID(datasourceclass, "getSize", "()J");
+ CHECK(mGetSizeMethod != NULL);
+
+ mCloseMethod = env->GetMethodID(datasourceclass, "close", "()V");
+ CHECK(mCloseMethod != NULL);
+ }
+
+ ~JavaDataSourceBridge() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mDataSource, mCloseMethod);
+ env->DeleteGlobalRef(mDataSource);
+ }
+
+ virtual status_t initCheck() const {
+ return OK;
+ }
+
+ virtual ssize_t readAt(off64_t offset, void* buffer, size_t size) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ // XXX could optimize this by reusing the same array
+ jbyteArray byteArrayObj = env->NewByteArray(size);
+ env->DeleteLocalRef(env->GetObjectClass(mDataSource));
+ env->DeleteLocalRef(env->GetObjectClass(byteArrayObj));
+ ssize_t numread = env->CallIntMethod(mDataSource, mReadMethod, offset, byteArrayObj, size);
+ env->GetByteArrayRegion(byteArrayObj, 0, size, (jbyte*) buffer);
+ env->DeleteLocalRef(byteArrayObj);
+ if (env->ExceptionCheck()) {
+ ALOGW("Exception occurred while reading %d at %lld", size, offset);
+ LOGW_EX(env);
+ env->ExceptionClear();
+ return -1;
+ }
+ return numread;
+ }
+
+ virtual status_t getSize(off64_t *size) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ CHECK(size != NULL);
+
+ int64_t len = env->CallLongMethod(mDataSource, mGetSizeMethod);
+ if (len < 0) {
+ *size = ERROR_UNSUPPORTED;
+ } else {
+ *size = len;
+ }
+ return OK;
+ }
+};
+
////////////////////////////////////////////////////////////////////////////////
JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz)
@@ -76,6 +142,10 @@
return mImpl->setDataSource(fd, offset, size);
}
+status_t JMediaExtractor::setDataSource(const sp<DataSource> &datasource) {
+ return mImpl->setDataSource(datasource);
+}
+
size_t JMediaExtractor::countTracks() const {
return mImpl->countTracks();
}
@@ -625,6 +695,33 @@
}
}
+static void android_media_MediaExtractor_setDataSourceCallback(
+ JNIEnv *env, jobject thiz,
+ jobject callbackObj) {
+ sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+ if (extractor == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ if (callbackObj == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ sp<JavaDataSourceBridge> bridge = new JavaDataSourceBridge(env, callbackObj);
+ status_t err = extractor->setDataSource(bridge);
+
+ if (err != OK) {
+ jniThrowException(
+ env,
+ "java/io/IOException",
+ "Failed to instantiate extractor.");
+ return;
+ }
+}
+
static jlong android_media_MediaExtractor_getCachedDurationUs(
JNIEnv *env, jobject thiz) {
sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
@@ -713,6 +810,9 @@
{ "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
(void *)android_media_MediaExtractor_setDataSourceFd },
+ { "setDataSource", "(Landroid/media/DataSource;)V",
+ (void *)android_media_MediaExtractor_setDataSourceCallback },
+
{ "getCachedDuration", "()J",
(void *)android_media_MediaExtractor_getCachedDurationUs },
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index 2d4627e..03900db 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -19,6 +19,7 @@
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/DataSource.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@@ -39,6 +40,7 @@
const KeyedVector<String8, String8> *headers);
status_t setDataSource(int fd, off64_t offset, off64_t size);
+ status_t setDataSource(const sp<DataSource> &source);
size_t countTracks() const;
status_t getTrackFormat(size_t index, jobject *format) const;
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index a9de51f..9a80090 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -157,6 +157,8 @@
<bool name="def_screensaver_enabled">true</bool>
<!-- Whether the feature activates when docked (SCREENSAVER_ACTIVATE_ON_DOCK) -->
<bool name="def_screensaver_activate_on_dock">true</bool>
+ <!-- Whether the feature activates when docked (SCREENSAVER_ACTIVATE_ON_SLEEP) -->
+ <bool name="def_screensaver_activate_on_sleep">true</bool>
<!-- ComponentName of the default screen saver (Settings.Secure.SCREENSAVER_COMPONENT) -->
<string name="def_screensaver_component">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 1481eb2..db81786 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1131,7 +1131,11 @@
R.bool.def_screensaver_enabled);
loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
R.bool.def_screensaver_activate_on_dock);
- loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENT,
+ loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+ R.bool.def_screensaver_activate_on_sleep);
+ loadStringSetting(stmt, Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
+ R.string.def_screensaver_component);
+ loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENTS,
R.string.def_screensaver_component);
db.setTransactionSuccessful();
} finally {
@@ -1746,7 +1750,11 @@
R.bool.def_screensaver_enabled);
loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
R.bool.def_screensaver_activate_on_dock);
- loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENT,
+ loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+ R.bool.def_screensaver_activate_on_sleep);
+ loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENTS,
+ R.string.def_screensaver_component);
+ loadStringSetting(stmt, Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
R.string.def_screensaver_component);
} finally {
if (stmt != null) stmt.close();
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 2eee31d..c18f76c 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -53,6 +53,7 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application
+ android:name="com.android.systemui.SystemUIApplication"
android:persistent="true"
android:allowClearUserData="false"
android:allowBackup="false"
@@ -96,6 +97,16 @@
android:excludeFromRecents="true">
</activity>
+ <activity android:name=".recent.RecentsActivity"
+ android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar"
+ android:excludeFromRecents="true"
+ android:launchMode="singleInstance"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.systemui.TOGGLE_RECENTS" />
+ </intent-filter>
+ </activity>
+
<!-- started from UsbDeviceSettingsManager -->
<activity android:name=".usb.UsbConfirmActivity"
android:exported="true"
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
index 84e6bc8..6ae32f1 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
index 782d214..fdc56bb 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
index a00bc5b..ea7c4e3 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
index 8605701..49d5101 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
index 38bd0cd..33e56e8 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
index 0c12c16..2fb191d 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
index 477df5f..ce008f3 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
index bd60cd6..b971088 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
index 5272c91..d2d7842 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index 00e3e27..2df9f6c 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -26,11 +26,6 @@
android:layout_width="match_parent"
systemui:recentItemLayout="@layout/status_bar_recent_item"
>
- <View
- android:id="@+id/recents_transition_background"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:visibility="invisible" />
<FrameLayout
android:id="@+id/recents_bg_protect"
android:background="@drawable/status_bar_recents_background"
@@ -40,12 +35,6 @@
android:clipToPadding="false"
android:clipChildren="false">
- <ImageView
- android:id="@+id/recents_transition_placeholder_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="invisible" />
-
<com.android.systemui.recent.RecentsHorizontalScrollView android:id="@+id/recents_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_recent_panel.xml b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
index a7e5db1..7335f86 100644
--- a/packages/SystemUI/res/layout/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
@@ -26,11 +26,6 @@
android:layout_width="match_parent"
systemui:recentItemLayout="@layout/status_bar_recent_item"
>
- <View
- android:id="@+id/recents_transition_background"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:visibility="invisible" />
<FrameLayout
android:id="@+id/recents_bg_protect"
android:background="@drawable/status_bar_recents_background"
@@ -38,12 +33,6 @@
android:layout_height="match_parent"
android:layout_alignParentBottom="true">
- <ImageView
- android:id="@+id/recents_transition_placeholder_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="invisible" />
-
<com.android.systemui.recent.RecentsVerticalScrollView
android:id="@+id/recents_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/system_bar_recent_panel.xml b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
index 127551d..3951bba 100644
--- a/packages/SystemUI/res/layout/system_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
@@ -28,11 +28,6 @@
android:clipChildren="false"
systemui:recentItemLayout="@layout/system_bar_recent_item"
>
- <View
- android:id="@+id/recents_transition_background"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:visibility="invisible" />
<FrameLayout
android:id="@+id/recents_bg_protect"
android:background="@drawable/recents_bg_protect_tile"
@@ -42,11 +37,6 @@
android:layout_marginBottom="@*android:dimen/system_bar_height"
android:clipToPadding="false"
android:clipChildren="false">
- <ImageView
- android:id="@+id/recents_transition_placeholder_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="invisible" />
<com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index b63ed4a..d5e4c0a 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Sien"</string>
<string name="always_use_device" msgid="1450287437017315906">"Gebruik by verstek vir hierdie USB-toestel"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Gebruik by verstek vir hierdie USB-toebehoorsel"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Moet USB-ontfouting toegelaat word?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Moet USB-ontfouting van hierdie rekenaar af toegelaat word?"\n"Jou RSA-sleutelvingerafdruk is"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Laat altyd hierdie rekenaar toe"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoem om skerm te vul"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Strek om skerm te vul"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Versoenbaarheidszoem"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 0d41cc7..f34ed8e 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -56,11 +56,11 @@
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ምንም የተጫኑ መተግበሪያዎች ከዚህ የUSB ተቀጥላ ጋር አይሰሩም። በ<xliff:g id="URL">%1$s</xliff:g> ስለዚህ ተቀጥላ የበለጠ ለመረዳት።"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"የUSB ተቀጥላ"</string>
<string name="label_view" msgid="6304565553218192990">"ዕይታ"</string>
- <string name="always_use_device" msgid="1450287437017315906">"ለዚህ USB መሣሪያ በነባሪነት ተጠቀም"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"ለዚህ USB ተቀጥላ በነባሪነት ተጠቀም"</string>
+ <string name="always_use_device" msgid="1450287437017315906">"ለእዚህ USB መሣሪያ በነባሪነት ተጠቀም"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"ለእዚህ USB ተቀጥላ በነባሪነት ተጠቀም"</string>
<string name="usb_debugging_title" msgid="1114766024068112429">"የUSB ማረሚያ ይፈቀድ?"</string>
<string name="usb_debugging_message" msgid="719863946976291180">"የUSB ማረም ከዚህ ኮምፒውተር ይፈቀድ?"\n"የእርስዎ RSA ቁልፍ ጣት አሻራ "\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g> ነው"</string>
- <string name="usb_debugging_always" msgid="4253099426793114693">"ለዚህ ኮምፒውተር ሁልጊዜ ፍቀድ"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"ለእዚህ ኮምፒውተር ሁልጊዜ ፍቀድ"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"ማያ እንዲሞላ አጉላ"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"ማያ ለመሙለት ሳብ"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"የተኳኋኝነት አጉላ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index d3d4c7f..6540f0a 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"عرض"</string>
<string name="always_use_device" msgid="1450287437017315906">"الاستخدام بشكل افتراضي لجهاز USB هذا"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"الاستخدام بشكل افتراضي لملحق USB هذا"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"هل تريد السماح بتصحيح أخطاء USB؟"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"هل تريد السماح بتصحيح أخطاء USB من هذا الكمبيوتر؟"\n"ملفك المرجعي لمفتاح RSA هو"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"السماح لهذا الكمبيوتر دومًا"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"تكبير/تصغير لملء الشاشة"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"توسيع بملء الشاشة"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"تكبير/تصغير التوافق"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index ba57e91..56b8bb3 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Преглед"</string>
<string name="always_use_device" msgid="1450287437017315906">"Използване по подразб. за това USB устройство"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Използване по подразб. за този аксесоар за USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Да се разреши ли отстраняването на грешки през USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Да се разреши ли отстраняването на грешки през USB от този компютър?"\n"Отпечатъкът на вашия RSA ключ е"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Този компютър винаги да е разрешен"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Мащаб – запълва екрана"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Разпъване – запълва екрана"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Промяна на мащаба за съвместимост"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index fb6584e..a7bf519 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Zobrazit"</string>
<string name="always_use_device" msgid="1450287437017315906">"Pro toto zařízení USB použít jako výchozí"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Pro toto periferní zařízení USB použít jako výchozí"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Povolit ladění USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Povolit ladění USB z tohoto počítače?"\n"Váš digitální otisk klíče RSA je"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Vždy povolit tento počítač."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Přiblížit na celou obrazovku"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Na celou obrazovku"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Úprava velikosti z důvodu kompatibility"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 4c07d9f..e0aa3f9 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Ver"</string>
<string name="always_use_device" msgid="1450287437017315906">"Se usa de forma predeterminada para este dispositivo USB."</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Se usa de forma predeterminada para este accesorio USB."</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"¿Permitir la depuración de USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"¿Quieres permitir la depuración de USB desde esta computadora?"\n"La huella digital de tu clave RSA es"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>."</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Permitir el uso de esta computadora siempre"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom para ocupar la pantalla"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Estirar p/ ocupar la pantalla"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilidad"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 17484377..4348bda 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Kuva"</string>
<string name="always_use_device" msgid="1450287437017315906">"Kasuta vaikimisi selle USB-seadme jaoks"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Vaikimisi kasuta seda USB-lisaseadet"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Kas lubada USB-silumine?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Kas lubada USB-silumine sellest arvutist?"\n"Teie RSA-võtme sõrmejälg on"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Luba alati see arvuti"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Suumi ekraani täitmiseks"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Venita ekraani täitmiseks"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Sobivussuum"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index e75d5f0..66d65d9 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"مشاهده"</string>
<string name="always_use_device" msgid="1450287437017315906">"استفاده به صورت پیشفرض برای این دستگاه USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"استفاده به صورت پیشفرض برای این دستگاه USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"اشکالزدایی USB انجام شود؟"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"اشکالزدایی USB از این رایانه مجاز باشد؟"\n"اثر انگشت کلید RSA شما"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"این رایانه همیشه مجاز است"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"بزرگنمایی برای پر کردن صفحه"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"گسترده کردن برای پر کردن صفحه"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"بزرگنمایی سازگاری"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index d862df8..18f8c9d 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Afficher"</string>
<string name="always_use_device" msgid="1450287437017315906">"Utiliser par défaut pour ce périphérique USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Utiliser par défaut pour cet accessoire USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Autoriser le débogage USB ?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Autoriser le débogage USB via cet ordinateur ?"\n"Votre empreinte de clé RSA est "\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>."</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Toujours autoriser cet ordinateur"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoomer pour remplir l\'écran"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Étirer pour remplir l\'écran"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilité"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index b45b4ce..16e1443 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"देखें"</string>
<string name="always_use_device" msgid="1450287437017315906">"इस USB उपकरण के लिए डिफ़ॉल्ट रूप से उपयोग करें"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"इस USB एसेसरी के लिए डिफ़ॉल्ट रूप से उपयोग करें"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"USB डीबग करने दें?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"इस कंप्यूटर से USB डीबग करने दें?"\n"आपका RSA कुंजी फ़िंगरप्रिंट यह है:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"इस कंप्यूटर को हमेशा अनुमति दें"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"स्क्रीन भरने हेतु ज़ूम करें"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"स्क्रीन को भरने के लिए खींचें"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"संगतता ज़ूम"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 620e193..830b73c 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Prikaži"</string>
<string name="always_use_device" msgid="1450287437017315906">"Koristi se prema zadanim postavkama za ovaj USB uređaj"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Koristi se prema zadanim postavkama za ovaj USB pribor"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Omogućiti rješavanje programske pogreške na USB-u?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Omogućiti rješavanje programske pogreške na USB-u na ovom računalu?"\n"Vaš je otisak prsta RSA ključa"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Uvijek dopusti ovom računalu"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zumiraj i ispuni zaslon"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Rastegni i ispuni zaslon"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Kompatibilno zumiranje"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 1805ce0..4d49939 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Megtekintés"</string>
<string name="always_use_device" msgid="1450287437017315906">"Alapértelmezett használat ehhez az USB-eszközhöz"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Alapértelmezett használat ehhez az USB-kiegészítőhöz"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Engedélyezi az USB hibakeresést?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Engedélyezi az USB hibakeresést erről a számítógépről?"\n"Az Ön RSA-kulcs ujjlenyomata"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Mindig legyen engedélyezve ezen a számítógépen"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Nagyítás a kitöltéshez"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Nyújtás kitöltéshez"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Kompatibilitás -- nagyítás/kicsinyítés"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 8eda13f..a9fe4ae 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"表示"</string>
<string name="always_use_device" msgid="1450287437017315906">"このUSBデバイスにデフォルトで使用する"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"このUSBアクセサリにデフォルトで使用する"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"USBデバッグを許可しますか?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"このパソコンからのUSBデバッグを許可しますか?"\n"RSAキーのフィンガープリントは次のとおりです"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"このパソコンを常に許可する"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"画面サイズに合わせて拡大"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"画面サイズに合わせて拡大"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"互換ズーム"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 9562237c..bd1cf03 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"보기"</string>
<string name="always_use_device" msgid="1450287437017315906">"이 USB 기기에 기본값으로 사용"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"이 USB 액세서리에 기본값으로 사용"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"USB 디버깅을 허용하시겠습니까?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"이 컴퓨터에서 USB 디버깅을 허용하시겠습니까?"\n"귀하의 RSA 키 지문 파일은 다음과 같습니다."\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"이 컴퓨터에서 항상 허용"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"전체화면 모드로 확대"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"전체화면 모드로 확대"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"호환성 확대/축소"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index daacca55..a5a11e2 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Žiūrėti"</string>
<string name="always_use_device" msgid="1450287437017315906">"Šiam USB įreng. naudoti pagal numat. nustatymus"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Šiam USB priedui naudoti pagal numat. nustatymus"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Leisti derinti USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Leisti derinti USB šiuo kompiuteriu?"\n"RSA rakto kontrolinis kodas yra"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Visada leisti šį kompiuterį"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Keisti mast., kad atit. ekr."</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Ištempti, kad atit. ekr."</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Suderinamumo mastelio keitimas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index b189fd2..c18b03f 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Skatīt"</string>
<string name="always_use_device" msgid="1450287437017315906">"Pēc noklusējuma izmantot šai USB ierīcei"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Pēc noklusējuma izmantot šim USB piederumam"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Vai atļaut USB atkļūdošanu?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Vai atļaut USB atkļūdošanu no šī datora?"\n"Jūsu RSA atslēgas identifikators ir"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Vienmēr atļaut no šī datora"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Tālumm., lai aizp. ekr."</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Stiepiet, lai aizp. ekr."</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Saderības tālummaiņa"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 8da9ed5..ef926ac 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Lihat"</string>
<string name="always_use_device" msgid="1450287437017315906">"Gunakan secara lalai untuk peranti USB ini"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Gunakan secara lalai untuk aksesori USB ini"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Benarkan penyahpepijatan USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Benarkan Penyahpepijatan USB dari komputer ini?"\n"Cap jari kunci RSA anda ialah"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Sentiasa benarkan komputer ini"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zum untuk memenuhi skrin"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Regang utk memenuhi skrin"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zum keserasian"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 50d5e3b..7639c84 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Wyświetl"</string>
<string name="always_use_device" msgid="1450287437017315906">"Używaj domyślnie dla tego urządzenia USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Używaj domyślnie dla tego akcesorium USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Zezwalać na debugowanie USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Zezwalać na debugowanie USB z tego komputera?"\n"Twój odcisk cyfrowy klucza RSA to"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Zawsze zezwalaj dla tego komputera"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Powiększ, aby wypełnić ekran"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Rozciągnij, aby wypełnić ekran"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Powiększenie w trybie zgodności"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index b583aea..4b41ca0 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Ver"</string>
<string name="always_use_device" msgid="1450287437017315906">"Utilizar por predefinição para este aparelho USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Utilizar por predefinição para este acessório USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Permitir Depuração USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Permitir a Depuração USB a partir deste computador?"\n"A sua pegada digital da chave RSA é"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Permitir sempre este computador"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom para preencher o ecrã"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Esticar p. caber em ec. int."</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilidade"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index bae61d0..b88e096 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Visualizar"</string>
<string name="always_use_device" msgid="1450287437017315906">"Usar por padrão para este dispositivo USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Usar por padrão para este acessório USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Permitir a depuração USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Permitir a depuração USB a partir deste computador?"\n"A impressão digital de sua chave RSA é"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Sempre permitir este computador"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom p/ preencher a tela"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Ampliar p/ preencher tela"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom em modo de compatibilidade"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 5580f01..c7dff3a 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Afişaţi"</string>
<string name="always_use_device" msgid="1450287437017315906">"Utilizaţi în mod prestabilit pt. acest dispoz. USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Utiliz. în mod prestabilit pt. acest accesoriu USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Permiteţi depanarea USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Permiteţi depanarea USB de pe acest computer?"\n"Amprenta digitală din cheia RSA este"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Permiteţi întotdeauna de pe acest computer"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom pt. a umple ecranul"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Înt. pt. a umple ecranul"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilitate"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 567d1de..b53fbe2 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Просмотр"</string>
<string name="always_use_device" msgid="1450287437017315906">"Использовать по умолчанию для этого USB-устройства"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Использовать по умолчанию для этого USB-аксессуара"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Разрешить отладку по USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Разрешить отладку по USB с этого компьютера?"\n"Контрольная сумма ключа RSA:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Всегда разрешать отладку с этого компьютера"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Подогнать по размерам экрана"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Растянуть на весь экран"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Масштаб и совместимость"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 01a8606..b57afe3 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Zobraziť"</string>
<string name="always_use_device" msgid="1450287437017315906">"Pre toto zariadenie USB použiť ako predvolené"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Pre toto periférne zar. USB použiť ako predvolené"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Chcete povoliť ladenie USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Chcete povoliť ladenie USB z tohto počítača?"\n"Digitálny odtlačok vášho kľúča RSA je"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Vždy povoliť v tomto počítači"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Priblížiť na celú obrazovku"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Na celú obrazovku"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Úprava veľkosti z dôvodu kompatibility"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 3987d76..5dbbbb4 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Прикажи"</string>
<string name="always_use_device" msgid="1450287437017315906">"Користи подразумевано за овај USB уређај"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Користи подразумевано за овај USB додатак"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Желите ли да дозволите отклањање USB грешака?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Желите ли да дозволите отклањање USB грешака са овог рачунара?"\n"Дигитални отисак RSA кључа је"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Увек дозволи овај рачунар"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Зумирај на целом екрану"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Развуци на цео екран"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Компатибилно зумирање"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 0c42f87..c24fa36 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"ดู"</string>
<string name="always_use_device" msgid="1450287437017315906">"ใช้ค่าเริ่มต้นสำหรับอุปกรณ์ USB นี้"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"ใช้ค่าเริ่มต้นสำหรับอุปกรณ์เสริม USB นี้"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"อนุญาตการแก้ไขข้อบกพร่องของ USB หรือไม่"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"อนุญาตการแก้ไขข้อบกพร่องของ USB จากคอมพิวเตอร์เครื่องนี้หรือไ่ม่"\n"ลายนิ้วมือคีย์ RSA ของคุณคือ"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"อนุญาตคอมพิวเตอร์เครื่องนี้เสมอ"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"ขยายจนเต็มหน้าจอ"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"ยืดจนเต็มหน้าจอ"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"ความเข้ากันได้ของการย่อ/ขยาย"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index bb0a2bf..ad601c9 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Tingnan"</string>
<string name="always_use_device" msgid="1450287437017315906">"Gamitin bilang default para sa USB device"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Gamitin bilang default sa USB accessory na ito"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Payagan ang Pag-debug ng USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Payagan ang Pag-debug ng USB mula sa computer na ito?"\n"Ang iyong RSA key fingerprint ay"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Palaging payagan ang computer na ito"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"I-zoom upang punan screen"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"I-stretch upang mapuno screen"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom sa pagiging Tugma"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 6c30abe..c4c64d9 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Görüntüle"</string>
<string name="always_use_device" msgid="1450287437017315906">"Bu USB cihazı için varsayılan olarak kullan"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Bu USB aksesuar için varsayılan olarak kullan"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"USB Hata Ayıklama işlemine izin verilsin mi?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Bu bilgisayardan USB Hata Ayıklama işlemine izin verilsin mi?"\n"RSA anahtarı parmak iziniz:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Bu bilgisayara her zaman izin ver"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Yakınlaştır (ekranı kaplasın)"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Genişlet (ekran kapansın)"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Uyumluluk yakınlaştırması"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index cef38ecb..c642c87 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Xem"</string>
<string name="always_use_device" msgid="1450287437017315906">"Sử dụng theo mặc định cho thiết bị USB này"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Sử dụng theo mặc định cho phụ kiện USB này"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Cho phép gỡ lỗi USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Cho phép gỡ lỗi USB từ máy tính này?"\n"Tệp tham chiếu chính của RSA của bạn là"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Luôn cho phép máy tính này"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"T.phóng để lấp đầy m.hình"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Giãn ra để lấp đầy m.hình"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Thu phóng tương thích"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index d0f4a9c..408f861 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"查看"</string>
<string name="always_use_device" msgid="1450287437017315906">"默认情况下用于该 USB 设备"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"默认情况下用于该 USB 配件"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"是否允许 USB 调试?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"是否允许在此计算机上进行 USB 调试?"\n"您的 RSA 密钥指纹是"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"始终允许在此计算机上进行 USB 调试"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"缩放以填满屏幕"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"拉伸以填满屏幕"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"兼容性缩放"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 2e5211f..debdb1c 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"查看"</string>
<string name="always_use_device" msgid="1450287437017315906">"預設用於這個 USB 裝置"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"預設用於這個 USB 配件"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"允許 USB 偵錯嗎?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"允許透過這台電腦進行 USB 偵錯嗎?"\n"您的 RSA 金鑰指紋如下"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"一律允許這台電腦"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"放大為全螢幕"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"放大為全螢幕"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"相容性縮放"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 07c9f0f..f31a11e 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Buka"</string>
<string name="always_use_device" msgid="1450287437017315906">"Sebenzisa ngokuzenzakalelayo yale divayisi ye-USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Sebenzisa ngokuzenzakalelayo kule-accessory ye-USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Vumela ukulungisa iphutha le-USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Vumela isa ukulung-USB Debugging kusuka kule khompyutha?"\n"Izigxivizo zakho zeminwe zokhiye we-RSA ngu-"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Hlala uvumela le khompyutha"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Sondeza ukugcwalisa isikrini"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Nweba ukugcwalisa isikrini"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Ukuhambelana Kokusondeza"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9539373..94465e2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -28,6 +28,7 @@
<!-- Size of application thumbnail -->
<dimen name="status_bar_recents_thumbnail_width">164dp</dimen>
<dimen name="status_bar_recents_thumbnail_height">145dp</dimen>
+ <dimen name="status_bar_recents_thumbnail_bg_padding">4dp</dimen>
<!-- Size of application label text -->
<dimen name="status_bar_recents_app_label_text_size">14dip</dimen>
@@ -163,6 +164,9 @@
<integer name="notification_panel_layout_gravity">0x37</integer>
<integer name="settings_panel_layout_gravity">0x37</integer>
+ <!-- Quick settings panels minimum fling open target width. -->
+ <dimen name="settings_panel_fling_gutter">90dp</dimen>
+
<!-- Height of the carrier/wifi name label -->
<dimen name="carrier_label_height">24dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
new file mode 100644
index 0000000..f97d4ff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -0,0 +1,32 @@
+/*
+ * 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.systemui;
+
+import android.app.Application;
+
+import com.android.systemui.recent.RecentTasksLoader;
+
+public class SystemUIApplication extends Application {
+ private RecentTasksLoader mRecentTasksLoader;
+
+ public RecentTasksLoader getRecentTasksLoader() {
+ if (mRecentTasksLoader == null) {
+ mRecentTasksLoader = new RecentTasksLoader(this);
+ }
+ return mRecentTasksLoader;
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
deleted file mode 100644
index 18ad682..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recent;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.AnimatorSet.Builder;
-import android.animation.ObjectAnimator;
-import android.content.res.Resources;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.util.Slog;
-import android.view.View;
-
-import com.android.systemui.R;
-
-/* package */ class Choreographer implements Animator.AnimatorListener {
- // should group this into a multi-property animation
- private static final int OPEN_DURATION = 136;
- private static final int CLOSE_DURATION = 230;
- private static final int SCRIM_DURATION = 400;
- private static final String TAG = RecentsPanelView.TAG;
- private static final boolean DEBUG = RecentsPanelView.DEBUG;
-
- boolean mVisible;
- int mPanelHeight;
- RecentsPanelView mRootView;
- View mScrimView;
- View mContentView;
- View mNoRecentAppsView;
- AnimatorSet mContentAnim;
- Animator.AnimatorListener mListener;
-
- // the panel will start to appear this many px from the end
- final int HYPERSPACE_OFFRAMP = 200;
-
- public Choreographer(RecentsPanelView root, View scrim, View content,
- View noRecentApps, Animator.AnimatorListener listener) {
- mRootView = root;
- mScrimView = scrim;
- mContentView = content;
- mListener = listener;
- mNoRecentAppsView = noRecentApps;
- }
-
- void createAnimation(boolean appearing) {
- float start, end;
-
- // 0: on-screen
- // height: off-screen
- float y = mContentView.getTranslationY();
- if (appearing) {
- // we want to go from near-the-top to the top, unless we're half-open in the right
- // general vicinity
- start = (y < HYPERSPACE_OFFRAMP) ? y : HYPERSPACE_OFFRAMP;
- end = 0;
- } else {
- start = y;
- end = y;
- }
-
- Animator posAnim = ObjectAnimator.ofFloat(mContentView, "translationY",
- start, end);
- posAnim.setInterpolator(appearing
- ? new android.view.animation.DecelerateInterpolator(2.5f)
- : new android.view.animation.AccelerateInterpolator(2.5f));
- posAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
-
- Animator fadeAnim = ObjectAnimator.ofFloat(mContentView, "alpha",
- mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
- fadeAnim.setInterpolator(appearing
- ? new android.view.animation.AccelerateInterpolator(1.0f)
- : new android.view.animation.AccelerateInterpolator(2.5f));
- fadeAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
-
- Animator noRecentAppsFadeAnim = null;
- if (mNoRecentAppsView != null && // doesn't exist on large devices
- mNoRecentAppsView.getVisibility() == View.VISIBLE) {
- noRecentAppsFadeAnim = ObjectAnimator.ofFloat(mNoRecentAppsView, "alpha",
- mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
- noRecentAppsFadeAnim.setInterpolator(appearing
- ? new android.view.animation.AccelerateInterpolator(1.0f)
- : new android.view.animation.DecelerateInterpolator(1.0f));
- noRecentAppsFadeAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
- }
-
- mContentAnim = new AnimatorSet();
- final Builder builder = mContentAnim.play(fadeAnim).with(posAnim);
-
- if (noRecentAppsFadeAnim != null) {
- builder.with(noRecentAppsFadeAnim);
- }
-
- if (appearing) {
- Drawable background = mScrimView.getBackground();
- if (background != null) {
- Animator bgAnim = ObjectAnimator.ofInt(background,
- "alpha", appearing ? 0 : 255, appearing ? 255 : 0);
- bgAnim.setDuration(appearing ? SCRIM_DURATION : CLOSE_DURATION);
- builder.with(bgAnim);
- }
- } else {
- final Resources res = mRootView.getResources();
- boolean isTablet = res.getBoolean(R.bool.config_recents_interface_for_tablets);
- if (!isTablet) {
- View recentsTransitionBackground =
- mRootView.findViewById(R.id.recents_transition_background);
- recentsTransitionBackground.setVisibility(View.VISIBLE);
- Drawable bgDrawable = new ColorDrawable(0xFF000000);
- recentsTransitionBackground.setBackground(bgDrawable);
- Animator bgAnim = ObjectAnimator.ofInt(bgDrawable, "alpha", 0, 255);
- bgAnim.setDuration(CLOSE_DURATION);
- bgAnim.setInterpolator(new android.view.animation.AccelerateInterpolator(1f));
- builder.with(bgAnim);
- }
- }
- mContentAnim.addListener(this);
- if (mListener != null) {
- mContentAnim.addListener(mListener);
- }
- }
-
- void startAnimation(boolean appearing) {
- if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
-
- createAnimation(appearing);
-
- // isHardwareAccelerated() checks if we're attached to a window and if that
- // window is HW accelerated-- we were sometimes not attached to a window
- // and buildLayer was throwing an IllegalStateException
- if (mContentView.isHardwareAccelerated()) {
- mContentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- mContentView.buildLayer();
- }
- mContentAnim.start();
-
- mVisible = appearing;
- }
-
- void jumpTo(boolean appearing) {
- mContentView.setTranslationY(appearing ? 0 : mPanelHeight);
- if (mScrimView.getBackground() != null) {
- mScrimView.getBackground().setAlpha(appearing ? 255 : 0);
- }
- View recentsTransitionBackground =
- mRootView.findViewById(R.id.recents_transition_background);
- recentsTransitionBackground.setVisibility(View.INVISIBLE);
- mRootView.requestLayout();
- }
-
- public void setPanelHeight(int h) {
- if (DEBUG) Slog.d(TAG, "panelHeight=" + h);
- mPanelHeight = h;
- }
-
- public void onAnimationCancel(Animator animation) {
- if (DEBUG) Slog.d(TAG, "onAnimationCancel");
- // force this to zero so we close the window
- mVisible = false;
- }
-
- public void onAnimationEnd(Animator animation) {
- if (DEBUG) Slog.d(TAG, "onAnimationEnd");
- if (!mVisible) {
- mRootView.hideWindow();
- }
- mContentView.setLayerType(View.LAYER_TYPE_NONE, null);
- mContentView.setAlpha(1f);
- mContentAnim = null;
- }
-
- public void onAnimationRepeat(Animator animation) {
- }
-
- public void onAnimationStart(Animator animation) {
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 4d8c168..4281ccf 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -32,6 +32,8 @@
import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
@@ -42,7 +44,7 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
-public class RecentTasksLoader {
+public class RecentTasksLoader implements View.OnTouchListener {
static final String TAG = "RecentTasksLoader";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
@@ -51,17 +53,43 @@
private Context mContext;
private RecentsPanelView mRecentsPanel;
+ private TaskDescription mFirstTask;
+ private boolean mFirstTaskLoaded;
private AsyncTask<Void, ArrayList<TaskDescription>, Void> mTaskLoader;
private AsyncTask<Void, TaskDescription, Void> mThumbnailLoader;
+ private Handler mHandler;
private int mIconDpi;
private Bitmap mDefaultThumbnailBackground;
private Bitmap mDefaultIconBackground;
- private int mNumTasksInFirstScreenful;
+ private int mNumTasksInFirstScreenful = Integer.MAX_VALUE;
+
+ private boolean mFirstScreenful;
+ private ArrayList<TaskDescription> mLoadedTasks;
+
+ private enum State { LOADING, LOADED, CANCELLED };
+ private State mState = State.CANCELLED;
+
+ public TaskDescription getFirstTask() {
+ while (!mFirstTaskLoaded) {
+ if (mState == State.CANCELLED) {
+ loadTasksInBackground();
+ }
+ try {
+ if (mState == State.LOADED) {
+ break;
+ }
+ Thread.sleep(5);
+ } catch (InterruptedException e) {
+ }
+ }
+ return mFirstTask;
+ }
public RecentTasksLoader(Context context) {
mContext = context;
+ mHandler = new Handler();
final Resources res = context.getResources();
@@ -91,16 +119,16 @@
Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(mDefaultThumbnailBackground);
c.drawColor(color);
-
- // If we're using the cache, begin listening to the activity manager for
- // updated thumbnails
- final ActivityManager am = (ActivityManager)
- mContext.getSystemService(Context.ACTIVITY_SERVICE);
}
- public void setRecentsPanel(RecentsPanelView recentsPanel) {
- mRecentsPanel = recentsPanel;
- mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful();
+ public void setRecentsPanel(RecentsPanelView newRecentsPanel, RecentsPanelView caller) {
+ // Only allow clearing mRecentsPanel if the caller is the current recentsPanel
+ if (newRecentsPanel != null || mRecentsPanel == caller) {
+ mRecentsPanel = newRecentsPanel;
+ if (mRecentsPanel != null) {
+ mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful();
+ }
+ }
}
public Bitmap getDefaultThumbnail() {
@@ -111,26 +139,33 @@
return mDefaultIconBackground;
}
- // Create an TaskDescription, returning null if the title or icon is null, or if it's the
- // home activity
+ public ArrayList<TaskDescription> getLoadedTasks() {
+ return mLoadedTasks;
+ }
+
+ public boolean isFirstScreenful() {
+ return mFirstScreenful;
+ }
+
+ private boolean isCurrentHomeActivity(ComponentName component, ActivityInfo homeInfo) {
+ if (homeInfo == null) {
+ final PackageManager pm = mContext.getPackageManager();
+ homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
+ .resolveActivityInfo(pm, 0);
+ }
+ return homeInfo != null
+ && homeInfo.packageName.equals(component.getPackageName())
+ && homeInfo.name.equals(component.getClassName());
+ }
+
+ // Create an TaskDescription, returning null if the title or icon is null
TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent,
- ComponentName origActivity, CharSequence description, ActivityInfo homeInfo) {
+ ComponentName origActivity, CharSequence description) {
Intent intent = new Intent(baseIntent);
if (origActivity != null) {
intent.setComponent(origActivity);
}
final PackageManager pm = mContext.getPackageManager();
- if (homeInfo == null) {
- homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
- .resolveActivityInfo(pm, 0);
- }
- // Don't load the current home activity.
- if (homeInfo != null
- && homeInfo.packageName.equals(intent.getComponent().getPackageName())
- && homeInfo.name.equals(intent.getComponent().getClassName())) {
- return null;
- }
-
intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
| Intent.FLAG_ACTIVITY_NEW_TASK);
final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
@@ -207,7 +242,43 @@
return getFullResDefaultActivityIcon();
}
- public void cancelLoadingThumbnailsAndIcons() {
+ Runnable mPreloadTasksRunnable = new Runnable() {
+ public void run() {
+ loadTasksInBackground();
+ }
+ };
+
+ // additional optimization when we have software system buttons - start loading the recent
+ // tasks on touch down
+ @Override
+ public boolean onTouch(View v, MotionEvent ev) {
+ int action = ev.getAction() & MotionEvent.ACTION_MASK;
+ if (action == MotionEvent.ACTION_DOWN) {
+ mHandler.post(mPreloadTasksRunnable);
+ } else if (action == MotionEvent.ACTION_CANCEL) {
+ cancelLoadingThumbnailsAndIcons();
+ mHandler.removeCallbacks(mPreloadTasksRunnable);
+ } else if (action == MotionEvent.ACTION_UP) {
+ // Remove the preloader if we haven't called it yet
+ mHandler.removeCallbacks(mPreloadTasksRunnable);
+ if (!v.isPressed()) {
+ cancelLoadingThumbnailsAndIcons();
+ }
+
+ }
+ return false;
+ }
+
+ public void cancelLoadingThumbnailsAndIcons(RecentsPanelView caller) {
+ // Only oblige this request if it comes from the current RecentsPanel
+ // (eg when you rotate, the old RecentsPanel request should be ignored)
+ if (mRecentsPanel == caller) {
+ cancelLoadingThumbnailsAndIcons();
+ }
+ }
+
+
+ private void cancelLoadingThumbnailsAndIcons() {
if (mTaskLoader != null) {
mTaskLoader.cancel(false);
mTaskLoader = null;
@@ -216,11 +287,26 @@
mThumbnailLoader.cancel(false);
mThumbnailLoader = null;
}
+ mLoadedTasks = null;
+ mFirstTask = null;
+ mFirstTaskLoaded = false;
+ if (mRecentsPanel != null) {
+ mRecentsPanel.onTaskLoadingCancelled();
+ }
+ mFirstScreenful = false;
+ mState = State.CANCELLED;
}
public void loadTasksInBackground() {
- // cancel all previous loading of tasks and thumbnails
- cancelLoadingThumbnailsAndIcons();
+ loadTasksInBackground(false);
+ }
+ public void loadTasksInBackground(final boolean zeroeth) {
+ if (mState != State.CANCELLED) {
+ return;
+ }
+ mState = State.LOADING;
+ mFirstScreenful = true;
+
final LinkedBlockingQueue<TaskDescription> tasksWaitingForThumbnails =
new LinkedBlockingQueue<TaskDescription>();
mTaskLoader = new AsyncTask<Void, ArrayList<TaskDescription>, Void>() {
@@ -230,7 +316,14 @@
ArrayList<TaskDescription> newTasks = values[0];
// do a callback to RecentsPanelView to let it know we have more values
// how do we let it know we're all done? just always call back twice
- mRecentsPanel.onTasksLoaded(newTasks);
+ if (mRecentsPanel != null) {
+ mRecentsPanel.onTasksLoaded(newTasks, mFirstScreenful);
+ }
+ if (mLoadedTasks == null) {
+ mLoadedTasks = new ArrayList<TaskDescription>();
+ }
+ mLoadedTasks.addAll(newTasks);
+ mFirstScreenful = false;
}
}
@Override
@@ -254,15 +347,34 @@
ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
// skip the first task - assume it's either the home screen or the current activity.
- final int first = 1;
+ final int first = 0;
for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
if (isCancelled()) {
break;
}
final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
+
+ Intent intent = new Intent(recentInfo.baseIntent);
+ if (recentInfo.origActivity != null) {
+ intent.setComponent(recentInfo.origActivity);
+ }
+
+ // Don't load the current home activity.
+ if (isCurrentHomeActivity(intent.getComponent(), homeInfo)) {
+ if (index == 0) {
+ mFirstTaskLoaded = true;
+ }
+ continue;
+ }
+
+ // Don't load ourselves
+ if (intent.getComponent().getPackageName().equals(mContext.getPackageName())) {
+ continue;
+ }
+
TaskDescription item = createTaskDescription(recentInfo.id,
recentInfo.persistentId, recentInfo.baseIntent,
- recentInfo.origActivity, recentInfo.description, homeInfo);
+ recentInfo.origActivity, recentInfo.description);
if (item != null) {
while (true) {
@@ -317,7 +429,13 @@
protected void onProgressUpdate(TaskDescription... values) {
if (!isCancelled()) {
TaskDescription td = values[0];
- mRecentsPanel.onTaskThumbnailLoaded(td);
+ if (td.isNull()) { // end sentinel
+ mState = State.LOADED;
+ } else {
+ if (mRecentsPanel != null) {
+ mRecentsPanel.onTaskThumbnailLoaded(td);
+ }
+ }
}
}
@Override
@@ -336,19 +454,25 @@
} catch (InterruptedException e) {
}
}
- if (td.isNull()) {
+ if (td.isNull()) { // end sentinel
+ publishProgress(td);
break;
}
loadThumbnailAndIcon(td);
- synchronized(td) {
- publishProgress(td);
+
+ if (!mFirstTaskLoaded) {
+ mFirstTask = td;
+ mFirstTaskLoaded = true;
}
+ publishProgress(td);
}
Process.setThreadPriority(origPri);
return null;
}
};
+ mFirstTask = null;
+ mFirstTaskLoaded = false;
mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
new file mode 100644
index 0000000..a4c8e64
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
@@ -0,0 +1,176 @@
+/*
+ * 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.systemui.recent;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.SystemUIApplication;
+import com.android.systemui.statusbar.tablet.StatusBarPanel;
+
+public class RecentsActivity extends Activity {
+ public static final String TOGGLE_RECENTS_INTENT = "com.android.systemui.TOGGLE_RECENTS";
+ public static final String CLOSE_RECENTS_INTENT = "com.android.systemui.CLOSE_RECENTS";
+
+ private RecentsPanelView mRecentsPanel;
+ private IntentFilter mIntentFilter;
+ private boolean mShowing;
+ private boolean mForeground;
+ private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
+ if (mShowing && !mForeground) {
+ // Captures the case right before we transition to another activity
+ mRecentsPanel.show(false);
+ }
+ }
+ }
+ };
+
+ public class TouchOutsideListener implements View.OnTouchListener {
+ private StatusBarPanel mPanel;
+
+ public TouchOutsideListener(StatusBarPanel panel) {
+ mPanel = panel;
+ }
+
+ public boolean onTouch(View v, MotionEvent ev) {
+ final int action = ev.getAction();
+ if (action == MotionEvent.ACTION_OUTSIDE
+ || (action == MotionEvent.ACTION_DOWN
+ && !mPanel.isInContentArea((int) ev.getX(), (int) ev.getY()))) {
+ dismissAndGoHome();
+ return true;
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public void onPause() {
+ mForeground = false;
+ super.onPause();
+ }
+
+ @Override
+ public void onStop() {
+ mShowing = false;
+ if (mRecentsPanel != null) {
+ mRecentsPanel.onUiHidden();
+ }
+ super.onStop();
+ }
+
+ @Override
+ public void onStart() {
+ mShowing = true;
+ super.onStart();
+ }
+
+ @Override
+ public void onResume() {
+ mForeground = true;
+ super.onResume();
+ }
+
+ @Override
+ public void onBackPressed() {
+ dismissAndGoBack();
+ }
+
+ public void dismissAndGoHome() {
+ if (mRecentsPanel != null) {
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ startActivityAsUser(homeIntent, new UserHandle(UserHandle.USER_CURRENT));
+ mRecentsPanel.show(false);
+ }
+ }
+
+ public void dismissAndGoBack() {
+ if (mRecentsPanel != null) {
+ final SystemUIApplication app = (SystemUIApplication) getApplication();
+ final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
+ TaskDescription firstTask = recentTasksLoader.getFirstTask();
+ if (firstTask != null && mRecentsPanel.simulateClick(firstTask)) {
+ // recents panel will take care of calling show(false);
+ return;
+ }
+ mRecentsPanel.show(false);
+ }
+ finish();
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ final SystemUIApplication app = (SystemUIApplication) getApplication();
+ final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
+
+ setContentView(R.layout.status_bar_recent_panel);
+ mRecentsPanel = (RecentsPanelView) findViewById(R.id.recents_root);
+ mRecentsPanel.setOnTouchListener(new TouchOutsideListener(mRecentsPanel));
+ mRecentsPanel.setRecentTasksLoader(recentTasksLoader);
+ recentTasksLoader.setRecentsPanel(mRecentsPanel, mRecentsPanel);
+
+ handleIntent(getIntent());
+ mIntentFilter = new IntentFilter();
+ mIntentFilter.addAction(CLOSE_RECENTS_INTENT);
+ registerReceiver(mIntentReceiver, mIntentFilter);
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ final SystemUIApplication app = (SystemUIApplication) getApplication();
+ final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
+ recentTasksLoader.setRecentsPanel(null, mRecentsPanel);
+ unregisterReceiver(mIntentReceiver);
+ super.onDestroy();
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ handleIntent(intent);
+ }
+
+ private void handleIntent(Intent intent) {
+ super.onNewIntent(intent);
+
+ if (TOGGLE_RECENTS_INTENT.equals(intent.getAction())) {
+ if (mRecentsPanel != null && !mRecentsPanel.isShowing()) {
+ final SystemUIApplication app = (SystemUIApplication) getApplication();
+ final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
+ mRecentsPanel.show(true, recentTasksLoader.getLoadedTasks(),
+ recentTasksLoader.isFirstScreenful());
+ } else if ((mRecentsPanel != null && mRecentsPanel.isShowing())) {
+ dismissAndGoBack();
+ }
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index e9c2ecb7..4aa2095 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -76,6 +76,17 @@
}
}
+ public View findViewForTask(TaskDescription task) {
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View v = mLinearLayout.getChildAt(i);
+ RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) v.getTag();
+ if (holder.taskDescription == task) {
+ return v;
+ }
+ }
+ return null;
+ }
+
private void update() {
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
View v = mLinearLayout.getChildAt(i);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index b407078..c3ecdb5 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -29,20 +29,17 @@
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Matrix;
-import android.graphics.Rect;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
-import android.view.IWindowManager;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
@@ -71,7 +68,7 @@
import java.util.ArrayList;
public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback,
- StatusBarPanel, Animator.AnimatorListener, View.OnTouchListener {
+ StatusBarPanel, Animator.AnimatorListener {
static final String TAG = "RecentsPanelView";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
private Context mContext;
@@ -84,36 +81,22 @@
private boolean mShowing;
private boolean mWaitingToShow;
- private boolean mWaitingToShowAnimated;
- private boolean mReadyToShow;
private int mNumItemsWaitingForThumbnailsAndIcons;
- private Choreographer mChoreo;
- OnRecentsPanelVisibilityChangedListener mVisibilityChangedListener;
-
- ImageView mPlaceholderThumbnail;
- View mTransitionBg;
- boolean mHideRecentsAfterThumbnailScaleUpStarted;
private RecentTasksLoader mRecentTasksLoader;
private ArrayList<TaskDescription> mRecentTaskDescriptions;
- private Runnable mPreloadTasksRunnable;
- private boolean mRecentTasksDirty = true;
private TaskDescriptionAdapter mListAdapter;
private int mThumbnailWidth;
private boolean mFitThumbnailToXY;
private int mRecentItemLayoutId;
- private boolean mFirstScreenful = true;
private boolean mHighEndGfx;
- public static interface OnRecentsPanelVisibilityChangedListener {
- public void onRecentsPanelVisibilityChanged(boolean visible);
- }
-
public static interface RecentsScrollView {
public int numItemsInOneScreenful();
public void setAdapter(TaskDescriptionAdapter adapter);
public void setCallback(RecentsCallback callback);
public void setMinSwipeAlpha(float minAlpha);
+ public View findViewForTask(TaskDescription task);
}
private final class OnLongClickDelegate implements View.OnLongClickListener {
@@ -252,15 +235,6 @@
}
}
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK && !event.isCanceled()) {
- show(false, false);
- return true;
- }
- return super.onKeyUp(keyCode, event);
- }
-
private boolean pointInside(int x, int y, View v) {
final int l = v.getLeft();
final int r = v.getRight();
@@ -280,22 +254,26 @@
}
}
- public void show(boolean show, boolean animate) {
+ public void show(boolean show) {
+ show(show, null, false);
+ }
+
+ public void show(boolean show, ArrayList<TaskDescription> recentTaskDescriptions,
+ boolean firstScreenful) {
if (show) {
- refreshRecentTasksList(null, true);
mWaitingToShow = true;
- mWaitingToShowAnimated = animate;
+ refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
showIfReady();
} else {
- show(show, animate, null, false);
+ showImpl(false);
}
}
private void showIfReady() {
- // mWaitingToShow = there was a touch up on the recents button
- // mReadyToShow = we've created views for the first screenful of items
- if (mWaitingToShow && mReadyToShow) { // && mNumItemsWaitingForThumbnailsAndIcons <= 0
- show(true, mWaitingToShowAnimated, null, false);
+ // mWaitingToShow => there was a touch up on the recents button
+ // mRecentTaskDescriptions != null => we've created views for the first screenful of items
+ if (mWaitingToShow && mRecentTaskDescriptions != null) {
+ showImpl(true);
}
}
@@ -308,79 +286,44 @@
}
}
- public void show(boolean show, boolean animate,
- ArrayList<TaskDescription> recentTaskDescriptions, boolean firstScreenful) {
+ private void showImpl(boolean show) {
sendCloseSystemWindows(mContext, BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
+ mShowing = show;
+
if (show) {
- // Need to update list of recent apps before we set visibility so this view's
- // content description is updated before it gets focus for TalkBack mode
- refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
+ // if there are no apps, bring up a "No recent apps" message
+ boolean noApps = mRecentTaskDescriptions != null
+ && (mRecentTaskDescriptions.size() == 0);
+ mRecentsNoApps.setAlpha(1f);
+ mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE);
- // if there are no apps, either bring up a "No recent apps" message, or just
- // quit early
- boolean noApps = !mFirstScreenful && (mRecentTaskDescriptions.size() == 0);
- if (mRecentsNoApps != null) {
- mRecentsNoApps.setAlpha(1f);
- mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE);
- } else {
- if (noApps) {
- if (DEBUG) Log.v(TAG, "Nothing to show");
- // Need to set recent tasks to dirty so that next time we load, we
- // refresh the list of tasks
- mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
- mRecentTasksDirty = true;
-
- mWaitingToShow = false;
- mReadyToShow = false;
- return;
- }
- }
- } else {
- // Need to set recent tasks to dirty so that next time we load, we
- // refresh the list of tasks
- mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
- mRecentTasksDirty = true;
- mWaitingToShow = false;
- mReadyToShow = false;
- }
- if (animate) {
- if (mShowing != show) {
- mShowing = show;
- if (show) {
- setVisibility(View.VISIBLE);
- }
- mChoreo.startAnimation(show);
- }
- } else {
- mShowing = show;
- setVisibility(show ? View.VISIBLE : View.GONE);
- mChoreo.jumpTo(show);
onAnimationEnd(null);
- }
- if (show) {
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
} else {
+ mWaitingToShow = false;
+ // call onAnimationEnd() and clearRecentTasksList() in onUiHidden()
if (mPopup != null) {
mPopup.dismiss();
}
}
}
- public void dismiss() {
- hide(true);
+ public void onUiHidden() {
+ if (!mShowing && mRecentTaskDescriptions != null) {
+ onAnimationEnd(null);
+ clearRecentTasksList();
+ }
}
- public void hide(boolean animate) {
- if (!animate) {
- setVisibility(View.GONE);
- }
- if (mBar != null) {
- // This will indirectly cause show(false, ...) to get called
- mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
- }
+ public void dismiss() {
+ ((RecentsActivity) mContext).dismissAndGoHome();
+ }
+
+ public void dismissAndGoBack() {
+ ((RecentsActivity) mContext).dismissAndGoBack();
}
public void onAnimationCancel(Animator animation) {
@@ -393,7 +336,6 @@
createCustomAnimations(transitioner);
} else {
((ViewGroup)mRecentsContainer).setLayoutTransition(null);
- clearRecentTasksList();
}
}
@@ -403,16 +345,6 @@
public void onAnimationStart(Animator animation) {
}
- /**
- * We need to be aligned at the bottom. LinearLayout can't do this, so instead,
- * let LinearLayout do all the hard work, and then shift everything down to the bottom.
- */
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- mChoreo.setPanelHeight(mRecentsContainer.getHeight());
- }
-
@Override
public boolean dispatchHoverEvent(MotionEvent event) {
// Ignore hover events outside of this panel bounds since such events
@@ -449,18 +381,6 @@
mRecentTasksLoader = loader;
}
- public void setOnVisibilityChangedListener(OnRecentsPanelVisibilityChangedListener l) {
- mVisibilityChangedListener = l;
-
- }
-
- public void setVisibility(int visibility) {
- if (mVisibilityChangedListener != null) {
- mVisibilityChangedListener.onRecentsPanelVisibilityChanged(visibility == VISIBLE);
- }
- super.setVisibility(visibility);
- }
-
public void updateValuesFromResources() {
final Resources res = mContext.getResources();
mThumbnailWidth = Math.round(res.getDimension(R.dimen.status_bar_recents_thumbnail_width));
@@ -486,7 +406,6 @@
mRecentsScrim = findViewById(R.id.recents_bg_protect);
mRecentsNoApps = findViewById(R.id.recents_no_apps);
- mChoreo = new Choreographer(this, mRecentsScrim, mRecentsContainer, mRecentsNoApps, this);
if (mRecentsScrim != null) {
mHighEndGfx = ActivityManager.isHighEndGfx();
@@ -497,18 +416,6 @@
((BitmapDrawable) mRecentsScrim.getBackground()).setTileModeY(TileMode.REPEAT);
}
}
-
- mPreloadTasksRunnable = new Runnable() {
- public void run() {
- // If we set our visibility to INVISIBLE here, we avoid an extra call to
- // onLayout later when we become visible (because onLayout is always called
- // when going from GONE)
- if (!mShowing) {
- setVisibility(INVISIBLE);
- refreshRecentTasksList();
- }
- }
- };
}
public void setMinSwipeAlpha(float minAlpha) {
@@ -602,44 +509,19 @@
showIfReady();
}
- // additional optimization when we have software system buttons - start loading the recent
- // tasks on touch down
- @Override
- public boolean onTouch(View v, MotionEvent ev) {
- if (!mShowing) {
- int action = ev.getAction() & MotionEvent.ACTION_MASK;
- if (action == MotionEvent.ACTION_DOWN) {
- post(mPreloadTasksRunnable);
- } else if (action == MotionEvent.ACTION_CANCEL) {
- setVisibility(GONE);
- clearRecentTasksList();
- // Remove the preloader if we haven't called it yet
- removeCallbacks(mPreloadTasksRunnable);
- } else if (action == MotionEvent.ACTION_UP) {
- // Remove the preloader if we haven't called it yet
- removeCallbacks(mPreloadTasksRunnable);
- if (!v.isPressed()) {
- setVisibility(GONE);
- clearRecentTasksList();
- }
- }
- }
- return false;
- }
-
- public void preloadRecentTasksList() {
- if (!mShowing) {
- mPreloadTasksRunnable.run();
- }
- }
-
public void clearRecentTasksList() {
// Clear memory used by screenshots
- if (!mShowing && mRecentTaskDescriptions != null) {
- mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
- mRecentTaskDescriptions.clear();
+ if (mRecentTaskDescriptions != null) {
+ mRecentTasksLoader.cancelLoadingThumbnailsAndIcons(this);
+ onTaskLoadingCancelled();
+ }
+ }
+
+ public void onTaskLoadingCancelled() {
+ // Gets called by RecentTasksLoader when it's cancelled
+ if (mRecentTaskDescriptions != null) {
+ mRecentTaskDescriptions = null;
mListAdapter.notifyDataSetInvalidated();
- mRecentTasksDirty = true;
}
}
@@ -649,23 +531,15 @@
private void refreshRecentTasksList(
ArrayList<TaskDescription> recentTasksList, boolean firstScreenful) {
- if (mRecentTasksDirty) {
- if (recentTasksList != null) {
- mFirstScreenful = true;
- onTasksLoaded(recentTasksList);
- } else {
- mFirstScreenful = true;
- mRecentTasksLoader.loadTasksInBackground();
- }
- mRecentTasksDirty = false;
+ if (mRecentTaskDescriptions == null && recentTasksList != null) {
+ onTasksLoaded(recentTasksList, firstScreenful);
+ } else {
+ mRecentTasksLoader.loadTasksInBackground();
}
}
- public void onTasksLoaded(ArrayList<TaskDescription> tasks) {
- if (!mFirstScreenful && tasks.size() == 0) {
- return;
- }
- mNumItemsWaitingForThumbnailsAndIcons = mFirstScreenful
+ public void onTasksLoaded(ArrayList<TaskDescription> tasks, boolean firstScreenful) {
+ mNumItemsWaitingForThumbnailsAndIcons = firstScreenful
? tasks.size() : mRecentTaskDescriptions == null
? 0 : mRecentTaskDescriptions.size();
if (mRecentTaskDescriptions == null) {
@@ -675,19 +549,9 @@
}
mListAdapter.notifyDataSetInvalidated();
updateUiElements(getResources().getConfiguration());
- mReadyToShow = true;
- mFirstScreenful = false;
showIfReady();
}
- public ArrayList<TaskDescription> getRecentTasksList() {
- return mRecentTaskDescriptions;
- }
-
- public boolean getFirstScreenful() {
- return mFirstScreenful;
- }
-
private void updateUiElements(Configuration config) {
final int items = mRecentTaskDescriptions.size();
@@ -706,8 +570,19 @@
setContentDescription(recentAppsAccessibilityDescription);
}
+ public boolean simulateClick(TaskDescription task) {
+ if (mRecentsContainer instanceof RecentsScrollView){
+ RecentsScrollView scrollView
+ = (RecentsScrollView) mRecentsContainer;
+ View v = scrollView.findViewForTask(task);
+ if (v != null) {
+ handleOnClick(v);
+ return true;
+ }
+ }
+ return false;
+ }
- boolean mThumbnailScaleUpStarted;
public void handleOnClick(View view) {
ViewHolder holder = (ViewHolder)view.getTag();
TaskDescription ad = holder.taskDescription;
@@ -725,59 +600,10 @@
usingDrawingCache = true;
}
- if (mPlaceholderThumbnail == null) {
- mPlaceholderThumbnail =
- (ImageView) findViewById(R.id.recents_transition_placeholder_icon);
- }
- if (mTransitionBg == null) {
- mTransitionBg = (View) findViewById(R.id.recents_transition_background);
-
- IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- try {
- if (!wm.hasSystemNavBar()) {
- FrameLayout.LayoutParams lp =
- (FrameLayout.LayoutParams) mTransitionBg.getLayoutParams();
- int statusBarHeight = getResources().
- getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
- lp.setMargins(0, statusBarHeight, 0, 0);
- mTransitionBg.setLayoutParams(lp);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Failing checking whether status bar is visible", e);
- }
- }
-
- final ImageView placeholderThumbnail = mPlaceholderThumbnail;
- mHideRecentsAfterThumbnailScaleUpStarted = false;
- placeholderThumbnail.setVisibility(VISIBLE);
- if (!usingDrawingCache) {
- placeholderThumbnail.setImageBitmap(bm);
- } else {
- Bitmap b2 = bm.copy(bm.getConfig(), true);
- placeholderThumbnail.setImageBitmap(b2);
- }
- Rect r = new Rect();
- holder.thumbnailViewImage.getGlobalVisibleRect(r);
-
- placeholderThumbnail.setTranslationX(r.left);
- placeholderThumbnail.setTranslationY(r.top);
-
- show(false, true);
-
- mThumbnailScaleUpStarted = false;
ActivityOptions opts = ActivityOptions.makeThumbnailScaleUpAnimation(
- holder.thumbnailViewImage, bm, 0, 0,
- new ActivityOptions.OnAnimationStartedListener() {
- @Override public void onAnimationStarted() {
- mThumbnailScaleUpStarted = true;
- if (!mHighEndGfx) {
- mPlaceholderThumbnail.setVisibility(INVISIBLE);
- }
- if (mHideRecentsAfterThumbnailScaleUpStarted) {
- hideWindow();
- }
- }
- });
+ holder.thumbnailViewImage, bm, 0, 0, null);
+
+ show(false);
if (ad.taskId >= 0) {
// This is an active task; it should just go to the foreground.
am.moveTaskToFront(ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME,
@@ -796,17 +622,6 @@
}
}
- public void hideWindow() {
- if (!mThumbnailScaleUpStarted) {
- mHideRecentsAfterThumbnailScaleUpStarted = true;
- } else {
- setVisibility(GONE);
- mTransitionBg.setVisibility(INVISIBLE);
- mPlaceholderThumbnail.setVisibility(INVISIBLE);
- mHideRecentsAfterThumbnailScaleUpStarted = false;
- }
- }
-
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
handleOnClick(view);
}
@@ -825,7 +640,7 @@
// mListAdapter.notifyDataSetChanged();
if (mRecentTaskDescriptions.size() == 0) {
- hide(false);
+ dismissAndGoBack();
}
// Currently, either direction means the same thing, so ignore direction and remove
@@ -875,7 +690,7 @@
if (viewHolder != null) {
final TaskDescription ad = viewHolder.taskDescription;
startApplicationDetailsActivity(ad.packageName);
- mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
+ show(false);
} else {
throw new IllegalStateException("Oops, no tag on view " + selectedView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index ba08775..a0f197dd 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -77,6 +77,17 @@
}
}
+ public View findViewForTask(TaskDescription task) {
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View v = mLinearLayout.getChildAt(i);
+ RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) v.getTag();
+ if (holder.taskDescription == task) {
+ return v;
+ }
+ }
+ return null;
+ }
+
private void update() {
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
View v = mLinearLayout.getChildAt(i);
@@ -146,7 +157,9 @@
appTitle.setContentDescription(" ");
appTitle.setOnTouchListener(noOpListener);
final View calloutLine = view.findViewById(R.id.recents_callout_line);
- calloutLine.setOnTouchListener(noOpListener);
+ if (calloutLine != null) {
+ calloutLine.setOnTouchListener(noOpListener);
+ }
mLinearLayout.addView(view);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index e9e043e..106ce7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1,3 +1,4 @@
+
/*
* Copyright (C) 2010 The Android Open Source Project
*
@@ -24,23 +25,31 @@
import com.android.systemui.R;
import com.android.systemui.SearchPanelView;
import com.android.systemui.SystemUI;
+import com.android.systemui.SystemUIApplication;
import com.android.systemui.recent.RecentTasksLoader;
-import com.android.systemui.recent.RecentsPanelView;
+import com.android.systemui.recent.RecentsActivity;
import com.android.systemui.recent.TaskDescription;
import com.android.systemui.statusbar.policy.NotificationRowLayout;
import com.android.systemui.statusbar.tablet.StatusBarPanel;
import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.PendingIntent;
+import android.app.Service;
import android.app.TaskStackBuilder;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.database.ContentObserver;
+import android.graphics.Bitmap;
+import android.graphics.Paint;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
@@ -52,6 +61,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;
import android.view.Display;
@@ -73,12 +83,12 @@
import java.util.ArrayList;
public abstract class BaseStatusBar extends SystemUI implements
- CommandQueue.Callbacks, RecentsPanelView.OnRecentsPanelVisibilityChangedListener {
+ CommandQueue.Callbacks {
static final String TAG = "StatusBar";
private static final boolean DEBUG = false;
public static final boolean MULTIUSER_DEBUG = false;
- protected static final int MSG_OPEN_RECENTS_PANEL = 1020;
+ protected static final int MSG_TOGGLE_RECENTS_PANEL = 1020;
protected static final int MSG_CLOSE_RECENTS_PANEL = 1021;
protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
@@ -111,10 +121,6 @@
// Search panel
protected SearchPanelView mSearchPanelView;
- // Recent apps
- protected RecentsPanelView mRecentsPanel;
- protected RecentTasksLoader mRecentTasksLoader;
-
protected PopupMenu mNotificationBlamePopup;
protected int mCurrentUserId = 0;
@@ -377,8 +383,7 @@
@Override
public void toggleRecentApps() {
- int msg = (mRecentsPanel.getVisibility() == View.VISIBLE)
- ? MSG_CLOSE_RECENTS_PANEL : MSG_OPEN_RECENTS_PANEL;
+ int msg = MSG_TOGGLE_RECENTS_PANEL;
mHandler.removeMessages(msg);
mHandler.sendEmptyMessage(msg);
}
@@ -411,49 +416,15 @@
mHandler.sendEmptyMessage(msg);
}
- @Override
- public void onRecentsPanelVisibilityChanged(boolean visible) {
- }
-
protected abstract WindowManager.LayoutParams getRecentsLayoutParams(
LayoutParams layoutParams);
protected abstract WindowManager.LayoutParams getSearchLayoutParams(
LayoutParams layoutParams);
- protected void updateRecentsPanel(int recentsResId) {
- // Recents Panel
- boolean visible = false;
- ArrayList<TaskDescription> recentTasksList = null;
- boolean firstScreenful = false;
- if (mRecentsPanel != null) {
- visible = mRecentsPanel.isShowing();
- mWindowManager.removeView(mRecentsPanel);
- if (visible) {
- recentTasksList = mRecentsPanel.getRecentTasksList();
- firstScreenful = mRecentsPanel.getFirstScreenful();
- }
- }
-
- // Provide RecentsPanelView with a temporary parent to allow layout params to work.
- LinearLayout tmpRoot = new LinearLayout(mContext);
- mRecentsPanel = (RecentsPanelView) LayoutInflater.from(mContext).inflate(
- recentsResId, tmpRoot, false);
- mRecentsPanel.setRecentTasksLoader(mRecentTasksLoader);
- mRecentTasksLoader.setRecentsPanel(mRecentsPanel);
- mRecentsPanel.setOnTouchListener(
- new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL, mRecentsPanel));
- mRecentsPanel.setVisibility(View.GONE);
-
-
- WindowManager.LayoutParams lp = getRecentsLayoutParams(mRecentsPanel.getLayoutParams());
-
- mWindowManager.addView(mRecentsPanel, lp);
- mRecentsPanel.setBar(this);
- if (visible) {
- mRecentsPanel.show(true, false, recentTasksList, firstScreenful);
- }
-
+ protected RecentTasksLoader getRecentTasksLoader() {
+ final SystemUIApplication app = (SystemUIApplication) ((Service) mContext).getApplication();
+ return app.getRecentTasksLoader();
}
protected void updateSearchPanel() {
@@ -494,28 +465,148 @@
}
}
+ protected abstract View getStatusBarView();
+
+ protected void toggleRecentsActivity() {
+ try {
+ final RecentTasksLoader recentTasksLoader = getRecentTasksLoader();
+ TaskDescription firstTask = recentTasksLoader.getFirstTask();
+
+ Intent intent = new Intent(RecentsActivity.TOGGLE_RECENTS_INTENT);
+ intent.setClassName("com.android.systemui",
+ "com.android.systemui.recent.RecentsActivity");
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+
+ if (firstTask == null) {
+ mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ } else {
+ Bitmap first = firstTask.getThumbnail();
+ final Resources res = mContext.getResources();
+
+ float thumbWidth = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width);
+ float thumbHeight = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height);
+ if (first.getWidth() != thumbWidth || first.getHeight() != thumbHeight) {
+ first = Bitmap.createScaledBitmap(first, (int) thumbWidth, (int) thumbHeight,
+ true);
+ }
+
+ DisplayMetrics dm = new DisplayMetrics();
+ mDisplay.getMetrics(dm);
+ // calculate it here, but consider moving it elsewhere
+ // first, determine which orientation you're in.
+ // todo: move the system_bar layouts to sw600dp ?
+ final Configuration config = res.getConfiguration();
+ int x, y;
+
+ if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
+ float appLabelLeftMargin = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_app_label_left_margin);
+ float appLabelWidth = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_app_label_width);
+ float thumbLeftMargin = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_left_margin);
+ float thumbBgPadding = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_bg_padding);
+
+ float width = appLabelLeftMargin +
+ +appLabelWidth
+ + thumbLeftMargin
+ + thumbWidth
+ + 2 * thumbBgPadding;
+
+ x = (int) ((dm.widthPixels - width) / 2f + appLabelLeftMargin + appLabelWidth
+ + thumbBgPadding + thumbLeftMargin);
+ y = (int) (dm.heightPixels
+ - res.getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height) - thumbBgPadding);
+ } else { // if (config.orientation ==
+ // Configuration.ORIENTATION_LANDSCAPE) {
+ float thumbTopMargin = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_top_margin);
+ float thumbBgPadding = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_bg_padding);
+ float textPadding = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_text_description_padding);
+ float labelTextSize = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_app_label_text_size);
+ Paint p = new Paint();
+ p.setTextSize(labelTextSize);
+ float labelTextHeight = p.getFontMetricsInt().bottom
+ - p.getFontMetricsInt().top;
+ float descriptionTextSize = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_app_description_text_size);
+ p.setTextSize(labelTextSize);
+ float descriptionTextHeight = p.getFontMetricsInt().bottom
+ - p.getFontMetricsInt().top;
+
+ float statusBarHeight = res
+ .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ float recentsItemTopPadding = statusBarHeight;
+
+ float height = thumbTopMargin
+ + thumbHeight
+ + 2 * thumbBgPadding + textPadding + labelTextHeight
+ + recentsItemTopPadding + textPadding + descriptionTextHeight;
+ float recentsItemRightPadding = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_item_padding);
+ float recentsScrollViewRightPadding = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_right_glow_margin);
+ x = (int) (dm.widthPixels - res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width)
+ - thumbBgPadding - recentsItemRightPadding - recentsScrollViewRightPadding);
+ y = (int) ((dm.heightPixels - statusBarHeight - height) / 2f + thumbTopMargin
+ + recentsItemTopPadding + thumbBgPadding + statusBarHeight);
+ }
+
+ ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(
+ getStatusBarView(),
+ first, x, y,
+ null);
+ mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
+ UserHandle.USER_CURRENT));
+ }
+ return;
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "Failed to launch RecentAppsIntent", e);
+ }
+ }
+
protected class H extends Handler {
public void handleMessage(Message m) {
switch (m.what) {
- case MSG_OPEN_RECENTS_PANEL:
- if (DEBUG) Slog.d(TAG, "opening recents panel");
- if (mRecentsPanel != null) {
- mRecentsPanel.show(true, false);
- }
- break;
+ case MSG_TOGGLE_RECENTS_PANEL:
+ if (DEBUG) Slog.d(TAG, "toggle recents panel");
+ toggleRecentsActivity();
+ break;
case MSG_CLOSE_RECENTS_PANEL:
- if (DEBUG) Slog.d(TAG, "closing recents panel");
- if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
- mRecentsPanel.show(false, false);
- }
- break;
+ if (DEBUG) Slog.d(TAG, "closing recents panel");
+ Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
+ intent.setPackage("com.android.systemui");
+ mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ break;
case MSG_PRELOAD_RECENT_APPS:
if (DEBUG) Slog.d(TAG, "preloading recents");
- mRecentsPanel.preloadRecentTasksList();
+ {
+ // TODO:
+ // need to implement this
+ //final RecentsPanelView recentsPanel = getRecentsPanel();
+ //if (recentsPanel != null) {
+ //recentsPanel.preloadRecentTasksList();
+ //}
+ }
break;
case MSG_CANCEL_PRELOAD_RECENT_APPS:
if (DEBUG) Slog.d(TAG, "cancel preloading recents");
- mRecentsPanel.clearRecentTasksList();
+ {
+ // TODO:
+ // need to implement this
+ //final RecentsPanelView recentsPanel = getRecentsPanel();
+ //if (recentsPanel != null) {
+ //recentsPanel.clearRecentTasksList();
+ //}
+ }
break;
case MSG_OPEN_SEARCH_PANEL:
if (DEBUG) Slog.d(TAG, "opening search panel");
@@ -559,8 +650,6 @@
}
protected boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
- int rowHeight =
- mContext.getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
int minHeight =
mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height);
int maxHeight =
@@ -605,7 +694,6 @@
// TODO(cwren) normalize variable names with those in updateNotification
View expandedOneU = null;
View expandedLarge = null;
- Exception exception = null;
try {
expandedOneU = oneU.apply(mContext, adaptive, mOnClickHandler);
if (large != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 2886441..9d2678a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -445,9 +445,6 @@
// if (wimaxRSSI != null) {
// mNetworkController.addWimaxIconView(wimaxRSSI);
// }
- // Recents Panel
- mRecentTasksLoader = new RecentTasksLoader(context);
- updateRecentsPanel();
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -460,6 +457,11 @@
}
@Override
+ protected View getStatusBarView() {
+ return mStatusBarView;
+ }
+
+ @Override
protected WindowManager.LayoutParams getRecentsLayoutParams(LayoutParams layoutParams) {
boolean opaque = false;
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
@@ -507,6 +509,7 @@
return lp;
}
+ /*
protected void updateRecentsPanel() {
super.updateRecentsPanel(R.layout.status_bar_recent_panel);
// Make .03 alpha the minimum so you always see the item a bit-- slightly below
@@ -517,6 +520,7 @@
mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
}
}
+ */
@Override
protected void updateSearchPanel() {
@@ -604,7 +608,7 @@
mNavigationBarView.reorient();
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
- mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
+ mNavigationBarView.getRecentsButton().setOnTouchListener(getRecentTasksLoader());
mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
updateSearchPanel();
}
@@ -785,7 +789,6 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
- updateRecentsPanel();
updateShowSearchHoldoff();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 6d47493..8fe525c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -43,6 +43,9 @@
private static final String TAG = "PhoneStatusBarView";
PhoneStatusBar mBar;
int mScrimColor;
+ float mMinFlingGutter;
+ float mNotificationWidth;
+ boolean mFullWidthNotifications;
PanelView mFadingPanel = null;
PanelView mNotificationPanel, mSettingsPanel;
@@ -58,6 +61,13 @@
public void onAttachedToWindow() {
Resources res = getContext().getResources();
mScrimColor = res.getColor(R.color.notification_panel_scrim_color);
+ mMinFlingGutter = res.getDimension(R.dimen.settings_panel_fling_gutter);
+ mFullWidthNotifications = false;
+ try {
+ mNotificationWidth = res.getDimension(R.dimen.notification_panel_width);
+ } catch (Resources.NotFoundException ex) {
+ mFullWidthNotifications = true;
+ }
}
@Override
@@ -96,9 +106,12 @@
// right 1/3 for quick settings. If you pull the status bar down a second time you'll
// toggle panels no matter where you pull it down.
final float w = (float) getMeasuredWidth();
+ final float gutter = w - mNotificationWidth;
+ final boolean useGutter = !mFullWidthNotifications && gutter > mMinFlingGutter;
+ final float threshold = 1.0f - (gutter / w);
final float f = x / w;
- if (f > 0.67f && mSettingsPanel.getExpandedFraction() != 1.0f
- || mNotificationPanel.getExpandedFraction() == 1.0f) {
+ if ((useGutter && f > threshold && mSettingsPanel.getExpandedFraction() != 1.0f) ||
+ mNotificationPanel.getExpandedFraction() == 1.0f) {
return mSettingsPanel;
}
return mNotificationPanel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 84697e0..8ca3a9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -84,8 +84,7 @@
import java.util.ArrayList;
public class TabletStatusBar extends BaseStatusBar implements
- InputMethodsPanel.OnHardKeyboardEnabledChangeListener,
- RecentsPanelView.OnRecentsPanelVisibilityChangedListener {
+ InputMethodsPanel.OnHardKeyboardEnabledChangeListener {
public static final boolean DEBUG = false;
public static final boolean DEBUG_COMPAT_HELP = false;
public static final String TAG = "TabletStatusBar";
@@ -305,10 +304,6 @@
mWindowManager.addView(mNotificationPanel, lp);
- // Recents Panel
- mRecentTasksLoader = new RecentTasksLoader(context);
- updateRecentsPanel();
-
// Search Panel
mStatusBarView.setBar(this);
mHomeButton.setOnTouchListener(mHomeSearchActionListener);
@@ -360,7 +355,7 @@
mWindowManager.addView(mCompatModePanel, lp);
- mRecentButton.setOnTouchListener(mRecentsPanel);
+ //mRecentButton.setOnTouchListener(mRecentsPanel); //TODO: plumb this
mPile = (NotificationRowLayout)mNotificationPanel.findViewById(R.id.content);
mPile.removeAllViews();
@@ -393,7 +388,6 @@
loadDimens();
mNotificationPanelParams.height = getNotificationPanelHeight();
mWindowManager.updateViewLayout(mNotificationPanel, mNotificationPanelParams);
- mRecentsPanel.updateValuesFromResources();
mShowSearchHoldoff = mContext.getResources().getInteger(
R.integer.config_show_search_delay);
updateSearchPanel();
@@ -445,6 +439,7 @@
}
}
+ @Override
public View getStatusBarView() {
return mStatusBarView;
}
@@ -656,11 +651,6 @@
return lp;
}
- protected void updateRecentsPanel() {
- super.updateRecentsPanel(R.layout.system_bar_recent_panel);
- mRecentsPanel.setStatusBarView(mStatusBarView);
- }
-
@Override
protected void updateSearchPanel() {
super.updateSearchPanel();
@@ -1183,14 +1173,6 @@
}
@Override
- public void onRecentsPanelVisibilityChanged(boolean visible) {
- boolean altBack = visible || mAltBackButtonEnabledForIme;
- mCommandQueue.setNavigationIconHints(
- altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT)
- : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT));
- }
-
- @Override
public void setHardKeyboardStatus(boolean available, boolean enabled) {
if (DEBUG) {
Slog.d(TAG, "Set hard keyboard status: available=" + available
@@ -1241,10 +1223,7 @@
public void onClickRecentButton() {
if (DEBUG) Slog.d(TAG, "clicked recent apps; disabled=" + mDisabled);
if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
- int msg = (mRecentsPanel.getVisibility() == View.VISIBLE)
- ? MSG_CLOSE_RECENTS_PANEL : MSG_OPEN_RECENTS_PANEL;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
+ toggleRecentApps();
}
}
@@ -1523,14 +1502,6 @@
flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
}
}
- if (Intent.ACTION_SCREEN_OFF.equals(action)) {
- // If we're turning the screen off, we want to hide the
- // recents panel with no animation
- // TODO: hide other things, like the notification tray,
- // with no animation as well
- mRecentsPanel.show(false, false);
- flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
- }
animateCollapse(flags);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 5a598dc..6022fd2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -148,6 +148,10 @@
return mView;
}
+ public View getStatusBarView() {
+ return null;
+ }
+
protected int getStatusBarGravity() {
return 0;
}
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 9999adb..96de1b9 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -79,7 +79,7 @@
mDataReceived = (TextView) view.findViewById(R.id.data_received);
mDataRowsHidden = true;
- if (mConfig.user.equals(VpnConfig.LEGACY_VPN)) {
+ if (mConfig.legacy) {
mAlertParams.mIconId = android.R.drawable.ic_dialog_info;
mAlertParams.mTitle = getText(R.string.legacy_title);
} else {
@@ -123,7 +123,11 @@
if (which == DialogInterface.BUTTON_POSITIVE) {
mConfig.configureIntent.send();
} else if (which == DialogInterface.BUTTON_NEUTRAL) {
- mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
+ if (mConfig.legacy) {
+ mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
+ } else {
+ mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
+ }
}
} catch (Exception e) {
Log.e(TAG, "onClick", e);
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 4d05a87..3ea50201 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -39,6 +39,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.EventLog;
@@ -1030,7 +1031,9 @@
mPM.wakeUp(SystemClock.uptimeMillis());
}
mWakeLock.release();
- mContext.sendBroadcast(mUserPresentIntent);
+
+ final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser());
+ mContext.sendBroadcastAsUser(mUserPresentIntent, currentUser);
}
/**
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 6ae16a4..4192a93 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -204,6 +204,11 @@
return mBatteryLevel;
}
+ // true if battery level is below the first warning threshold
+ public final boolean isBatteryLow() {
+ return mBatteryPresent && mBatteryLevel <= mLowBatteryWarningLevel;
+ }
+
void systemReady() {
// check our power situation now that it is safe to display the shutdown dialog.
shutdownIfNoPower();
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index cb6ce4b..3c2ab16 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -31,6 +31,8 @@
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.bluetooth.BluetoothTetheringDataTracker;
import android.content.ContentResolver;
import android.content.Context;
@@ -78,6 +80,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.security.KeyStore;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Slog;
@@ -85,8 +88,10 @@
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.util.Preconditions;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
@@ -115,13 +120,15 @@
* @hide
*/
public class ConnectivityService extends IConnectivityManager.Stub {
+ private static final String TAG = "ConnectivityService";
private static final boolean DBG = true;
private static final boolean VDBG = false;
- private static final String TAG = "ConnectivityService";
private static final boolean LOGD_RULES = false;
+ // TODO: create better separation between radio types and network types
+
// how long to wait before switching back to a radio's default network
private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
// system property that can override the above value
@@ -135,7 +142,10 @@
private Tethering mTethering;
private boolean mTetheringConfigValid = false;
+ private final KeyStore mKeyStore;
+
private Vpn mVpn;
+ private VpnCallback mVpnCallback = new VpnCallback();
/** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
private Object mRulesLock = new Object();
@@ -328,7 +338,7 @@
this(context, netd, statsService, policyManager, null);
}
- public ConnectivityService(Context context, INetworkManagementService netd,
+ public ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
NetworkFactory netFactory) {
if (DBG) log("ConnectivityService starting up");
@@ -366,8 +376,9 @@
}
mContext = checkNotNull(context, "missing Context");
- mNetd = checkNotNull(netd, "missing INetworkManagementService");
+ mNetd = checkNotNull(netManager, "missing INetworkManagementService");
mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
+ mKeyStore = KeyStore.getInstance();
try {
mPolicyManager.registerListener(mPolicyListener);
@@ -506,11 +517,11 @@
mTethering.getTetherableBluetoothRegexs().length != 0) &&
mTethering.getUpstreamIfaceTypes().length != 0);
- mVpn = new Vpn(mContext, new VpnCallback());
+ mVpn = new Vpn(mContext, mVpnCallback, mNetd);
+ mVpn.startMonitoring(mContext, mTrackerHandler);
try {
mNetd.registerObserver(mTethering);
- mNetd.registerObserver(mVpn);
mNetd.registerObserver(mDataActivityObserver);
} catch (RemoteException e) {
loge("Error registering observer :" + e);
@@ -2238,9 +2249,9 @@
*/
public void updateNetworkSettings(NetworkStateTracker nt) {
String key = nt.getTcpBufferSizesPropName();
- String bufferSizes = SystemProperties.get(key);
+ String bufferSizes = key == null ? null : SystemProperties.get(key);
- if (bufferSizes.length() == 0) {
+ if (TextUtils.isEmpty(bufferSizes)) {
if (VDBG) log(key + " not found in system properties. Using defaults");
// Setting to default values so we won't be stuck to previous values
@@ -3121,14 +3132,16 @@
}
/**
- * Start legacy VPN and return an intent to VpnDialogs. This method is
- * used by VpnSettings and not available in ConnectivityManager.
- * Permissions are checked in Vpn class.
- * @hide
+ * Start legacy VPN, controlling native daemons as needed. Creates a
+ * secondary thread to perform connection work, returning quickly.
*/
@Override
- public void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
- mVpn.startLegacyVpn(config, racoon, mtpd);
+ public void startLegacyVpn(VpnProfile profile) {
+ final LinkProperties egress = getActiveLinkProperties();
+ if (egress == null) {
+ throw new IllegalStateException("Missing active network connection");
+ }
+ mVpn.startLegacyVpn(profile, mKeyStore, egress);
}
/**
@@ -3153,10 +3166,14 @@
* be done whenever a better abstraction is developed.
*/
public class VpnCallback {
-
private VpnCallback() {
}
+ public void onStateChanged(NetworkInfo info) {
+ // TODO: if connected, release delayed broadcast
+ // TODO: if disconnected, consider kicking off reconnect
+ }
+
public void override(List<String> dnsServers, List<String> searchDomains) {
if (dnsServers == null) {
restore();
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index ef09b01..2bed957 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -17,6 +17,7 @@
package com.android.server;
import static android.provider.Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK;
+import static android.provider.Settings.Secure.SCREENSAVER_ENABLED;
import android.content.ContentResolver;
import android.content.Context;
@@ -51,7 +52,8 @@
private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
- private static final int DEFAULT_DOCK = 1;
+ private static final int DEFAULT_SCREENSAVER_ENABLED = 1;
+ private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
private static final int MSG_DOCK_STATE_CHANGED = 0;
@@ -214,7 +216,7 @@
Slog.w(TAG, "Unable to awaken!", e);
}
} else {
- if (isScreenSaverActivatedOnDock(mContext)) {
+ if (isScreenSaverEnabled(mContext) && isScreenSaverActivatedOnDock(mContext)) {
try {
mgr.dream();
} catch (RemoteException e) {
@@ -229,9 +231,14 @@
}
}
+ private static boolean isScreenSaverEnabled(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
+ SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED) != 0;
+ }
+
private static boolean isScreenSaverActivatedOnDock(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
- SCREENSAVER_ACTIVATE_ON_DOCK, DEFAULT_DOCK) != 0;
+ SCREENSAVER_ACTIVATE_ON_DOCK, DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK) != 0;
}
private final Handler mHandler = new Handler(Looper.myLooper(), null, true) {
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 39e5186..fbd45a0 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -35,6 +35,7 @@
import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
+import android.bluetooth.BluetoothTetheringDataTracker;
import android.content.Context;
import android.net.INetworkManagementEventObserver;
import android.net.InterfaceConfiguration;
@@ -55,6 +56,7 @@
import android.util.SparseBooleanArray;
import com.android.internal.net.NetworkStatsFactory;
+import com.android.internal.util.Preconditions;
import com.android.server.NativeDaemonConnector.Command;
import com.google.android.collect.Maps;
@@ -78,7 +80,6 @@
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.concurrent.CountDownLatch;
-import android.bluetooth.BluetoothTetheringDataTracker;
/**
* @hide
@@ -92,6 +93,9 @@
private static final String ADD = "add";
private static final String REMOVE = "remove";
+ private static final String ALLOW = "allow";
+ private static final String DENY = "deny";
+
private static final String DEFAULT = "default";
private static final String SECONDARY = "secondary";
@@ -169,6 +173,7 @@
private HashMap<String, IdleTimerParams> mActiveIdleTimers = Maps.newHashMap();
private volatile boolean mBandwidthControlEnabled;
+ private volatile boolean mFirewallEnabled;
/**
* Constructs a new NetworkManagementService instance
@@ -363,6 +368,9 @@
}
}
}
+
+ // TODO: Push any existing firewall state
+ setFirewallEnabled(mFirewallEnabled);
}
//
@@ -1425,7 +1433,72 @@
}
}
- /** {@inheritDoc} */
+ @Override
+ public void setFirewallEnabled(boolean enabled) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ try {
+ mConnector.execute("firewall", enabled ? "enable" : "disable");
+ mFirewallEnabled = enabled;
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public boolean isFirewallEnabled() {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ return mFirewallEnabled;
+ }
+
+ @Override
+ public void setFirewallInterfaceRule(String iface, boolean allow) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Preconditions.checkState(mFirewallEnabled);
+ final String rule = allow ? ALLOW : DENY;
+ try {
+ mConnector.execute("firewall", "set_interface_rule", iface, rule);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void setFirewallEgressSourceRule(String addr, boolean allow) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Preconditions.checkState(mFirewallEnabled);
+ final String rule = allow ? ALLOW : DENY;
+ try {
+ mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Preconditions.checkState(mFirewallEnabled);
+ final String rule = allow ? ALLOW : DENY;
+ try {
+ mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void setFirewallUidRule(int uid, boolean allow) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Preconditions.checkState(mFirewallEnabled);
+ final String rule = allow ? ALLOW : DENY;
+ try {
+ mConnector.execute("firewall", "set_uid_rule", uid, rule);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
public void monitor() {
if (mConnector != null) {
mConnector.monitor();
@@ -1456,5 +1529,7 @@
}
pw.println("]");
}
+
+ pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
}
}
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index 1232846..d96bd0d 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -16,8 +16,11 @@
package com.android.server.connectivity;
+import static android.Manifest.permission.BIND_VPN_SERVICE;
+
import android.app.Notification;
import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -28,27 +31,43 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.net.BaseNetworkStateTracker;
+import android.net.ConnectivityManager;
import android.net.INetworkManagementEventObserver;
+import android.net.LinkProperties;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
+import android.net.NetworkInfo;
+import android.net.RouteInfo;
+import android.net.NetworkInfo.DetailedState;
import android.os.Binder;
import android.os.FileUtils;
import android.os.IBinder;
+import android.os.INetworkManagementService;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemService;
+import android.security.Credentials;
+import android.security.KeyStore;
import android.util.Log;
+import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
+import com.android.internal.util.Preconditions;
import com.android.server.ConnectivityService.VpnCallback;
+import com.android.server.net.BaseNetworkObserver;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.Inet4Address;
+import java.net.InetAddress;
import java.nio.charset.Charsets;
import java.util.Arrays;
@@ -57,24 +76,63 @@
/**
* @hide
*/
-public class Vpn extends INetworkManagementEventObserver.Stub {
+public class Vpn extends BaseNetworkStateTracker {
+ private static final String TAG = "Vpn";
+ private static final boolean LOGD = true;
+
+ // TODO: create separate trackers for each unique VPN to support
+ // automated reconnection
- private final static String TAG = "Vpn";
-
- private final static String BIND_VPN_SERVICE =
- android.Manifest.permission.BIND_VPN_SERVICE;
-
- private final Context mContext;
private final VpnCallback mCallback;
private String mPackage = VpnConfig.LEGACY_VPN;
private String mInterface;
private Connection mConnection;
private LegacyVpnRunner mLegacyVpnRunner;
+ private PendingIntent mStatusIntent;
- public Vpn(Context context, VpnCallback callback) {
+ public Vpn(Context context, VpnCallback callback, INetworkManagementService netService) {
+ // TODO: create dedicated TYPE_VPN network type
+ super(ConnectivityManager.TYPE_DUMMY);
mContext = context;
mCallback = callback;
+
+ try {
+ netService.registerObserver(mObserver);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Problem registering observer", e);
+ }
+ }
+
+ @Override
+ protected void startMonitoringInternal() {
+ // Ignored; events are sent through callbacks for now
+ }
+
+ @Override
+ public boolean teardown() {
+ // TODO: finish migration to unique tracker for each VPN
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean reconnect() {
+ // TODO: finish migration to unique tracker for each VPN
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getTcpBufferSizesPropName() {
+ return PROP_TCP_BUFFER_UNKNOWN;
+ }
+
+ /**
+ * Update current state, dispaching event to listeners.
+ */
+ private void updateState(DetailedState detailedState, String reason) {
+ if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
+ mNetworkInfo.setDetailedState(detailedState, reason, null);
+ mCallback.onStateChanged(new NetworkInfo(mNetworkInfo));
}
/**
@@ -113,10 +171,13 @@
// Reset the interface and hide the notification.
if (mInterface != null) {
jniReset(mInterface);
- long identity = Binder.clearCallingIdentity();
- mCallback.restore();
- hideNotification();
- Binder.restoreCallingIdentity(identity);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mCallback.restore();
+ hideNotification();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
mInterface = null;
}
@@ -137,6 +198,7 @@
Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
mPackage = newPackage;
+ updateState(DetailedState.IDLE, "prepare");
return true;
}
@@ -145,7 +207,7 @@
* interface. The socket is NOT closed by this method.
*
* @param socket The socket to be bound.
- * @param name The name of the interface.
+ * @param interfaze The name of the interface.
*/
public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
PackageManager pm = mContext.getPackageManager();
@@ -209,6 +271,7 @@
// Configure the interface. Abort if any of these steps fails.
ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
try {
+ updateState(DetailedState.CONNECTING, "establish");
String interfaze = jniGetName(tun.getFd());
if (jniSetAddresses(interfaze, config.addresses) < 1) {
throw new IllegalArgumentException("At least one address must be specified");
@@ -229,6 +292,7 @@
mConnection = connection;
mInterface = interfaze;
} catch (RuntimeException e) {
+ updateState(DetailedState.FAILED, "establish");
IoUtils.closeQuietly(tun);
throw e;
}
@@ -239,57 +303,61 @@
config.interfaze = mInterface;
// Override DNS servers and show the notification.
- long identity = Binder.clearCallingIdentity();
- mCallback.override(config.dnsServers, config.searchDomains);
- showNotification(config, label, bitmap);
- Binder.restoreCallingIdentity(identity);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mCallback.override(config.dnsServers, config.searchDomains);
+ showNotification(config, label, bitmap);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ // TODO: ensure that contract class eventually marks as connected
+ updateState(DetailedState.AUTHENTICATING, "establish");
return tun;
}
- // INetworkManagementEventObserver.Stub
- @Override
- public void interfaceAdded(String interfaze) {
- }
-
- // INetworkManagementEventObserver.Stub
- @Override
- public synchronized void interfaceStatusChanged(String interfaze, boolean up) {
- if (!up && mLegacyVpnRunner != null) {
- mLegacyVpnRunner.check(interfaze);
+ @Deprecated
+ public synchronized void interfaceStatusChanged(String iface, boolean up) {
+ try {
+ mObserver.interfaceStatusChanged(iface, up);
+ } catch (RemoteException e) {
+ // ignored; target is local
}
}
- // INetworkManagementEventObserver.Stub
- @Override
- public void interfaceLinkStateChanged(String interfaze, boolean up) {
- }
-
- // INetworkManagementEventObserver.Stub
- @Override
- public synchronized void interfaceRemoved(String interfaze) {
- if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
- long identity = Binder.clearCallingIdentity();
- mCallback.restore();
- hideNotification();
- Binder.restoreCallingIdentity(identity);
- mInterface = null;
- if (mConnection != null) {
- mContext.unbindService(mConnection);
- mConnection = null;
- } else if (mLegacyVpnRunner != null) {
- mLegacyVpnRunner.exit();
- mLegacyVpnRunner = null;
+ private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() {
+ @Override
+ public void interfaceStatusChanged(String interfaze, boolean up) {
+ synchronized (Vpn.this) {
+ if (!up && mLegacyVpnRunner != null) {
+ mLegacyVpnRunner.check(interfaze);
+ }
}
}
- }
- // INetworkManagementEventObserver.Stub
- @Override
- public void limitReached(String limit, String interfaze) {
- }
-
- public void interfaceClassDataActivityChanged(String label, boolean active) {
- }
+ @Override
+ public void interfaceRemoved(String interfaze) {
+ synchronized (Vpn.this) {
+ if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mCallback.restore();
+ hideNotification();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ mInterface = null;
+ if (mConnection != null) {
+ mContext.unbindService(mConnection);
+ mConnection = null;
+ updateState(DetailedState.DISCONNECTED, "interfaceRemoved");
+ } else if (mLegacyVpnRunner != null) {
+ mLegacyVpnRunner.exit();
+ mLegacyVpnRunner = null;
+ }
+ }
+ }
+ }
+ };
private void enforceControlPermission() {
// System user is allowed to control VPN.
@@ -326,6 +394,8 @@
}
private void showNotification(VpnConfig config, String label, Bitmap icon) {
+ mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext, config);
+
NotificationManager nm = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -341,15 +411,17 @@
.setLargeIcon(icon)
.setContentTitle(title)
.setContentText(text)
- .setContentIntent(VpnConfig.getIntentForStatusPanel(mContext, config))
+ .setContentIntent(mStatusIntent)
.setDefaults(0)
.setOngoing(true)
- .getNotification();
+ .build();
nm.notify(R.drawable.vpn_connected, notification);
}
}
private void hideNotification() {
+ mStatusIntent = null;
+
NotificationManager nm = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -366,31 +438,164 @@
private native int jniCheck(String interfaze);
private native void jniProtect(int socket, String interfaze);
+ private static String findLegacyVpnGateway(LinkProperties prop) {
+ for (RouteInfo route : prop.getRoutes()) {
+ // Currently legacy VPN only works on IPv4.
+ if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) {
+ return route.getGateway().getHostAddress();
+ }
+ }
+
+ throw new IllegalStateException("Unable to find suitable gateway");
+ }
+
/**
- * Start legacy VPN. This method stops the daemons and restart them
- * if arguments are not null. Heavy things are offloaded to another
- * thread, so callers will not be blocked for a long time.
- *
- * @param config The parameters to configure the network.
- * @param raoocn The arguments to be passed to racoon.
- * @param mtpd The arguments to be passed to mtpd.
+ * Start legacy VPN, controlling native daemons as needed. Creates a
+ * secondary thread to perform connection work, returning quickly.
*/
- public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
+ public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
+ if (keyStore.state() != KeyStore.State.UNLOCKED) {
+ throw new IllegalStateException("KeyStore isn't unlocked");
+ }
+
+ final String iface = egress.getInterfaceName();
+ final String gateway = findLegacyVpnGateway(egress);
+
+ // Load certificates.
+ String privateKey = "";
+ String userCert = "";
+ String caCert = "";
+ String serverCert = "";
+ if (!profile.ipsecUserCert.isEmpty()) {
+ privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert;
+ byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert);
+ userCert = (value == null) ? null : new String(value, Charsets.UTF_8);
+ }
+ if (!profile.ipsecCaCert.isEmpty()) {
+ byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert);
+ caCert = (value == null) ? null : new String(value, Charsets.UTF_8);
+ }
+ if (!profile.ipsecServerCert.isEmpty()) {
+ byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert);
+ serverCert = (value == null) ? null : new String(value, Charsets.UTF_8);
+ }
+ if (privateKey == null || userCert == null || caCert == null || serverCert == null) {
+ throw new IllegalStateException("Cannot load credentials");
+ }
+
+ // Prepare arguments for racoon.
+ String[] racoon = null;
+ switch (profile.type) {
+ case VpnProfile.TYPE_L2TP_IPSEC_PSK:
+ racoon = new String[] {
+ iface, profile.server, "udppsk", profile.ipsecIdentifier,
+ profile.ipsecSecret, "1701",
+ };
+ break;
+ case VpnProfile.TYPE_L2TP_IPSEC_RSA:
+ racoon = new String[] {
+ iface, profile.server, "udprsa", privateKey, userCert,
+ caCert, serverCert, "1701",
+ };
+ break;
+ case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
+ racoon = new String[] {
+ iface, profile.server, "xauthpsk", profile.ipsecIdentifier,
+ profile.ipsecSecret, profile.username, profile.password, "", gateway,
+ };
+ break;
+ case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
+ racoon = new String[] {
+ iface, profile.server, "xauthrsa", privateKey, userCert,
+ caCert, serverCert, profile.username, profile.password, "", gateway,
+ };
+ break;
+ case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
+ racoon = new String[] {
+ iface, profile.server, "hybridrsa",
+ caCert, serverCert, profile.username, profile.password, "", gateway,
+ };
+ break;
+ }
+
+ // Prepare arguments for mtpd.
+ String[] mtpd = null;
+ switch (profile.type) {
+ case VpnProfile.TYPE_PPTP:
+ mtpd = new String[] {
+ iface, "pptp", profile.server, "1723",
+ "name", profile.username, "password", profile.password,
+ "linkname", "vpn", "refuse-eap", "nodefaultroute",
+ "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
+ (profile.mppe ? "+mppe" : "nomppe"),
+ };
+ break;
+ case VpnProfile.TYPE_L2TP_IPSEC_PSK:
+ case VpnProfile.TYPE_L2TP_IPSEC_RSA:
+ mtpd = new String[] {
+ iface, "l2tp", profile.server, "1701", profile.l2tpSecret,
+ "name", profile.username, "password", profile.password,
+ "linkname", "vpn", "refuse-eap", "nodefaultroute",
+ "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
+ };
+ break;
+ }
+
+ VpnConfig config = new VpnConfig();
+ config.legacy = true;
+ config.user = profile.key;
+ config.interfaze = iface;
+ config.session = profile.name;
+ config.routes = profile.routes;
+ if (!profile.dnsServers.isEmpty()) {
+ config.dnsServers = Arrays.asList(profile.dnsServers.split(" +"));
+ }
+ if (!profile.searchDomains.isEmpty()) {
+ config.searchDomains = Arrays.asList(profile.searchDomains.split(" +"));
+ }
+
+ startLegacyVpn(config, racoon, mtpd);
+ }
+
+ private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
+ stopLegacyVpn();
+
// Prepare for the new request. This also checks the caller.
prepare(null, VpnConfig.LEGACY_VPN);
+ updateState(DetailedState.CONNECTING, "startLegacyVpn");
// Start a new LegacyVpnRunner and we are done!
mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd);
mLegacyVpnRunner.start();
}
+ public synchronized void stopLegacyVpn() {
+ if (mLegacyVpnRunner != null) {
+ mLegacyVpnRunner.exit();
+ mLegacyVpnRunner = null;
+
+ synchronized (LegacyVpnRunner.TAG) {
+ // wait for old thread to completely finish before spinning up
+ // new instance, otherwise state updates can be out of order.
+ }
+ }
+ }
+
/**
* Return the information of the current ongoing legacy VPN.
*/
public synchronized LegacyVpnInfo getLegacyVpnInfo() {
// Check if the caller is authorized.
enforceControlPermission();
- return (mLegacyVpnRunner == null) ? null : mLegacyVpnRunner.getInfo();
+ if (mLegacyVpnRunner == null) return null;
+
+ final LegacyVpnInfo info = new LegacyVpnInfo();
+ info.key = mLegacyVpnRunner.mConfig.user;
+ info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo);
+ if (mNetworkInfo.isConnected()) {
+ info.intent = mStatusIntent;
+ }
+ return info;
}
/**
@@ -407,8 +612,6 @@
private final String[] mDaemons;
private final String[][] mArguments;
private final LocalSocket[] mSockets;
- private final String mOuterInterface;
- private final LegacyVpnInfo mInfo;
private long mTimer = -1;
@@ -416,20 +619,13 @@
super(TAG);
mConfig = config;
mDaemons = new String[] {"racoon", "mtpd"};
+ // TODO: clear arguments from memory once launched
mArguments = new String[][] {racoon, mtpd};
mSockets = new LocalSocket[mDaemons.length];
- mInfo = new LegacyVpnInfo();
-
- // This is the interface which VPN is running on.
- mOuterInterface = mConfig.interfaze;
-
- // Legacy VPN is not a real package, so we use it to carry the key.
- mInfo.key = mConfig.user;
- mConfig.user = VpnConfig.LEGACY_VPN;
}
public void check(String interfaze) {
- if (interfaze.equals(mOuterInterface)) {
+ if (interfaze.equals(mConfig.interfaze)) {
Log.i(TAG, "Legacy VPN is going down with " + interfaze);
exit();
}
@@ -441,15 +637,7 @@
for (LocalSocket socket : mSockets) {
IoUtils.closeQuietly(socket);
}
- }
-
- public LegacyVpnInfo getInfo() {
- // Update the info when VPN is disconnected.
- if (mInfo.state == LegacyVpnInfo.STATE_CONNECTED && mInterface == null) {
- mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED;
- mInfo.intent = null;
- }
- return mInfo;
+ updateState(DetailedState.DISCONNECTED, "exit");
}
@Override
@@ -459,6 +647,7 @@
synchronized (TAG) {
Log.v(TAG, "Executing");
execute();
+ monitorDaemons();
}
}
@@ -470,17 +659,17 @@
} else if (now - mTimer <= 60000) {
Thread.sleep(yield ? 200 : 1);
} else {
- mInfo.state = LegacyVpnInfo.STATE_TIMEOUT;
+ updateState(DetailedState.FAILED, "checkpoint");
throw new IllegalStateException("Time is up");
}
}
private void execute() {
// Catch all exceptions so we can clean up few things.
+ boolean initFinished = false;
try {
// Initialize the timer.
checkpoint(false);
- mInfo.state = LegacyVpnInfo.STATE_INITIALIZING;
// Wait for the daemons to stop.
for (String daemon : mDaemons) {
@@ -496,6 +685,7 @@
throw new IllegalStateException("Cannot delete the state");
}
new File("/data/misc/vpn/abort").delete();
+ initFinished = true;
// Check if we need to restart any of the daemons.
boolean restart = false;
@@ -503,10 +693,10 @@
restart = restart || (arguments != null);
}
if (!restart) {
- mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED;
+ updateState(DetailedState.DISCONNECTED, "execute");
return;
}
- mInfo.state = LegacyVpnInfo.STATE_CONNECTING;
+ updateState(DetailedState.CONNECTING, "execute");
// Start the daemon with arguments.
for (int i = 0; i < mDaemons.length; ++i) {
@@ -633,26 +823,53 @@
showNotification(mConfig, null, null);
Log.i(TAG, "Connected!");
- mInfo.state = LegacyVpnInfo.STATE_CONNECTED;
- mInfo.intent = VpnConfig.getIntentForStatusPanel(mContext, null);
+ updateState(DetailedState.CONNECTED, "execute");
}
} catch (Exception e) {
Log.i(TAG, "Aborting", e);
exit();
} finally {
// Kill the daemons if they fail to stop.
- if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING) {
+ if (!initFinished) {
for (String daemon : mDaemons) {
SystemService.stop(daemon);
}
}
// Do not leave an unstable state.
- if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING ||
- mInfo.state == LegacyVpnInfo.STATE_CONNECTING) {
- mInfo.state = LegacyVpnInfo.STATE_FAILED;
+ if (!initFinished || mNetworkInfo.getDetailedState() == DetailedState.CONNECTING) {
+ updateState(DetailedState.FAILED, "execute");
}
}
}
+
+ /**
+ * Monitor the daemons we started, moving to disconnected state if the
+ * underlying services fail.
+ */
+ private void monitorDaemons() {
+ if (!mNetworkInfo.isConnected()) {
+ return;
+ }
+
+ try {
+ while (true) {
+ Thread.sleep(2000);
+ for (int i = 0; i < mDaemons.length; i++) {
+ if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) {
+ return;
+ }
+ }
+ }
+ } catch (InterruptedException e) {
+ Log.d(TAG, "interrupted during monitorDaemons(); stopping services");
+ } finally {
+ for (String daemon : mDaemons) {
+ SystemService.stop(daemon);
+ }
+
+ updateState(DetailedState.DISCONNECTED, "babysit");
+ }
+ }
}
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index a76f854..4252b90 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -780,7 +780,7 @@
final int verificationId = msg.arg1;
final PackageVerificationState state = mPendingVerification.get(verificationId);
- if (state != null) {
+ if ((state != null) && !state.timeoutExtended()) {
final InstallArgs args = state.getInstallArgs();
Slog.i(TAG, "Verification timed out for " + args.packageURI.toString());
mPendingVerification.remove(verificationId);
@@ -788,20 +788,20 @@
int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
if (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW) {
- Slog.i(TAG, "Continuing with installation of " + args.packageURI.toString());
- state.setVerifierResponse(Binder.getCallingUid(), PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
- try {
- ret = args.copyApk(mContainerService, true);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not contact the ContainerService");
- }
+ Slog.i(TAG, "Continuing with installation of "
+ + args.packageURI.toString());
+ state.setVerifierResponse(Binder.getCallingUid(),
+ PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
+ try {
+ ret = args.copyApk(mContainerService, true);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not contact the ContainerService");
+ }
}
processPendingInstall(args, ret);
-
mHandler.sendEmptyMessage(MCS_UNBIND);
}
-
break;
}
case PACKAGE_VERIFIED: {
@@ -5393,6 +5393,32 @@
mHandler.sendMessage(msg);
}
+ @Override
+ public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
+ long millisecondsToDelay) {
+ final PackageVerificationState state = mPendingVerification.get(id);
+ final PackageVerificationResponse response = new PackageVerificationResponse(
+ verificationCodeAtTimeout, Binder.getCallingUid());
+
+ if ((millisecondsToDelay > PackageManager.MAXIMUM_VERIFICATION_TIMEOUT)
+ || (millisecondsToDelay < 0)) {
+ throw new IllegalArgumentException("millisecondsToDelay is out of bounds.");
+ }
+ if ((verificationCodeAtTimeout != PackageManager.VERIFICATION_ALLOW)
+ || (verificationCodeAtTimeout != PackageManager.VERIFICATION_REJECT)) {
+ throw new IllegalArgumentException("verificationCodeAtTimeout is unknown.");
+ }
+
+ if ((state != null) && !state.timeoutExtended()) {
+ state.extendTimeout();
+
+ final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED);
+ msg.arg1 = id;
+ msg.obj = response;
+ mHandler.sendMessageDelayed(msg, millisecondsToDelay);
+ }
+ }
+
private ComponentName matchComponentForVerifier(String packageName,
List<ResolveInfo> receivers) {
ActivityInfo targetReceiver = null;
diff --git a/services/java/com/android/server/pm/PackageVerificationState.java b/services/java/com/android/server/pm/PackageVerificationState.java
index e5b89c1..3214e88 100644
--- a/services/java/com/android/server/pm/PackageVerificationState.java
+++ b/services/java/com/android/server/pm/PackageVerificationState.java
@@ -43,6 +43,8 @@
private boolean mRequiredVerificationPassed;
+ private boolean mExtendedTimeout;
+
/**
* Create a new package verification state where {@code requiredVerifierUid}
* is the user ID for the package that must reply affirmative before things
@@ -55,6 +57,7 @@
mRequiredVerifierUid = requiredVerifierUid;
mArgs = args;
mSufficientVerifierUids = new SparseBooleanArray();
+ mExtendedTimeout = false;
}
public InstallArgs getInstallArgs() {
@@ -146,4 +149,22 @@
return true;
}
+
+ /**
+ * Extend the timeout for this Package to be verified.
+ */
+ public void extendTimeout() {
+ if (!mExtendedTimeout) {
+ mExtendedTimeout = true;
+ }
+ }
+
+ /**
+ * Returns whether the timeout was extended for verification.
+ *
+ * @return {@code true} if a timeout was already extended.
+ */
+ public boolean timeoutExtended() {
+ return mExtendedTimeout;
+ }
}
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index d3a3ffb..9f2b247 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -227,6 +227,9 @@
// True if dreams are enabled by the user.
private boolean mDreamsEnabledSetting;
+ // True if dreams should be activated on sleep.
+ private boolean mDreamsActivateOnSleepSetting;
+
// The screen off timeout setting value in milliseconds.
private int mScreenOffTimeoutSetting;
@@ -356,6 +359,8 @@
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ENABLED), false, mSettingsObserver);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP), false, mSettingsObserver);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_OFF_TIMEOUT), false, mSettingsObserver);
resolver.registerContentObserver(Settings.System.getUriFor(
@@ -387,6 +392,8 @@
mDreamsEnabledSetting = (Settings.Secure.getInt(resolver,
Settings.Secure.SCREENSAVER_ENABLED, 0) != 0);
+ mDreamsActivateOnSleepSetting = (Settings.Secure.getInt(resolver,
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 0) != 0);
mScreenOffTimeoutSetting = Settings.System.getInt(resolver,
Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT);
mStayOnWhilePluggedInSetting = Settings.System.getInt(resolver,
@@ -1130,7 +1137,7 @@
*/
private void updateDreamLocked(int dirty) {
if ((dirty & (DIRTY_WAKEFULNESS | DIRTY_SETTINGS
- | DIRTY_IS_POWERED | DIRTY_STAY_ON)) != 0) {
+ | DIRTY_IS_POWERED | DIRTY_STAY_ON | DIRTY_BATTERY_STATE)) != 0) {
scheduleSandmanLocked();
}
}
@@ -1156,13 +1163,13 @@
boolean startDreaming = false;
synchronized (mLock) {
mSandmanScheduled = false;
-
+ boolean canDream = canDreamLocked();
if (DEBUG_SPEW) {
- Log.d(TAG, "handleSandman: canDream=" + canDreamLocked()
+ Log.d(TAG, "handleSandman: canDream=" + canDream
+ ", mWakefulness=" + wakefulnessToString(mWakefulness));
}
- if (canDreamLocked() && mWakefulness == WAKEFULNESS_NAPPING) {
+ if (canDream && mWakefulness == WAKEFULNESS_NAPPING) {
startDreaming = true;
}
}
@@ -1246,7 +1253,11 @@
* assuming there has been no recent user activity and no wake locks are held.
*/
private boolean canDreamLocked() {
- return mIsPowered && mDreamsSupportedConfig && mDreamsEnabledSetting;
+ return mIsPowered
+ && mDreamsSupportedConfig
+ && mDreamsEnabledSetting
+ && mDreamsActivateOnSleepSetting
+ && !mBatteryService.isBatteryLow();
}
/**
@@ -1822,6 +1833,7 @@
pw.println("Settings and Configuration:");
pw.println(" mDreamsSupportedConfig=" + mDreamsSupportedConfig);
pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting);
+ pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
pw.println(" mScreenOffTimeoutSetting=" + mScreenOffTimeoutSetting);
pw.println(" mMaximumScreenOffTimeoutFromDeviceAdmin="
+ mMaximumScreenOffTimeoutFromDeviceAdmin + " (enforced="
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java
index b98ab00..64d2602 100644
--- a/services/java/com/android/server/wm/BlackFrame.java
+++ b/services/java/com/android/server/wm/BlackFrame.java
@@ -22,7 +22,6 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.util.Slog;
-import android.view.Display;
import android.view.Surface;
import android.view.SurfaceSession;
@@ -36,7 +35,7 @@
final int layer;
final Surface surface;
- BlackSurface(SurfaceSession session, int layer, int l, int t, int r, int b)
+ BlackSurface(SurfaceSession session, int layer, int l, int t, int r, int b, int layerStack)
throws Surface.OutOfResourcesException {
left = l;
top = t;
@@ -45,10 +44,10 @@
int h = b-t;
if (WindowManagerService.DEBUG_SURFACE_TRACE) {
surface = new WindowStateAnimator.SurfaceTrace(session, 0, "BlackSurface("
- + l + ", " + t + ")", Display.DEFAULT_DISPLAY,
+ + l + ", " + t + ")", layerStack,
w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM);
} else {
- surface = new Surface(session, 0, "BlackSurface", Display.DEFAULT_DISPLAY,
+ surface = new Surface(session, 0, "BlackSurface", layerStack,
w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM);
}
surface.setAlpha(1);
@@ -104,7 +103,7 @@
}
public BlackFrame(SurfaceSession session, Rect outer, Rect inner,
- int layer) throws Surface.OutOfResourcesException {
+ int layer, final int layerStack) throws Surface.OutOfResourcesException {
boolean success = false;
mOuterRect = new Rect(outer);
@@ -112,19 +111,19 @@
try {
if (outer.top < inner.top) {
mBlackSurfaces[0] = new BlackSurface(session, layer,
- outer.left, outer.top, inner.right, inner.top);
+ outer.left, outer.top, inner.right, inner.top, layerStack);
}
if (outer.left < inner.left) {
mBlackSurfaces[1] = new BlackSurface(session, layer,
- outer.left, inner.top, inner.left, outer.bottom);
+ outer.left, inner.top, inner.left, outer.bottom, layerStack);
}
if (outer.bottom > inner.bottom) {
mBlackSurfaces[2] = new BlackSurface(session, layer,
- inner.left, inner.bottom, outer.right, outer.bottom);
+ inner.left, inner.bottom, outer.right, outer.bottom, layerStack);
}
if (outer.right > inner.right) {
mBlackSurfaces[3] = new BlackSurface(session, layer,
- inner.right, outer.top, outer.right, inner.bottom);
+ inner.right, outer.top, outer.right, inner.bottom, layerStack);
}
success = true;
} finally {
diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java
index 7e8b0ec..81daac6 100644
--- a/services/java/com/android/server/wm/DimAnimator.java
+++ b/services/java/com/android/server/wm/DimAnimator.java
@@ -39,18 +39,18 @@
int mLastDimWidth, mLastDimHeight;
- DimAnimator (SurfaceSession session, final int displayId) {
+ DimAnimator (SurfaceSession session, final int layerStack) {
if (mDimSurface == null) {
try {
if (WindowManagerService.DEBUG_SURFACE_TRACE) {
mDimSurface = new WindowStateAnimator.SurfaceTrace(session, 0,
"DimAnimator",
- displayId, 16, 16, PixelFormat.OPAQUE,
+ layerStack, 16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM);
} else {
mDimSurface = new Surface(session, 0,
"DimAnimator",
- displayId, 16, 16, PixelFormat.OPAQUE,
+ layerStack, 16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM);
}
if (WindowManagerService.SHOW_TRANSACTIONS ||
diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java
index 0e5d5563..4ab8ce1 100644
--- a/services/java/com/android/server/wm/DimSurface.java
+++ b/services/java/com/android/server/wm/DimSurface.java
@@ -30,18 +30,18 @@
int mLayer = -1;
int mLastDimWidth, mLastDimHeight;
- DimSurface(SurfaceSession session, final int displayId) {
+ DimSurface(SurfaceSession session, final int layerStack) {
if (mDimSurface == null) {
try {
if (WindowManagerService.DEBUG_SURFACE_TRACE) {
mDimSurface = new WindowStateAnimator.SurfaceTrace(session, 0,
"DimSurface",
- displayId, 16, 16, PixelFormat.OPAQUE,
+ layerStack, 16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM);
} else {
mDimSurface = new Surface(session, 0,
"DimSurface",
- displayId, 16, 16, PixelFormat.OPAQUE,
+ layerStack, 16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM);
}
if (WindowManagerService.SHOW_TRANSACTIONS ||
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index a8854cf..6e5bbcb 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -16,10 +16,9 @@
package com.android.server.wm;
+import android.view.Display;
import android.view.DisplayInfo;
-import com.android.server.display.DisplayManagerService;
-
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -60,13 +59,13 @@
int mBaseDisplayWidth = 0;
int mBaseDisplayHeight = 0;
int mBaseDisplayDensity = 0;
- final DisplayManagerService mDisplayManager;
final DisplayInfo mDisplayInfo = new DisplayInfo();
+ final Display mDisplay;
- DisplayContent(DisplayManagerService displayManager, final int displayId) {
- mDisplayManager = displayManager;
- mDisplayId = displayId;
- displayManager.getDisplayInfo(displayId, mDisplayInfo);
+ DisplayContent(Display display) {
+ mDisplay = display;
+ mDisplayId = display.getDisplayId();
+ display.getDisplayInfo(mDisplayInfo);
}
int getDisplayId() {
@@ -77,6 +76,10 @@
return mWindows;
}
+ Display getDisplay() {
+ return mDisplay;
+ }
+
DisplayInfo getDisplayInfo() {
return mDisplayInfo;
}
diff --git a/services/java/com/android/server/wm/KeyguardDisableHandler.java b/services/java/com/android/server/wm/KeyguardDisableHandler.java
new file mode 100644
index 0000000..d935b8b
--- /dev/null
+++ b/services/java/com/android/server/wm/KeyguardDisableHandler.java
@@ -0,0 +1,107 @@
+/*
+ * 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.server.wm;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.TokenWatcher;
+import android.util.Log;
+import android.util.Pair;
+import android.view.WindowManagerPolicy;
+
+public class KeyguardDisableHandler extends Handler {
+ private static final String TAG = "KeyguardDisableHandler";
+
+ private static final int ALLOW_DISABLE_YES = 1;
+ private static final int ALLOW_DISABLE_NO = 0;
+ private static final int ALLOW_DISABLE_UNKNOWN = -1; // check with DevicePolicyManager
+ private int mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN; // sync'd by mKeyguardTokenWatcher
+
+ // Message.what constants
+ static final int KEYGUARD_DISABLE = 1;
+ static final int KEYGUARD_REENABLE = 2;
+ static final int KEYGUARD_POLICY_CHANGED = 3;
+
+ final Context mContext;
+ final WindowManagerPolicy mPolicy;
+ KeyguardTokenWatcher mKeyguardTokenWatcher;
+
+ public KeyguardDisableHandler(final Context context, final WindowManagerPolicy policy) {
+ mContext = context;
+ mPolicy = policy;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void handleMessage(Message msg) {
+ if (mKeyguardTokenWatcher == null) {
+ mKeyguardTokenWatcher = new KeyguardTokenWatcher(this);
+ }
+
+ switch (msg.what) {
+ case KEYGUARD_DISABLE:
+ final Pair<IBinder, String> pair = (Pair<IBinder, String>)msg.obj;
+ mKeyguardTokenWatcher.acquire(pair.first, pair.second);
+ break;
+
+ case KEYGUARD_REENABLE:
+ mKeyguardTokenWatcher.release((IBinder)msg.obj);
+ break;
+
+ case KEYGUARD_POLICY_CHANGED:
+ mPolicy.enableKeyguard(true);
+ // lazily evaluate this next time we're asked to disable keyguard
+ mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN;
+ break;
+ }
+ }
+
+ class KeyguardTokenWatcher extends TokenWatcher {
+
+ public KeyguardTokenWatcher(final Handler handler) {
+ super(handler, TAG);
+ }
+
+ @Override
+ public void acquired() {
+ // We fail safe and prevent disabling keyguard in the unlikely event this gets
+ // called before DevicePolicyManagerService has started.
+ if (mAllowDisableKeyguard == ALLOW_DISABLE_UNKNOWN) {
+ DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ if (dpm != null) {
+ mAllowDisableKeyguard = dpm.getPasswordQuality(null)
+ == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ?
+ ALLOW_DISABLE_YES : ALLOW_DISABLE_NO;
+ }
+ }
+ if (mAllowDisableKeyguard == ALLOW_DISABLE_YES) {
+ mPolicy.enableKeyguard(false);
+ } else {
+ Log.v(TAG, "Not disabling keyguard since device policy is enforced");
+ }
+ }
+
+ @Override
+ public void released() {
+ mPolicy.enableKeyguard(true);
+ }
+ }
+}
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 7d85d89..7679413 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -477,6 +477,7 @@
mRotateFrameAnimation.scaleCurrentDuration(animationScale);
}
+ final int layerStack = mDisplay.getLayerStack();
if (USE_CUSTOM_BLACK_FRAME && mCustomBlackFrame == null) {
if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
WindowManagerService.TAG,
@@ -495,7 +496,8 @@
Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
mOriginalWidth*2, mOriginalHeight*2);
Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
- mCustomBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 3);
+ mCustomBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 3,
+ layerStack);
mCustomBlackFrame.setMatrix(mFrameInitialMatrix);
} catch (Surface.OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
@@ -525,7 +527,8 @@
Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
mOriginalWidth*2, mOriginalHeight*2);
Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
- mExitingBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 2);
+ mExitingBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 2,
+ layerStack);
mExitingBlackFrame.setMatrix(mFrameInitialMatrix);
} catch (Surface.OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
@@ -547,7 +550,8 @@
Rect outer = new Rect(-finalWidth*1, -finalHeight*1,
finalWidth*2, finalHeight*2);
Rect inner = new Rect(0, 0, finalWidth, finalHeight);
- mEnteringBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER);
+ mEnteringBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER,
+ layerStack);
} catch (Surface.OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
} finally {
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 1defa49..580f00d 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -103,6 +103,8 @@
/** Do not modify unless holding mService.mWindowMap or this and mAnimToLayout in that order */
final AnimatorToLayoutParams mAnimToLayout = new AnimatorToLayoutParams();
+ boolean mInitialized = false;
+
WindowAnimator(final WindowManagerService service) {
mService = service;
mContext = service.mContext;
@@ -121,10 +123,13 @@
}
}
};
+ }
+ void initializeLocked(final int layerStack) {
mWindowAnimationBackgroundSurface =
- new DimSurface(mService.mFxSession, Display.DEFAULT_DISPLAY);
- mDimAnimator = new DimAnimator(mService.mFxSession, Display.DEFAULT_DISPLAY);
+ new DimSurface(mService.mFxSession, layerStack);
+ mDimAnimator = new DimAnimator(mService.mFxSession, layerStack);
+ mInitialized = true;
}
/** Locked on mAnimToLayout */
@@ -563,6 +568,9 @@
// TODO(cmautner): Change the following comment when no longer locked on mWindowMap */
/** Locked on mService.mWindowMap and this. */
private void animateLocked() {
+ if (!mInitialized) {
+ return;
+ }
for (int i = mWinAnimatorLists.size() - 1; i >= 0; i--) {
animateLocked(mWinAnimatorLists.get(i));
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index b0c5835..42bc7ce 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -74,7 +74,7 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
-import android.os.BatteryStats;
+import android.hardware.display.DisplayManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
@@ -92,7 +92,6 @@
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.TokenWatcher;
import android.os.Trace;
import android.os.WorkSource;
import android.provider.Settings;
@@ -278,55 +277,19 @@
private static final String SYSTEM_SECURE = "ro.secure";
private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
- /**
- * Condition waited on by {@link #reenableKeyguard} to know the call to
- * the window policy has finished.
- * This is set to true only if mKeyguardTokenWatcher.acquired() has
- * actually disabled the keyguard.
- */
- private boolean mKeyguardDisabled = false;
+ final private KeyguardDisableHandler mKeyguardDisableHandler;
private final boolean mHeadless;
- private static final int ALLOW_DISABLE_YES = 1;
- private static final int ALLOW_DISABLE_NO = 0;
- private static final int ALLOW_DISABLE_UNKNOWN = -1; // check with DevicePolicyManager
- private int mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN; // sync'd by mKeyguardTokenWatcher
-
private static final float THUMBNAIL_ANIMATION_DECELERATE_FACTOR = 1.5f;
- final TokenWatcher mKeyguardTokenWatcher = new TokenWatcher(
- new Handler(), "WindowManagerService.mKeyguardTokenWatcher") {
- @Override
- public void acquired() {
- if (shouldAllowDisableKeyguard()) {
- mPolicy.enableKeyguard(false);
- mKeyguardDisabled = true;
- } else {
- Log.v(TAG, "Not disabling keyguard since device policy is enforced");
- }
- }
- @Override
- public void released() {
- mPolicy.enableKeyguard(true);
- synchronized (mKeyguardTokenWatcher) {
- mKeyguardDisabled = false;
- mKeyguardTokenWatcher.notifyAll();
- }
- }
- };
-
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) {
- mPolicy.enableKeyguard(true);
- synchronized(mKeyguardTokenWatcher) {
- // lazily evaluate this next time we're asked to disable keyguard
- mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN;
- mKeyguardDisabled = false;
- }
+ mKeyguardDisableHandler.sendEmptyMessage(
+ KeyguardDisableHandler.KEYGUARD_POLICY_CHANGED);
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
final int newUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
Slog.v(TAG, "Switching user from " + mCurrentUserId + " to " + newUserId);
@@ -540,7 +503,7 @@
final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
- Display mDisplay;
+ Display mDefaultDisplay;
boolean mIsTouchDevice;
@@ -606,7 +569,8 @@
float mAnimatorDurationScale = 1.0f;
final InputManagerService mInputManager;
- final DisplayManagerService mDisplayManager;
+ final DisplayManagerService mDisplayManagerService;
+ final DisplayManager mDisplayManager;
// Who is holding the screen on.
Session mHoldingScreenOn;
@@ -844,17 +808,14 @@
private final WindowManagerPolicy mPolicy;
private final WindowManagerService mService;
private final Context mContext;
- private final PowerManagerService mPM;
boolean mRunning = false;
public PolicyThread(WindowManagerPolicy policy,
- WindowManagerService service, Context context,
- PowerManagerService pm) {
+ WindowManagerService service, Context context) {
super("WindowManagerPolicy");
mPolicy = policy;
mService = service;
mContext = context;
- mPM = pm;
}
@Override
@@ -895,9 +856,12 @@
mOnlyCore = onlyCore;
mLimitedAlphaCompositing = context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_limitedAlpha);
- mDisplayManager = displayManager;
+ mDisplayManagerService = displayManager;
+ mDisplayManager = DisplayManager.getInstance();
mHeadless = displayManager.isHeadless();
+ mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
+
mPowerManager = pm;
mPowerManager.setPolicy(mPolicy);
PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
@@ -931,7 +895,7 @@
mFxSession = new SurfaceSession();
mAnimator = new WindowAnimator(this);
- PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
+ PolicyThread thr = new PolicyThread(mPolicy, this, context);
thr.start();
synchronized (thr) {
@@ -1238,7 +1202,6 @@
/**
* Dig through the WindowStates and find the one that the Input Method will target.
* @param willMove
- * @param windows TODO(cmautner):
* @return The index+1 in mWindows of the discovered target.
*/
int findDesiredInputMethodWindowIndexLocked(boolean willMove) {
@@ -2164,7 +2127,7 @@
long origId;
synchronized(mWindowMap) {
- if (mDisplay == null) {
+ if (mDefaultDisplay == null) {
throw new IllegalStateException("Display has not been initialialized");
}
@@ -3076,6 +3039,7 @@
Binder.restoreCallingIdentity(origId);
}
+ @Override
public float getWindowCompatibilityScale(IBinder windowToken) {
if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
"getWindowCompatibilityScale()")) {
@@ -3807,7 +3771,7 @@
Configuration config = null;
long ident = Binder.clearCallingIdentity();
-
+
synchronized(mWindowMap) {
config = updateOrientationFromAppTokensLocked(currentConfig,
freezeThisOneIfNeeded);
@@ -3848,7 +3812,7 @@
}
}
}
-
+
return config;
}
@@ -3859,7 +3823,7 @@
* setNewConfiguration() TO TELL THE WINDOW MANAGER IT CAN UNFREEZE THE
* SCREEN. This will typically be done for you if you call
* sendNewConfiguration().
- *
+ *
* The orientation is computed from non-application windows first. If none of
* the non-application windows specify orientation, the orientation is computed from
* application tokens.
@@ -5062,59 +5026,26 @@
// Misc IWindowSession methods
// -------------------------------------------------------------
- private boolean shouldAllowDisableKeyguard()
- {
- // We fail safe and prevent disabling keyguard in the unlikely event this gets
- // called before DevicePolicyManagerService has started.
- if (mAllowDisableKeyguard == ALLOW_DISABLE_UNKNOWN) {
- DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
- Context.DEVICE_POLICY_SERVICE);
- if (dpm != null) {
- mAllowDisableKeyguard = dpm.getPasswordQuality(null)
- == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ?
- ALLOW_DISABLE_YES : ALLOW_DISABLE_NO;
- }
- }
- return mAllowDisableKeyguard == ALLOW_DISABLE_YES;
- }
-
+ @Override
public void disableKeyguard(IBinder token, String tag) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires DISABLE_KEYGUARD permission");
}
- synchronized (mKeyguardTokenWatcher) {
- mKeyguardTokenWatcher.acquire(token, tag);
- }
+ mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
+ KeyguardDisableHandler.KEYGUARD_DISABLE, new Pair<IBinder, String>(token, tag)));
}
+ @Override
public void reenableKeyguard(IBinder token) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires DISABLE_KEYGUARD permission");
}
- synchronized (mKeyguardTokenWatcher) {
- mKeyguardTokenWatcher.release(token);
-
- if (!mKeyguardTokenWatcher.isAcquired()) {
- // If we are the last one to reenable the keyguard wait until
- // we have actually finished reenabling until returning.
- // It is possible that reenableKeyguard() can be called before
- // the previous disableKeyguard() is handled, in which case
- // neither mKeyguardTokenWatcher.acquired() or released() would
- // be called. In that case mKeyguardDisabled will be false here
- // and we have nothing to wait for.
- while (mKeyguardDisabled) {
- try {
- mKeyguardTokenWatcher.wait();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- }
- }
+ mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
+ KeyguardDisableHandler.KEYGUARD_REENABLE, token));
}
/**
@@ -5546,7 +5477,7 @@
Surface.openTransaction();
try {
if (mStrictModeFlash == null) {
- mStrictModeFlash = new StrictModeFlash(mDisplay, mFxSession);
+ mStrictModeFlash = new StrictModeFlash(mDefaultDisplay, mFxSession);
}
mStrictModeFlash.setVisibility(on);
} finally {
@@ -5659,7 +5590,7 @@
}
// The screenshot API does not apply the current screen rotation.
- rot = mDisplay.getRotation();
+ rot = mDefaultDisplay.getRotation();
int fw = frame.width();
int fh = frame.height();
@@ -6574,7 +6505,7 @@
}
boolean computeScreenConfigurationLocked(Configuration config) {
- if (mDisplay == null) {
+ if (mDefaultDisplay == null) {
return false;
}
@@ -6630,7 +6561,7 @@
displayInfo.appHeight = appHeight;
displayInfo.getLogicalMetrics(mRealDisplayMetrics, null);
displayInfo.getAppMetrics(mDisplayMetrics, null);
- mDisplayManager.setDisplayInfo(displayContent.getDisplayId(), displayInfo);
+ mDisplayManagerService.setDisplayInfo(displayContent.getDisplayId(), displayInfo);
mAnimator.setDisplayDimensions(dw, dh, appWidth, appHeight);
}
@@ -6781,7 +6712,7 @@
try {
if (mDragState == null) {
Surface surface = new Surface(session, callerPid, "drag surface",
- Display.DEFAULT_DISPLAY,
+ mDefaultDisplay.getLayerStack(),
width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
if (SHOW_TRANSACTIONS) Slog.i(TAG, " DRAG "
+ surface + ": CREATE");
@@ -6939,30 +6870,33 @@
}
public void displayReady() {
- displayReady(Display.DEFAULT_DISPLAY);
+ WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+ final Display display = wm.getDefaultDisplay();
+ displayReady(display.getDisplayId());
synchronized(mWindowMap) {
readForcedDisplaySizeAndDensityLocked(getDefaultDisplayContent());
- WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
- mDisplay = wm.getDefaultDisplay();
+ mDefaultDisplay = display;
mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TOUCHSCREEN);
+ mAnimator.initializeLocked(display.getLayerStack());
+
final DisplayInfo displayInfo = getDefaultDisplayInfo();
mAnimator.setDisplayDimensions(displayInfo.logicalWidth, displayInfo.logicalHeight,
displayInfo.appWidth, displayInfo.appHeight);
DisplayDeviceInfo info = new DisplayDeviceInfo();
- mDisplayManager.getDefaultExternalDisplayDeviceInfo(info);
+ mDisplayManagerService.getDefaultExternalDisplayDeviceInfo(info);
final DisplayContent displayContent = getDefaultDisplayContent();
- mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY,
+ mInputManager.setDisplaySize(displayContent.getDisplayId(),
displayContent.mInitialDisplayWidth, displayContent.mInitialDisplayHeight,
info.width, info.height);
- mInputManager.setDisplayOrientation(Display.DEFAULT_DISPLAY,
- mDisplay.getRotation(), Surface.ROTATION_0);
- mPolicy.setInitialDisplaySize(mDisplay, displayContent.mInitialDisplayWidth,
+ mInputManager.setDisplayOrientation(displayContent.getDisplayId(),
+ mDefaultDisplay.getRotation(), Surface.ROTATION_0);
+ mPolicy.setInitialDisplaySize(mDefaultDisplay, displayContent.mInitialDisplayWidth,
displayContent.mInitialDisplayHeight, displayContent.mInitialDisplayDensity);
}
@@ -6979,7 +6913,7 @@
synchronized(displayContent.mDisplaySizeLock) {
// Bootstrap the default logical display from the display manager.
displayInfo = displayContent.getDisplayInfo();
- mDisplayManager.getDisplayInfo(displayId, displayInfo);
+ mDisplayManagerService.getDisplayInfo(displayId, displayInfo);
displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
@@ -7620,7 +7554,8 @@
Rect outer = new Rect(0, 0, initW, initH);
Rect inner = new Rect(0, 0, baseW, baseH);
try {
- mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
+ mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER,
+ mDefaultDisplay.getLayerStack());
} catch (Surface.OutOfResourcesException e) {
}
}
@@ -7719,7 +7654,7 @@
}
private void reconfigureDisplayLocked(DisplayContent displayContent) {
- mPolicy.setInitialDisplaySize(mDisplay, displayContent.mBaseDisplayWidth,
+ mPolicy.setInitialDisplaySize(mDefaultDisplay, displayContent.mBaseDisplayWidth,
displayContent.mBaseDisplayHeight, displayContent.mBaseDisplayDensity);
mLayoutNeeded = true;
@@ -7944,7 +7879,7 @@
return;
}
- if (mDisplay == null) {
+ if (mDefaultDisplay == null) {
// Not yet initialized, nothing to do.
return;
}
@@ -8408,7 +8343,7 @@
mNextAppTransitionThumbnail.getHeight());
try {
Surface surface = new Surface(mFxSession, Process.myPid(),
- "thumbnail anim", Display.DEFAULT_DISPLAY,
+ "thumbnail anim", mDefaultDisplay.getLayerStack(),
dirty.width(), dirty.height(),
PixelFormat.TRANSLUCENT, Surface.HIDDEN);
topOpeningApp.mAppAnimator.thumbnail = surface;
@@ -8676,7 +8611,7 @@
Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
+ Debug.getCallers(3));
}
- if (mDisplay == null) {
+ if (mDefaultDisplay == null) {
Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
return;
}
@@ -9587,7 +9522,7 @@
return;
}
- if (mDisplay == null || !mPolicy.isScreenOnFully()) {
+ if (mDefaultDisplay == null || !mPolicy.isScreenOnFully()) {
// No need to freeze the screen before the system is ready or if
// the screen is off.
return;
@@ -9620,9 +9555,9 @@
// TODO(multidisplay): rotation on main screen only.
DisplayInfo displayInfo = getDefaultDisplayContent().getDisplayInfo();
- mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext, mDisplay,
- mFxSession, inTransaction, displayInfo.logicalWidth, displayInfo.logicalHeight,
- mDisplay.getRotation());
+ mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
+ mDefaultDisplay, mFxSession, inTransaction, displayInfo.logicalWidth,
+ displayInfo.logicalHeight, mDefaultDisplay.getRotation());
}
}
@@ -9733,7 +9668,8 @@
if (line != null) {
String[] toks = line.split("%");
if (toks != null && toks.length > 0) {
- mWatermark = new Watermark(mDisplay, mRealDisplayMetrics, mFxSession, toks);
+ mWatermark =
+ new Watermark(mDefaultDisplay, mRealDisplayMetrics, mFxSession, toks);
}
}
} catch (FileNotFoundException e) {
@@ -10101,7 +10037,7 @@
}
}
pw.println();
- if (mDisplay != null) {
+ if (mDefaultDisplay != null) {
DisplayContentsIterator dCIterator = new DisplayContentsIterator();
while (dCIterator.hasNext()) {
dCIterator.next().dump(pw);
@@ -10411,7 +10347,6 @@
// Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
public void monitor() {
synchronized (mWindowMap) { }
- synchronized (mKeyguardTokenWatcher) { }
}
public interface OnHardKeyboardStatusChangeListener {
@@ -10428,7 +10363,7 @@
public DisplayContent getDisplayContent(final int displayId) {
DisplayContent displayContent = mDisplayContents.get(displayId);
if (displayContent == null) {
- displayContent = new DisplayContent(mDisplayManager, displayId);
+ displayContent = new DisplayContent(mDisplayManager.getRealDisplay(displayId));
mDisplayContents.put(displayId, displayContent);
}
return displayContent;
@@ -10497,7 +10432,8 @@
}
} else {
mWindowListIndex++;
- if (mWindowListIndex >= mWindowList.size() && mDisplayContentsIterator.hasNext()) {
+ if (mWindowListIndex >= mWindowList.size()
+ && mDisplayContentsIterator.hasNext()) {
mDisplayContent = mDisplayContentsIterator.next();
mWindowList = mDisplayContent.getWindowList();
mWindowListIndex = 0;
@@ -10515,7 +10451,9 @@
}
public DisplayContent getDefaultDisplayContent() {
- return getDisplayContent(Display.DEFAULT_DISPLAY);
+ final int displayId = mDefaultDisplay == null
+ ? Display.DEFAULT_DISPLAY : mDefaultDisplay.getDisplayId();
+ return getDisplayContent(displayId);
}
public WindowList getDefaultWindowList() {
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 69bad81..982f60d 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -148,6 +148,8 @@
int mAttrFlags;
int mAttrType;
+ final int mLayerStack;
+
public WindowStateAnimator(final WindowState win) {
final WindowManagerService service = win.mService;
@@ -167,6 +169,7 @@
mAttrFlags = win.mAttrs.flags;
mAttrType = win.mAttrs.type;
mIsWallpaper = win.mIsWallpaper;
+ mLayerStack = win.mDisplayContent.getDisplay().getLayerStack();
}
public void setAnimation(Animation anim) {
@@ -651,12 +654,12 @@
mSurface = new SurfaceTrace(
mSession.mSurfaceSession, mSession.mPid,
attrs.getTitle().toString(),
- mWin.mDisplayContent.getDisplayId(), w, h, format, flags);
+ mLayerStack, w, h, format, flags);
} else {
mSurface = new Surface(
mSession.mSurfaceSession, mSession.mPid,
attrs.getTitle().toString(),
- mWin.mDisplayContent.getDisplayId(), w, h, format, flags);
+ mLayerStack, w, h, format, flags);
}
mWin.mHasSurface = true;
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG,
diff --git a/telephony/java/com/android/internal/telephony/IccCardConstants.java b/telephony/java/com/android/internal/telephony/IccCardConstants.java
index 20439bc..4d1eb3f 100644
--- a/telephony/java/com/android/internal/telephony/IccCardConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccCardConstants.java
@@ -22,6 +22,8 @@
/* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */
public static final String INTENT_KEY_ICC_STATE = "ss";
+ /* UNKNOWN means the ICC state is unknown */
+ public static final String INTENT_VALUE_ICC_UNKNOWN = "UNKNOWN";
/* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */
public static final String INTENT_VALUE_ICC_NOT_READY = "NOT_READY";
/* ABSENT means ICC is missing */
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 0fb51f0..ac40fc6b 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -536,6 +536,12 @@
throw new UnsupportedOperationException();
}
+ @Override
+ public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
+ long millisecondsToDelay) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* @hide
*/
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 1d06c76..a5322fa 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -3553,7 +3553,12 @@
handleNetworkDisconnect();
break;
case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
- // EAP failures do not mean much during WPS
+ // Disregard auth failure events during WPS connection. The
+ // EAP sequence is retried several times, and there might be
+ // failures (especially for wps pin). We will get a WPS_XXX
+ // event at the end of the sequence anyway.
+ if (DBG) log("Ignore auth failure during WPS connection");
+ break;
case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
//Throw away supplicant state changes when WPS is running.
//We will start getting supplicant state changes once we get