Merge "Refactor CameraService to handle errors properly." into klp-dev
diff --git a/api/current.txt b/api/current.txt
index 5a3c7db..f912a0b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1015,6 +1015,7 @@
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsRtl = 16843695; // 0x10103af
+ field public static final int supportsSwitchingToNextInputMethod = 16843753; // 0x10103e9
field public static final int supportsUploading = 16843419; // 0x101029b
field public static final int switchMinWidth = 16843632; // 0x1010370
field public static final int switchPadding = 16843633; // 0x1010371
@@ -10924,7 +10925,9 @@
public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
method public void addTarget(android.view.Surface);
+ method public java.lang.Object getTag();
method public void removeTarget(android.view.Surface);
+ method public void setTag(java.lang.Object);
field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_MODE;
@@ -12598,6 +12601,7 @@
ctor public MediaFormat();
method public final boolean containsKey(java.lang.String);
method public static final android.media.MediaFormat createAudioFormat(java.lang.String, int, int);
+ method public static final android.media.MediaFormat createSubtitleFormat(java.lang.String, java.lang.String);
method public static final android.media.MediaFormat createVideoFormat(java.lang.String, int, int);
method public final java.nio.ByteBuffer getByteBuffer(java.lang.String);
method public final float getFloat(java.lang.String);
@@ -12620,6 +12624,7 @@
field public static final java.lang.String KEY_HEIGHT = "height";
field public static final java.lang.String KEY_IS_ADTS = "is-adts";
field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
+ field public static final java.lang.String KEY_LANGUAGE = "language";
field public static final java.lang.String KEY_MAX_INPUT_SIZE = "max-input-size";
field public static final java.lang.String KEY_MIME = "mime";
field public static final java.lang.String KEY_SAMPLE_RATE = "sample-rate";
@@ -18108,8 +18113,14 @@
public class ParcelFileDescriptor implements java.io.Closeable android.os.Parcelable {
ctor public ParcelFileDescriptor(android.os.ParcelFileDescriptor);
method public static android.os.ParcelFileDescriptor adoptFd(int);
+ method public boolean canDetectErrors();
+ method public void checkError(boolean) throws java.io.IOException;
method public void close() throws java.io.IOException;
+ method public void closeWithError(java.lang.String) throws java.io.IOException;
method public static android.os.ParcelFileDescriptor[] createPipe() throws java.io.IOException;
+ method public static android.os.ParcelFileDescriptor[] createReliablePipe() throws java.io.IOException;
+ method public static android.os.ParcelFileDescriptor[] createReliableSocketPair() throws java.io.IOException;
+ method public static android.os.ParcelFileDescriptor[] createSocketPair() throws java.io.IOException;
method public int describeContents();
method public int detachFd();
method public static android.os.ParcelFileDescriptor dup(java.io.FileDescriptor) throws java.io.IOException;
@@ -18121,6 +18132,7 @@
method public java.io.FileDescriptor getFileDescriptor();
method public long getStatSize();
method public static android.os.ParcelFileDescriptor open(java.io.File, int) throws java.io.FileNotFoundException;
+ method public static android.os.ParcelFileDescriptor open(java.io.File, int, android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener) throws java.io.IOException;
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int MODE_APPEND = 33554432; // 0x2000000
@@ -18128,8 +18140,8 @@
field public static final int MODE_READ_ONLY = 268435456; // 0x10000000
field public static final int MODE_READ_WRITE = 805306368; // 0x30000000
field public static final int MODE_TRUNCATE = 67108864; // 0x4000000
- field public static final int MODE_WORLD_READABLE = 1; // 0x1
- field public static final int MODE_WORLD_WRITEABLE = 2; // 0x2
+ field public static final deprecated int MODE_WORLD_READABLE = 1; // 0x1
+ field public static final deprecated int MODE_WORLD_WRITEABLE = 2; // 0x2
field public static final int MODE_WRITE_ONLY = 536870912; // 0x20000000
}
@@ -18141,6 +18153,10 @@
ctor public ParcelFileDescriptor.AutoCloseOutputStream(android.os.ParcelFileDescriptor);
}
+ public static abstract interface ParcelFileDescriptor.OnCloseListener {
+ method public abstract void onClose(java.io.IOException, boolean);
+ }
+
public class ParcelFormatException extends java.lang.RuntimeException {
ctor public ParcelFormatException();
ctor public ParcelFormatException(java.lang.String);
@@ -29491,19 +29507,18 @@
public abstract class Transition implements java.lang.Cloneable {
ctor public Transition();
method public void addListener(android.view.transition.Transition.TransitionListener);
- method protected void cancelTransition();
+ method protected void cancel();
method protected abstract void captureValues(android.view.transition.TransitionValues, boolean);
method public android.view.transition.Transition clone();
method public long getDuration();
method public android.animation.TimeInterpolator getInterpolator();
method public java.util.ArrayList<android.view.transition.Transition.TransitionListener> getListeners();
+ method public java.lang.String getName();
method public long getStartDelay();
method public int[] getTargetIds();
method public android.view.View[] getTargets();
+ method public java.lang.String[] getTransitionProperties();
method protected android.view.transition.TransitionValues getTransitionValues(android.view.View, boolean);
- method protected void onTransitionCancel();
- method protected void onTransitionEnd();
- method protected void onTransitionStart();
method protected android.animation.Animator play(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
method public void removeListener(android.view.transition.Transition.TransitionListener);
method public android.view.transition.Transition setDuration(long);
@@ -29516,6 +29531,8 @@
public static abstract interface Transition.TransitionListener {
method public abstract void onTransitionCancel(android.view.transition.Transition);
method public abstract void onTransitionEnd(android.view.transition.Transition);
+ method public abstract void onTransitionPause(android.view.transition.Transition);
+ method public abstract void onTransitionResume(android.view.transition.Transition);
method public abstract void onTransitionStart(android.view.transition.Transition);
}
@@ -29562,6 +29579,7 @@
method protected android.animation.Animator appear(android.view.ViewGroup, android.view.transition.TransitionValues, int, android.view.transition.TransitionValues, int);
method protected void captureValues(android.view.transition.TransitionValues, boolean);
method protected android.animation.Animator disappear(android.view.ViewGroup, android.view.transition.TransitionValues, int, android.view.transition.TransitionValues, int);
+ method public boolean isVisible(android.view.transition.TransitionValues);
}
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 45fed2d..5cabfeef 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2060,7 +2060,7 @@
private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
private final IContentProvider mContentProvider;
- private boolean mReleaseProviderFlag = false;
+ private boolean mProviderReleased;
ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
super(pfd);
@@ -2069,17 +2069,10 @@
@Override
public void close() throws IOException {
- if(!mReleaseProviderFlag) {
- super.close();
+ super.close();
+ if (!mProviderReleased) {
ContentResolver.this.releaseProvider(mContentProvider);
- mReleaseProviderFlag = true;
- }
- }
-
- @Override
- protected void finalize() throws Throwable {
- if (!mReleaseProviderFlag) {
- close();
+ mProviderReleased = true;
}
}
}
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 1a10bdd..63d6134 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -53,6 +53,7 @@
private final Object mLock = new Object();
private final HashSet<Surface> mSurfaceSet = new HashSet<Surface>();
+ private Object mUserTag;
/**
* @hide
@@ -89,6 +90,42 @@
}
}
+ /**
+ * Set a tag for this request.
+ *
+ * <p>This tag is not used for anything by the camera device, but can be
+ * used by an application to easily identify a CaptureRequest when it is
+ * returned by
+ * {@link CameraDevice.CaptureListener#onCaptureComplete CaptureListener.onCaptureComplete}
+ *
+ * @param tag an arbitrary Object to store with this request
+ * @see #getTag
+ */
+ public void setTag(Object tag) {
+ synchronized (mLock) {
+ mUserTag = tag;
+ }
+ }
+
+ /**
+ * Retrieve the tag for this request, if any.
+ *
+ * <p>This tag is not used for anything by the camera device, but can be
+ * used by an application to easily identify a CaptureRequest when it is
+ * returned by
+ * {@link CameraDevice.CaptureListener#onCaptureComplete CaptureListener.onCaptureComplete}
+ * </p>
+ *
+ * @return the last tag Object set on this request, or {@code null} if
+ * no tag has been set.
+ * @see #setTag
+ */
+ public Object getTag() {
+ synchronized (mLock) {
+ return mUserTag;
+ }
+ }
+
public static final Parcelable.Creator<CaptureRequest> CREATOR =
new Parcelable.Creator<CaptureRequest>() {
@Override
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 12f7915..46b0150 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1520,6 +1520,11 @@
return fd != null ? new ParcelFileDescriptor(fd) : null;
}
+ /** {@hide} */
+ public final FileDescriptor readRawFileDescriptor() {
+ return nativeReadFileDescriptor(mNativePtr);
+ }
+
/*package*/ static native FileDescriptor openFileDescriptor(String file,
int mode) throws FileNotFoundException;
/*package*/ static native FileDescriptor dupFileDescriptor(FileDescriptor orig)
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 3de362c..579971d 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -16,8 +16,25 @@
package android.os;
+import static libcore.io.OsConstants.AF_UNIX;
+import static libcore.io.OsConstants.SEEK_SET;
+import static libcore.io.OsConstants.SOCK_STREAM;
+import static libcore.io.OsConstants.S_ISLNK;
+import static libcore.io.OsConstants.S_ISREG;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentProvider;
+import android.util.Log;
+
import dalvik.system.CloseGuard;
+import libcore.io.ErrnoException;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+import libcore.io.Memory;
+import libcore.io.OsConstants;
+import libcore.io.StructStat;
+
import java.io.Closeable;
import java.io.File;
import java.io.FileDescriptor;
@@ -27,36 +44,80 @@
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.Socket;
+import java.nio.ByteOrder;
/**
* The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing
* you to close it when done with it.
*/
public class ParcelFileDescriptor implements Parcelable, Closeable {
- private final FileDescriptor mFileDescriptor;
+ private static final String TAG = "ParcelFileDescriptor";
+
+ private final FileDescriptor mFd;
+
+ /**
+ * Optional socket used to communicate close events, status at close, and
+ * detect remote process crashes.
+ */
+ private FileDescriptor mCommFd;
/**
* Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid
- * double-closing {@link #mFileDescriptor}.
+ * double-closing {@link #mFd}.
*/
private final ParcelFileDescriptor mWrapped;
+ /**
+ * Maximum {@link #mStatusBuf} size; longer status messages will be
+ * truncated.
+ */
+ private static final int MAX_STATUS = 1024;
+
+ /**
+ * Temporary buffer used by {@link #readCommStatus(FileDescriptor, byte[])},
+ * allocated on-demand.
+ */
+ private byte[] mStatusBuf;
+
+ /**
+ * Status read by {@link #checkError(boolean)}, or null if not read yet.
+ */
+ private Status mStatus;
+
private volatile boolean mClosed;
private final CloseGuard mGuard = CloseGuard.get();
/**
- * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied
- * and this file doesn't already exist, then create the file with
- * permissions such that any application can read it.
+ * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
+ * this file doesn't already exist, then create the file with permissions
+ * such that any application can read it.
+ *
+ * @deprecated Creating world-readable files is very dangerous, and likely
+ * to cause security holes in applications. It is strongly
+ * discouraged; instead, applications should use more formal
+ * mechanism for interactions such as {@link ContentProvider},
+ * {@link BroadcastReceiver}, and {@link android.app.Service}.
+ * There are no guarantees that this access mode will remain on
+ * a file, such as when it goes through a backup and restore.
*/
+ @Deprecated
public static final int MODE_WORLD_READABLE = 0x00000001;
/**
- * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied
- * and this file doesn't already exist, then create the file with
- * permissions such that any application can write it.
+ * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
+ * this file doesn't already exist, then create the file with permissions
+ * such that any application can write it.
+ *
+ * @deprecated Creating world-writable files is very dangerous, and likely
+ * to cause security holes in applications. It is strongly
+ * discouraged; instead, applications should use more formal
+ * mechanism for interactions such as {@link ContentProvider},
+ * {@link BroadcastReceiver}, and {@link android.app.Service}.
+ * There are no guarantees that this access mode will remain on
+ * a file, such as when it goes through a backup and restore.
*/
+ @Deprecated
public static final int MODE_WORLD_WRITEABLE = 0x00000002;
/**
@@ -90,32 +151,102 @@
public static final int MODE_APPEND = 0x02000000;
/**
+ * Create a new ParcelFileDescriptor wrapped around another descriptor. By
+ * default all method calls are delegated to the wrapped descriptor.
+ */
+ public ParcelFileDescriptor(ParcelFileDescriptor wrapped) {
+ // We keep a strong reference to the wrapped PFD, and rely on its
+ // finalizer to trigger CloseGuard. All calls are delegated to wrapper.
+ mWrapped = wrapped;
+ mFd = null;
+ mCommFd = null;
+ mClosed = true;
+ }
+
+ /** {@hide} */
+ public ParcelFileDescriptor(FileDescriptor fd) {
+ this(fd, null);
+ }
+
+ /** {@hide} */
+ public ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel) {
+ if (fd == null) {
+ throw new NullPointerException("FileDescriptor must not be null");
+ }
+ mWrapped = null;
+ mFd = fd;
+ mCommFd = commChannel;
+ mGuard.open("close");
+ }
+
+ /**
* Create a new ParcelFileDescriptor accessing a given file.
*
* @param file The file to be opened.
* @param mode The desired access mode, must be one of
- * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
- * {@link #MODE_READ_WRITE}; may also be any combination of
- * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
- * {@link #MODE_WORLD_READABLE}, and {@link #MODE_WORLD_WRITEABLE}.
- *
- * @return Returns a new ParcelFileDescriptor pointing to the given
- * file.
- *
- * @throws FileNotFoundException Throws FileNotFoundException if the given
- * file does not exist or can not be opened with the requested mode.
+ * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
+ * {@link #MODE_READ_WRITE}; may also be any combination of
+ * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
+ * {@link #MODE_WORLD_READABLE}, and
+ * {@link #MODE_WORLD_WRITEABLE}.
+ * @return a new ParcelFileDescriptor pointing to the given file.
+ * @throws FileNotFoundException if the given file does not exist or can not
+ * be opened with the requested mode.
*/
- public static ParcelFileDescriptor open(File file, int mode)
- throws FileNotFoundException {
- String path = file.getPath();
+ public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException {
+ final FileDescriptor fd = openInternal(file, mode);
+ if (fd == null) return null;
- if ((mode&MODE_READ_WRITE) == 0) {
+ return new ParcelFileDescriptor(fd);
+ }
+
+ /**
+ * Create a new ParcelFileDescriptor accessing a given file.
+ *
+ * @param file The file to be opened.
+ * @param mode The desired access mode, must be one of
+ * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
+ * {@link #MODE_READ_WRITE}; may also be any combination of
+ * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
+ * {@link #MODE_WORLD_READABLE}, and
+ * {@link #MODE_WORLD_WRITEABLE}.
+ * @param handler to call listener from; must not be null.
+ * @param listener to be invoked when the returned descriptor has been
+ * closed; must not be null.
+ * @return a new ParcelFileDescriptor pointing to the given file.
+ * @throws FileNotFoundException if the given file does not exist or can not
+ * be opened with the requested mode.
+ */
+ public static ParcelFileDescriptor open(
+ File file, int mode, Handler handler, OnCloseListener listener) throws IOException {
+ if (handler == null) {
+ throw new IllegalArgumentException("Handler must not be null");
+ }
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener must not be null");
+ }
+
+ final FileDescriptor fd = openInternal(file, mode);
+ if (fd == null) return null;
+
+ final FileDescriptor[] comm = createCommSocketPair(true);
+ final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
+
+ // Kick off thread to watch for status updates
+ final ListenerBridge bridge = new ListenerBridge(comm[1], handler.getLooper(), listener);
+ bridge.start();
+
+ return pfd;
+ }
+
+ private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
+ if ((mode & MODE_READ_WRITE) == 0) {
throw new IllegalArgumentException(
"Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE");
}
- FileDescriptor fd = Parcel.openFileDescriptor(path, mode);
- return fd != null ? new ParcelFileDescriptor(fd) : null;
+ final String path = file.getPath();
+ return Parcel.openFileDescriptor(path, mode);
}
/**
@@ -125,8 +256,12 @@
* original file descriptor.
*/
public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
- FileDescriptor fd = Parcel.dupFileDescriptor(orig);
- return fd != null ? new ParcelFileDescriptor(fd) : null;
+ try {
+ final FileDescriptor fd = Libcore.os.dup(orig);
+ return new ParcelFileDescriptor(fd);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
}
/**
@@ -136,7 +271,11 @@
* original file descriptor.
*/
public ParcelFileDescriptor dup() throws IOException {
- return dup(getFileDescriptor());
+ if (mWrapped != null) {
+ return mWrapped.dup();
+ } else {
+ return dup(getFileDescriptor());
+ }
}
/**
@@ -150,12 +289,16 @@
* for a dup of the given fd.
*/
public static ParcelFileDescriptor fromFd(int fd) throws IOException {
- FileDescriptor fdesc = getFileDescriptorFromFd(fd);
- return new ParcelFileDescriptor(fdesc);
- }
+ final FileDescriptor original = new FileDescriptor();
+ original.setInt$(fd);
- // Extracts the file descriptor from the specified socket and returns it untouched
- private static native FileDescriptor getFileDescriptorFromFd(int fd) throws IOException;
+ try {
+ final FileDescriptor dup = Libcore.os.dup(original);
+ return new ParcelFileDescriptor(dup);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ }
/**
* Take ownership of a raw native fd in to a new ParcelFileDescriptor.
@@ -168,13 +311,12 @@
* for the given fd.
*/
public static ParcelFileDescriptor adoptFd(int fd) {
- FileDescriptor fdesc = getFileDescriptorFromFdNoDup(fd);
+ final FileDescriptor fdesc = new FileDescriptor();
+ fdesc.setInt$(fd);
+
return new ParcelFileDescriptor(fdesc);
}
- // Extracts the file descriptor from the specified socket and returns it untouched
- private static native FileDescriptor getFileDescriptorFromFdNoDup(int fd);
-
/**
* Create a new ParcelFileDescriptor from the specified Socket. The new
* ParcelFileDescriptor holds a dup of the original FileDescriptor in
@@ -212,15 +354,90 @@
* is the write side.
*/
public static ParcelFileDescriptor[] createPipe() throws IOException {
- FileDescriptor[] fds = new FileDescriptor[2];
- createPipeNative(fds);
- ParcelFileDescriptor[] pfds = new ParcelFileDescriptor[2];
- pfds[0] = new ParcelFileDescriptor(fds[0]);
- pfds[1] = new ParcelFileDescriptor(fds[1]);
- return pfds;
+ try {
+ final FileDescriptor[] fds = Libcore.os.pipe();
+ return new ParcelFileDescriptor[] {
+ new ParcelFileDescriptor(fds[0]),
+ new ParcelFileDescriptor(fds[1]) };
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
}
- private static native void createPipeNative(FileDescriptor[] outFds) throws IOException;
+ /**
+ * Create two ParcelFileDescriptors structured as a data pipe. The first
+ * ParcelFileDescriptor in the returned array is the read side; the second
+ * is the write side.
+ * <p>
+ * The write end has the ability to deliver an error message through
+ * {@link #closeWithError(String)} which can be handled by the read end
+ * calling {@link #checkError(boolean)}, usually after detecting an EOF.
+ * This can also be used to detect remote crashes.
+ */
+ public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
+ try {
+ final FileDescriptor[] comm = createCommSocketPair(false);
+ final FileDescriptor[] fds = Libcore.os.pipe();
+ return new ParcelFileDescriptor[] {
+ new ParcelFileDescriptor(fds[0], comm[0]),
+ new ParcelFileDescriptor(fds[1], comm[1]) };
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ }
+
+ /**
+ * Create two ParcelFileDescriptors structured as a pair of sockets
+ * connected to each other. The two sockets are indistinguishable.
+ */
+ public static ParcelFileDescriptor[] createSocketPair() throws IOException {
+ try {
+ final FileDescriptor fd0 = new FileDescriptor();
+ final FileDescriptor fd1 = new FileDescriptor();
+ Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
+ return new ParcelFileDescriptor[] {
+ new ParcelFileDescriptor(fd0),
+ new ParcelFileDescriptor(fd1) };
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ }
+
+ /**
+ * Create two ParcelFileDescriptors structured as a pair of sockets
+ * connected to each other. The two sockets are indistinguishable.
+ * <p>
+ * Both ends have the ability to deliver an error message through
+ * {@link #closeWithError(String)} which can be detected by the other end
+ * calling {@link #checkError(boolean)}, usually after detecting an EOF.
+ * This can also be used to detect remote crashes.
+ */
+ public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
+ try {
+ final FileDescriptor[] comm = createCommSocketPair(false);
+ final FileDescriptor fd0 = new FileDescriptor();
+ final FileDescriptor fd1 = new FileDescriptor();
+ Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
+ return new ParcelFileDescriptor[] {
+ new ParcelFileDescriptor(fd0, comm[0]),
+ new ParcelFileDescriptor(fd1, comm[1]) };
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ }
+
+ private static FileDescriptor[] createCommSocketPair(boolean blocking) throws IOException {
+ try {
+ final FileDescriptor comm1 = new FileDescriptor();
+ final FileDescriptor comm2 = new FileDescriptor();
+ Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, comm1, comm2);
+ IoUtils.setBlocking(comm1, blocking);
+ IoUtils.setBlocking(comm2, blocking);
+ return new FileDescriptor[] { comm1, comm2 };
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ }
/**
* @hide Please use createPipe() or ContentProvider.openPipeHelper().
@@ -250,21 +467,51 @@
* @return Returns the FileDescriptor associated with this object.
*/
public FileDescriptor getFileDescriptor() {
- return mFileDescriptor;
+ if (mWrapped != null) {
+ return mWrapped.getFileDescriptor();
+ } else {
+ return mFd;
+ }
}
/**
- * Return the total size of the file representing this fd, as determined
- * by stat(). Returns -1 if the fd is not a file.
+ * Return the total size of the file representing this fd, as determined by
+ * {@code stat()}. Returns -1 if the fd is not a file.
*/
- public native long getStatSize();
+ public long getStatSize() {
+ if (mWrapped != null) {
+ return mWrapped.getStatSize();
+ } else {
+ try {
+ final StructStat st = Libcore.os.fstat(mFd);
+ if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
+ return st.st_size;
+ } else {
+ return -1;
+ }
+ } catch (ErrnoException e) {
+ Log.w(TAG, "fstat() failed: " + e);
+ return -1;
+ }
+ }
+ }
/**
* This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
* and I really don't think we want it to be public.
* @hide
*/
- public native long seekTo(long pos);
+ public long seekTo(long pos) throws IOException {
+ if (mWrapped != null) {
+ return mWrapped.seekTo(pos);
+ } else {
+ try {
+ return Libcore.os.lseek(mFd, pos, SEEK_SET);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ }
+ }
/**
* Return the native fd int for this ParcelFileDescriptor. The
@@ -272,34 +519,39 @@
* through this API.
*/
public int getFd() {
- if (mClosed) {
- throw new IllegalStateException("Already closed");
+ if (mWrapped != null) {
+ return mWrapped.getFd();
+ } else {
+ if (mClosed) {
+ throw new IllegalStateException("Already closed");
+ }
+ return mFd.getInt$();
}
- return getFdNative();
}
- private native int getFdNative();
-
/**
- * Return the native fd int for this ParcelFileDescriptor and detach it
- * from the object here. You are now responsible for closing the fd in
- * native code.
+ * Return the native fd int for this ParcelFileDescriptor and detach it from
+ * the object here. You are now responsible for closing the fd in native
+ * code.
+ * <p>
+ * You should not detach when the original creator of the descriptor is
+ * expecting a reliable signal through {@link #close()} or
+ * {@link #closeWithError(String)}.
+ *
+ * @see #canDetectErrors()
*/
public int detachFd() {
- if (mClosed) {
- throw new IllegalStateException("Already closed");
- }
if (mWrapped != null) {
- int fd = mWrapped.detachFd();
- mClosed = true;
- mGuard.close();
+ return mWrapped.detachFd();
+ } else {
+ if (mClosed) {
+ throw new IllegalStateException("Already closed");
+ }
+ final int fd = getFd();
+ Parcel.clearFileDescriptor(mFd);
+ writeCommStatusAndClose(Status.DETACHED, null);
return fd;
}
- int fd = getFd();
- mClosed = true;
- mGuard.close();
- Parcel.clearFileDescriptor(mFileDescriptor);
- return fd;
}
/**
@@ -311,16 +563,176 @@
*/
@Override
public void close() throws IOException {
- if (mClosed) return;
- mClosed = true;
- mGuard.close();
-
if (mWrapped != null) {
- // If this is a proxy to another file descriptor, just call through to its
- // close method.
mWrapped.close();
} else {
- Parcel.closeFileDescriptor(mFileDescriptor);
+ closeWithStatus(Status.OK, null);
+ }
+ }
+
+ /**
+ * Close the ParcelFileDescriptor, informing any peer that an error occurred
+ * while processing. If the creator of this descriptor is not observing
+ * errors, it will close normally.
+ *
+ * @param msg describing the error; must not be null.
+ */
+ public void closeWithError(String msg) throws IOException {
+ if (mWrapped != null) {
+ mWrapped.closeWithError(msg);
+ } else {
+ if (msg == null) {
+ throw new IllegalArgumentException("Message must not be null");
+ }
+ closeWithStatus(Status.ERROR, msg);
+ }
+ }
+
+ private void closeWithStatus(int status, String msg) throws IOException {
+ if (mWrapped != null) {
+ mWrapped.closeWithStatus(status, msg);
+ } else {
+ if (mClosed) return;
+ mClosed = true;
+ mGuard.close();
+ // Status MUST be sent before closing actual descriptor
+ writeCommStatusAndClose(status, msg);
+ IoUtils.closeQuietly(mFd);
+ }
+ }
+
+ private byte[] getOrCreateStatusBuffer() {
+ if (mStatusBuf == null) {
+ mStatusBuf = new byte[MAX_STATUS];
+ }
+ return mStatusBuf;
+ }
+
+ private void writeCommStatusAndClose(int status, String msg) {
+ if (mCommFd == null) {
+ // Not reliable, or someone already sent status
+ if (msg != null) {
+ Log.w(TAG, "Unable to inform peer: " + msg);
+ }
+ return;
+ }
+
+ if (status == Status.DETACHED) {
+ Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
+ }
+
+ try {
+ try {
+ if (status != Status.SILENCE) {
+ final byte[] buf = getOrCreateStatusBuffer();
+ int writePtr = 0;
+
+ Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
+ writePtr += 4;
+
+ if (msg != null) {
+ final byte[] rawMsg = msg.getBytes();
+ final int len = Math.min(rawMsg.length, buf.length - writePtr);
+ System.arraycopy(rawMsg, 0, buf, writePtr, len);
+ writePtr += len;
+ }
+
+ Libcore.os.write(mCommFd, buf, 0, writePtr);
+ }
+ } catch (ErrnoException e) {
+ // Reporting status is best-effort
+ Log.w(TAG, "Failed to report status: " + e);
+ }
+
+ if (status != Status.SILENCE) {
+ // Since we're about to close, read off any remote status. It's
+ // okay to remember missing here.
+ mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
+ }
+
+ } finally {
+ IoUtils.closeQuietly(mCommFd);
+ mCommFd = null;
+ }
+ }
+
+ private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
+ try {
+ final int n = Libcore.os.read(comm, buf, 0, buf.length);
+ if (n == 0) {
+ // EOF means they're dead
+ return new Status(Status.DEAD);
+ } else {
+ final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
+ if (status == Status.ERROR) {
+ final String msg = new String(buf, 4, n - 4);
+ return new Status(status, msg);
+ }
+ return new Status(status);
+ }
+ } catch (ErrnoException e) {
+ if (e.errno == OsConstants.EAGAIN) {
+ // Remote is still alive, but no status written yet
+ return null;
+ } else {
+ Log.d(TAG, "Failed to read status; assuming dead: " + e);
+ return new Status(Status.DEAD);
+ }
+ }
+ }
+
+ /**
+ * Indicates if this ParcelFileDescriptor can communicate and detect remote
+ * errors/crashes.
+ *
+ * @see #checkError(boolean)
+ */
+ public boolean canDetectErrors() {
+ if (mWrapped != null) {
+ return mWrapped.canDetectErrors();
+ } else {
+ return mCommFd != null;
+ }
+ }
+
+ /**
+ * Detect and throw if the other end of a pipe or socket pair encountered an
+ * error or crashed. This allows a reader to distinguish between a valid EOF
+ * and an error/crash.
+ * <p>
+ * If this ParcelFileDescriptor is unable to detect remote errors, it will
+ * return silently.
+ *
+ * @param throwIfDetached requests that an exception be thrown if the remote
+ * side called {@link #detachFd()}. Once detached, the remote
+ * side is unable to communicate any errors through
+ * {@link #closeWithError(String)}. An application may pass true
+ * if it needs a stronger guarantee that the stream was closed
+ * normally and was not merely detached.
+ * @see #canDetectErrors()
+ */
+ public void checkError(boolean throwIfDetached) throws IOException {
+ if (mWrapped != null) {
+ mWrapped.checkError(throwIfDetached);
+ } else {
+ if (mStatus == null) {
+ if (mCommFd == null) {
+ Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
+ return;
+ }
+
+ // Try reading status; it might be null if nothing written yet.
+ // Either way, we keep comm open to write our status later.
+ mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
+ }
+
+ if (mStatus == null || mStatus.status == Status.OK
+ || (mStatus.status == Status.DETACHED && !throwIfDetached)) {
+ // No status yet, or everything is peachy!
+ return;
+ } else {
+ throw mStatus.asIOException();
+ }
}
}
@@ -330,17 +742,17 @@
* ParcelFileDescriptor.close()} for you when the stream is closed.
*/
public static class AutoCloseInputStream extends FileInputStream {
- private final ParcelFileDescriptor mFd;
+ private final ParcelFileDescriptor mPfd;
- public AutoCloseInputStream(ParcelFileDescriptor fd) {
- super(fd.getFileDescriptor());
- mFd = fd;
+ public AutoCloseInputStream(ParcelFileDescriptor pfd) {
+ super(pfd.getFileDescriptor());
+ mPfd = pfd;
}
@Override
public void close() throws IOException {
try {
- mFd.close();
+ mPfd.close();
} finally {
super.close();
}
@@ -353,17 +765,17 @@
* ParcelFileDescriptor.close()} for you when the stream is closed.
*/
public static class AutoCloseOutputStream extends FileOutputStream {
- private final ParcelFileDescriptor mFd;
+ private final ParcelFileDescriptor mPfd;
- public AutoCloseOutputStream(ParcelFileDescriptor fd) {
- super(fd.getFileDescriptor());
- mFd = fd;
+ public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
+ super(pfd.getFileDescriptor());
+ mPfd = pfd;
}
@Override
public void close() throws IOException {
try {
- mFd.close();
+ mPfd.close();
} finally {
super.close();
}
@@ -372,7 +784,11 @@
@Override
public String toString() {
- return "{ParcelFileDescriptor: " + mFileDescriptor + "}";
+ if (mWrapped != null) {
+ return mWrapped.toString();
+ } else {
+ return "{ParcelFileDescriptor: " + mFd + "}";
+ }
}
@Override
@@ -382,32 +798,20 @@
}
try {
if (!mClosed) {
- close();
+ closeWithStatus(Status.LEAKED, null);
}
} finally {
super.finalize();
}
}
- public ParcelFileDescriptor(ParcelFileDescriptor descriptor) {
- mWrapped = descriptor;
- mFileDescriptor = mWrapped.mFileDescriptor;
- mGuard.open("close");
- }
-
- /** {@hide} */
- public ParcelFileDescriptor(FileDescriptor descriptor) {
- if (descriptor == null) {
- throw new NullPointerException("descriptor must not be null");
- }
- mWrapped = null;
- mFileDescriptor = descriptor;
- mGuard.open("close");
- }
-
@Override
public int describeContents() {
- return Parcelable.CONTENTS_FILE_DESCRIPTOR;
+ if (mWrapped != null) {
+ return mWrapped.describeContents();
+ } else {
+ return Parcelable.CONTENTS_FILE_DESCRIPTOR;
+ }
}
/**
@@ -417,12 +821,22 @@
*/
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeFileDescriptor(mFileDescriptor);
- if ((flags&PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
- try {
- close();
- } catch (IOException e) {
- // Empty
+ if (mWrapped != null) {
+ mWrapped.writeToParcel(out, flags);
+ } else {
+ out.writeFileDescriptor(mFd);
+ if (mCommFd != null) {
+ out.writeInt(1);
+ out.writeFileDescriptor(mCommFd);
+ } else {
+ out.writeInt(0);
+ }
+ if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
+ try {
+ // Not a real close, so emit no status
+ closeWithStatus(Status.SILENCE, null);
+ } catch (IOException e) {
+ }
}
}
}
@@ -431,7 +845,12 @@
= new Parcelable.Creator<ParcelFileDescriptor>() {
@Override
public ParcelFileDescriptor createFromParcel(Parcel in) {
- return in.readFileDescriptor();
+ final FileDescriptor fd = in.readRawFileDescriptor();
+ FileDescriptor commChannel = null;
+ if (in.readInt() != 0) {
+ commChannel = in.readRawFileDescriptor();
+ }
+ return new ParcelFileDescriptor(fd, commChannel);
}
@Override
@@ -439,4 +858,111 @@
return new ParcelFileDescriptor[size];
}
};
+
+ /**
+ * Callback indicating that a ParcelFileDescriptor has been closed.
+ */
+ public interface OnCloseListener {
+ /**
+ * Event indicating the ParcelFileDescriptor to which this listener was
+ * attached has been closed.
+ *
+ * @param e error state, or {@code null} if closed cleanly.
+ * @param fromDetach indicates if close event was result of
+ * {@link ParcelFileDescriptor#detachFd()}. After detach the
+ * remote side may continue reading/writing to the underlying
+ * {@link FileDescriptor}, but they can no longer deliver
+ * reliable close/error events.
+ */
+ public void onClose(IOException e, boolean fromDetach);
+ }
+
+ /**
+ * Internal class representing a remote status read by
+ * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
+ */
+ private static class Status {
+ /** Special value indicating remote side died. */
+ public static final int DEAD = -2;
+ /** Special value indicating no status should be written. */
+ public static final int SILENCE = -1;
+
+ /** Remote reported that everything went better than expected. */
+ public static final int OK = 0;
+ /** Remote reported error; length and message follow. */
+ public static final int ERROR = 1;
+ /** Remote reported {@link #detachFd()} and went rogue. */
+ public static final int DETACHED = 2;
+ /** Remote reported their object was finalized. */
+ public static final int LEAKED = 3;
+
+ public final int status;
+ public final String msg;
+
+ public Status(int status) {
+ this(status, null);
+ }
+
+ public Status(int status, String msg) {
+ this.status = status;
+ this.msg = msg;
+ }
+
+ public IOException asIOException() {
+ switch (status) {
+ case DEAD:
+ return new IOException("Remote side is dead");
+ case OK:
+ return null;
+ case ERROR:
+ return new IOException("Remote error: " + msg);
+ case DETACHED:
+ return new IOException("Remote side is detached");
+ case LEAKED:
+ return new IOException("Remote side was leaked");
+ default:
+ return new IOException("Unknown status: " + status);
+ }
+ }
+ }
+
+ /**
+ * Bridge to watch for remote status, and deliver to listener. Currently
+ * requires that communication socket is <em>blocking</em>.
+ */
+ private static final class ListenerBridge extends Thread {
+ // TODO: switch to using Looper to avoid burning a thread
+
+ private FileDescriptor mCommFd;
+ private final Handler mHandler;
+
+ public ListenerBridge(FileDescriptor comm, Looper looper, final OnCloseListener listener) {
+ mCommFd = comm;
+ mHandler = new Handler(looper) {
+ @Override
+ public void handleMessage(Message msg) {
+ final Status s = (Status) msg.obj;
+ if (s.status == Status.DETACHED) {
+ listener.onClose(null, true);
+ } else if (s.status == Status.OK) {
+ listener.onClose(null, false);
+ } else {
+ listener.onClose(s.asIOException(), false);
+ }
+ }
+ };
+ }
+
+ @Override
+ public void run() {
+ try {
+ final byte[] buf = new byte[MAX_STATUS];
+ final Status status = readCommStatus(mCommFd, buf);
+ mHandler.obtainMessage(0, status).sendToTarget();
+ } finally {
+ IoUtils.closeQuietly(mCommFd);
+ mCommFd = null;
+ }
+ }
+ }
}
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index 2b805a9..22675b4 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -816,9 +816,10 @@
*/
public static Formatter formatDateRange(Context context, Formatter formatter, long startMillis,
long endMillis, int flags, String timeZone) {
- // icu4c will fall back to the locale's preferred 12/24 format,
+ // If we're being asked to format a time without being explicitly told whether to use
+ // the 12- or 24-hour clock, icu4c will fall back to the locale's preferred 12/24 format,
// but we want to fall back to the user's preference.
- if ((flags & (FORMAT_12HOUR | FORMAT_24HOUR)) == 0) {
+ if ((flags & (FORMAT_SHOW_TIME | FORMAT_12HOUR | FORMAT_24HOUR)) == FORMAT_SHOW_TIME) {
flags |= DateFormat.is24HourFormat(context) ? FORMAT_24HOUR : FORMAT_12HOUR;
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index f574efa..c874c82 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5357,6 +5357,18 @@
}
/**
+ * Returns whether layout calls on this container are currently being
+ * suppressed, due to an earlier call to {@link #suppressLayout(boolean)}.
+ *
+ * @return true if layout calls are currently suppressed, false otherwise.
+ *
+ * @hide
+ */
+ public boolean isLayoutSuppressed() {
+ return mSuppressLayout;
+ }
+
+ /**
* {@inheritDoc}
*/
@Override
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index feaab3ea..c440c7b 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -82,11 +82,16 @@
private final boolean mIsAuxIme;
/**
- * Cavert: mForceDefault must be false for production. This flag is only for test.
+ * Caveat: mForceDefault must be false for production. This flag is only for test.
*/
private final boolean mForceDefault;
/**
+ * The flag whether this IME supports ways to switch to a next input method (e.g. globe key.)
+ */
+ private final boolean mSupportsSwitchingToNextInputMethod;
+
+ /**
* Constructor.
*
* @param context The Context in which we are parsing the input method.
@@ -114,6 +119,7 @@
ServiceInfo si = service.serviceInfo;
mId = new ComponentName(si.packageName, si.name).flattenToShortString();
boolean isAuxIme = true;
+ boolean supportsSwitchingToNextInputMethod = false; // false as default
mForceDefault = false;
PackageManager pm = context.getPackageManager();
@@ -149,6 +155,9 @@
com.android.internal.R.styleable.InputMethod_settingsActivity);
isDefaultResId = sa.getResourceId(
com.android.internal.R.styleable.InputMethod_isDefault, 0);
+ supportsSwitchingToNextInputMethod = sa.getBoolean(
+ com.android.internal.R.styleable.InputMethod_supportsSwitchingToNextInputMethod,
+ false);
sa.recycle();
final int depth = parser.getDepth();
@@ -216,6 +225,7 @@
mSettingsActivityName = settingsActivityComponent;
mIsDefaultResId = isDefaultResId;
mIsAuxIme = isAuxIme;
+ mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
}
InputMethodInfo(Parcel source) {
@@ -223,6 +233,7 @@
mSettingsActivityName = source.readString();
mIsDefaultResId = source.readInt();
mIsAuxIme = source.readInt() == 1;
+ mSupportsSwitchingToNextInputMethod = source.readInt() == 1;
mService = ResolveInfo.CREATOR.createFromParcel(source);
source.readTypedList(mSubtypes, InputMethodSubtype.CREATOR);
mForceDefault = false;
@@ -254,6 +265,7 @@
mSubtypes.addAll(subtypes);
}
mForceDefault = forceDefault;
+ mSupportsSwitchingToNextInputMethod = true;
}
private static ResolveInfo buildDummyResolveInfo(String packageName, String className,
@@ -435,6 +447,14 @@
}
/**
+ * @return true if this input method supports ways to switch to a next input method.
+ * @hide
+ */
+ public boolean supportsSwitchingToNextInputMethod() {
+ return mSupportsSwitchingToNextInputMethod;
+ }
+
+ /**
* Used to package this object into a {@link Parcel}.
*
* @param dest The {@link Parcel} to be written.
@@ -446,6 +466,7 @@
dest.writeString(mSettingsActivityName);
dest.writeInt(mIsDefaultResId);
dest.writeInt(mIsAuxIme ? 1 : 0);
+ dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0);
mService.writeToParcel(dest, flags);
dest.writeTypedList(mSubtypes);
}
diff --git a/core/java/android/view/transition/Fade.java b/core/java/android/view/transition/Fade.java
index 4fd60c1..45c21d8 100644
--- a/core/java/android/view/transition/Fade.java
+++ b/core/java/android/view/transition/Fade.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -35,6 +36,7 @@
private static boolean DBG = Transition.DBG && false;
private static final String LOG_TAG = "Fade";
+ private static final String PROPNAME_ALPHA = "android:fade:alpha";
private static final String PROPNAME_SCREEN_X = "android:fade:screenX";
private static final String PROPNAME_SCREEN_Y = "android:fade:screenY";
@@ -74,20 +76,28 @@
/**
* Utility method to handle creating and running the Animator.
*/
- private Animator runAnimation(View view, float startAlpha, float endAlpha,
- Animator.AnimatorListener listener) {
+ private Animator createAnimation(View view, float startAlpha, float endAlpha,
+ AnimatorListenerAdapter listener) {
+ if (startAlpha == endAlpha) {
+ // run listener if we're noop'ing the animation, to get the end-state results now
+ if (listener != null) {
+ listener.onAnimationEnd(null);
+ }
+ return null;
+ }
final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", startAlpha, endAlpha);
if (listener != null) {
anim.addListener(listener);
+ anim.addPauseListener(listener);
}
- // TODO: Maybe extract a method into Transition to run an animation that handles the
- // duration/startDelay stuff for all subclasses.
return anim;
}
@Override
protected void captureValues(TransitionValues values, boolean start) {
super.captureValues(values, start);
+ float alpha = values.view.getAlpha();
+ values.values.put(PROPNAME_ALPHA, alpha);
int[] loc = new int[2];
values.view.getLocationOnScreen(loc);
values.values.put(PROPNAME_SCREEN_X, loc[0]);
@@ -95,6 +105,23 @@
}
@Override
+ protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ Animator animator = super.play(sceneRoot, startValues, endValues);
+ if (animator == null && startValues != null && endValues != null) {
+ boolean endVisible = isVisible(endValues);
+ final View endView = endValues.view;
+ float endAlpha = endView.getAlpha();
+ float startAlpha = (Float) startValues.values.get(PROPNAME_ALPHA);
+ if ((endVisible && startAlpha < endAlpha && (mFadingMode & Fade.IN) != 0) ||
+ (!endVisible && startAlpha > endAlpha && (mFadingMode & Fade.OUT) != 0)) {
+ animator = createAnimation(endView, startAlpha, endAlpha, null);
+ }
+ }
+ return animator;
+ }
+
+ @Override
protected Animator appear(ViewGroup sceneRoot,
TransitionValues startValues, int startVisibility,
TransitionValues endValues, int endVisibility) {
@@ -102,15 +129,11 @@
return null;
}
final View endView = endValues.view;
- endView.setAlpha(0);
- final Animator.AnimatorListener endListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Always end animation with full alpha, in case it's canceled mid-stream
- endView.setAlpha(1);
- }
- };
- return runAnimation(endView, 0, 1, endListener);
+ // if alpha < 1, just fade it in from the current value
+ if (endView.getAlpha() == 1.0f) {
+ endView.setAlpha(0);
+ }
+ return createAnimation(endView, endView.getAlpha(), 1, null);
}
@Override
@@ -129,7 +152,7 @@
}
View overlayView = null;
View viewToKeep = null;
- if (endView == null) {
+ if (endView == null || endView.getParent() == null) {
// view was removed: add the start view to the Overlay
view = startView;
overlayView = view;
@@ -167,7 +190,7 @@
final View finalOverlayView = overlayView;
final View finalViewToKeep = viewToKeep;
final ViewGroup finalSceneRoot = sceneRoot;
- final Animator.AnimatorListener endListener = new AnimatorListenerAdapter() {
+ final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
finalView.setAlpha(startAlpha);
@@ -179,8 +202,22 @@
finalSceneRoot.getOverlay().remove(finalOverlayView);
}
}
+
+ @Override
+ public void onAnimationPause(Animator animation) {
+ if (finalOverlayView != null) {
+ finalSceneRoot.getOverlay().remove(finalOverlayView);
+ }
+ }
+
+ @Override
+ public void onAnimationResume(Animator animation) {
+ if (finalOverlayView != null) {
+ finalSceneRoot.getOverlay().add(finalOverlayView);
+ }
+ }
};
- return runAnimation(view, startAlpha, endAlpha, endListener);
+ return createAnimation(view, startAlpha, endAlpha, endListener);
}
if (viewToKeep != null) {
// TODO: find a different way to do this, like just changing the view to be
@@ -193,12 +230,42 @@
final View finalOverlayView = overlayView;
final View finalViewToKeep = viewToKeep;
final ViewGroup finalSceneRoot = sceneRoot;
- final Animator.AnimatorListener endListener = new AnimatorListenerAdapter() {
+ final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
+ boolean mCanceled = false;
+ float mPausedAlpha = -1;
+
+ @Override
+ public void onAnimationPause(Animator animation) {
+ if (finalViewToKeep != null && !mCanceled) {
+ finalViewToKeep.setVisibility(finalVisibility);
+ }
+ mPausedAlpha = finalView.getAlpha();
+ finalView.setAlpha(startAlpha);
+ }
+
+ @Override
+ public void onAnimationResume(Animator animation) {
+ if (finalViewToKeep != null && !mCanceled) {
+ finalViewToKeep.setVisibility(View.VISIBLE);
+ }
+ finalView.setAlpha(mPausedAlpha);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCanceled = true;
+ if (mPausedAlpha >= 0) {
+ finalView.setAlpha(mPausedAlpha);
+ }
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
- finalView.setAlpha(startAlpha);
+ if (!mCanceled) {
+ finalView.setAlpha(startAlpha);
+ }
// TODO: restore view offset from overlay repositioning
- if (finalViewToKeep != null) {
+ if (finalViewToKeep != null && !mCanceled) {
finalViewToKeep.setVisibility(finalVisibility);
}
if (finalOverlayView != null) {
@@ -206,7 +273,7 @@
}
}
};
- return runAnimation(view, startAlpha, endAlpha, endListener);
+ return createAnimation(view, startAlpha, endAlpha, endListener);
}
return null;
}
diff --git a/core/java/android/view/transition/Move.java b/core/java/android/view/transition/Move.java
index ceda5a5..ae7d759 100644
--- a/core/java/android/view/transition/Move.java
+++ b/core/java/android/view/transition/Move.java
@@ -25,8 +25,6 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
-import android.util.ArrayMap;
-import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -42,6 +40,13 @@
private static final String PROPNAME_PARENT = "android:move:parent";
private static final String PROPNAME_WINDOW_X = "android:move:windowX";
private static final String PROPNAME_WINDOW_Y = "android:move:windowY";
+ private static String[] sTransitionProperties = {
+ PROPNAME_BOUNDS,
+ PROPNAME_PARENT,
+ PROPNAME_WINDOW_X,
+ PROPNAME_WINDOW_Y
+ };
+
int[] tempLocation = new int[2];
boolean mResizeClip = false;
boolean mReparent = false;
@@ -49,6 +54,11 @@
private static RectEvaluator sRectEvaluator = new RectEvaluator();
+ @Override
+ public String[] getTransitionProperties() {
+ return sTransitionProperties;
+ }
+
public void setResizeClip(boolean resizeClip) {
mResizeClip = resizeClip;
}
@@ -146,12 +156,33 @@
if (view.getParent() instanceof ViewGroup) {
final ViewGroup parent = (ViewGroup) view.getParent();
parent.suppressLayout(true);
- anim.addListener(new AnimatorListenerAdapter() {
+ TransitionListener transitionListener = new TransitionListenerAdapter() {
+ boolean mCanceled = false;
+
@Override
- public void onAnimationEnd(Animator animation) {
+ public void onTransitionCancel(Transition transition) {
+ parent.suppressLayout(false);
+ mCanceled = true;
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ if (!mCanceled) {
+ parent.suppressLayout(false);
+ }
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
parent.suppressLayout(false);
}
- });
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ parent.suppressLayout(true);
+ }
+ };
+ addListener(transitionListener);
}
return anim;
} else {
@@ -191,12 +222,33 @@
if (view.getParent() instanceof ViewGroup) {
final ViewGroup parent = (ViewGroup) view.getParent();
parent.suppressLayout(true);
- anim.addListener(new AnimatorListenerAdapter() {
+ TransitionListener transitionListener = new TransitionListenerAdapter() {
+ boolean mCanceled = false;
+
@Override
- public void onAnimationEnd(Animator animation) {
+ public void onTransitionCancel(Transition transition) {
+ parent.suppressLayout(false);
+ mCanceled = true;
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ if (!mCanceled) {
+ parent.suppressLayout(false);
+ }
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
parent.suppressLayout(false);
}
- });
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ parent.suppressLayout(true);
+ }
+ };
+ addListener(transitionListener);
}
anim.addListener(new AnimatorListenerAdapter() {
@Override
diff --git a/core/java/android/view/transition/Transition.java b/core/java/android/view/transition/Transition.java
index f99ddc0..0444843 100644
--- a/core/java/android/view/transition/Transition.java
+++ b/core/java/android/view/transition/Transition.java
@@ -22,7 +22,6 @@
import android.util.ArrayMap;
import android.util.Log;
import android.util.LongSparseArray;
-import android.util.Pair;
import android.util.SparseArray;
import android.view.SurfaceView;
import android.view.TextureView;
@@ -60,6 +59,8 @@
private static final String LOG_TAG = "Transition";
static final boolean DBG = false;
+ private String mName = getClass().getName();
+
long mStartDelay = -1;
long mDuration = -1;
TimeInterpolator mInterpolator = null;
@@ -69,29 +70,29 @@
private TransitionValuesMaps mEndValues = new TransitionValuesMaps();
TransitionGroup mParent = null;
+ // Per-animator information used for later canceling when future transitions overlap
+ private static ThreadLocal<ArrayMap<Animator, AnimationInfo>> sRunningAnimators =
+ new ThreadLocal<ArrayMap<Animator, AnimationInfo>>();
+
// Scene Root is set at play() time in the cloned Transition
ViewGroup mSceneRoot = null;
- // Used to carry data between setup() and play(), cleared before every scene transition
- private ArrayList<TransitionValues> mPlayStartValuesList = new ArrayList<TransitionValues>();
- private ArrayList<TransitionValues> mPlayEndValuesList = new ArrayList<TransitionValues>();
-
// Track all animators in use in case the transition gets canceled and needs to
// cancel running animators
private ArrayList<Animator> mCurrentAnimators = new ArrayList<Animator>();
// Number of per-target instances of this Transition currently running. This count is
- // determined by calls to startTransition() and endTransition()
+ // determined by calls to start() and end()
int mNumInstances = 0;
-
+ // Whether this transition is currently paused, due to a call to pause()
+ boolean mPaused = false;
// The set of listeners to be sent transition lifecycle events.
ArrayList<TransitionListener> mListeners = null;
// The set of animators collected from calls to play(), to be run in runAnimations()
- ArrayMap<Pair<TransitionValues, TransitionValues>, Animator> mAnimatorMap =
- new ArrayMap<Pair<TransitionValues, TransitionValues>, Animator>();
+ ArrayList<Animator> mAnimators = new ArrayList<Animator>();
/**
* Constructs a Transition object with no target objects. A transition with
@@ -115,6 +116,14 @@
return this;
}
+ /**
+ * Returns the duration set on this transition. If no duration has been set,
+ * the returned value will be negative, indicating that resulting animators will
+ * retain their own durations.
+ *
+ * @return The duration set on this transition, if one has been set, otherwise
+ * returns a negative number.
+ */
public long getDuration() {
return mDuration;
}
@@ -131,6 +140,14 @@
mStartDelay = startDelay;
}
+ /**
+ * Returns the startDelay set on this transition. If no startDelay has been set,
+ * the returned value will be negative, indicating that resulting animators will
+ * retain their own startDelays.
+ *
+ * @return The startDealy set on this transition, if one has been set, otherwise
+ * returns a negative number.
+ */
public long getStartDelay() {
return mStartDelay;
}
@@ -147,11 +164,44 @@
mInterpolator = interpolator;
}
+ /**
+ * Returns the interpolator set on this transition. If no interpolator has been set,
+ * the returned value will be null, indicating that resulting animators will
+ * retain their own interpolators.
+ *
+ * @return The interpolator set on this transition, if one has been set, otherwise
+ * returns null.
+ */
public TimeInterpolator getInterpolator() {
return mInterpolator;
}
/**
+ * Returns the set of property names used stored in the {@link TransitionValues}
+ * object passed into {@link #captureValues(TransitionValues, boolean)} that
+ * this transition cares about for the purposes of canceling overlapping animations.
+ * When any transition is started on a given scene root, all transitions
+ * currently running on that same scene root are checked to see whether the
+ * properties on which they based their animations agree with the end values of
+ * the same properties in the new transition. If the end values are not equal,
+ * then the old animation is canceled since the new transition will start a new
+ * animation to these new values. If the values are equal, the old animation is
+ * allowed to continue and no new animation is started for that transition.
+ *
+ * <p>A transition does not need to override this method. However, not doing so
+ * will mean that the cancellation logic outlined in the previous paragraph
+ * will be skipped for that transition, possibly leading to artifacts as
+ * old transitions and new transitions on the same targets run in parallel,
+ * animating views toward potentially different end values.</p>
+ *
+ * @return An array of property names as described in the class documentation for
+ * {@link TransitionValues}. The default implementation returns <code>null</code>.
+ */
+ public String[] getTransitionProperties() {
+ return null;
+ }
+
+ /**
* This method is called by the transition's parent (all the way up to the
* topmost Transition in the hierarchy) with the sceneRoot and start/end
* values that the transition may need to set up initial target values
@@ -210,8 +260,6 @@
if (DBG) {
Log.d(LOG_TAG, "play() for " + this);
}
- mPlayStartValuesList.clear();
- mPlayEndValuesList.clear();
ArrayMap<View, TransitionValues> endCopy =
new ArrayMap<View, TransitionValues>(endValues.viewValues);
SparseArray<TransitionValues> endIdCopy =
@@ -316,6 +364,7 @@
startValuesList.add(start);
endValuesList.add(end);
}
+ ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
for (int i = 0; i < startValuesList.size(); ++i) {
TransitionValues start = startValuesList.get(i);
TransitionValues end = endValuesList.get(i);
@@ -345,14 +394,46 @@
// TODO: what to do about targetIds and itemIds?
Animator animator = play(sceneRoot, start, end);
if (animator != null) {
- mAnimatorMap.put(new Pair(start, end), animator);
- // Note: we've already done the check against targetIDs in these lists
- mPlayStartValuesList.add(start);
- mPlayEndValuesList.add(end);
+ // Save animation info for future cancellation purposes
+ View view = null;
+ TransitionValues infoValues = null;
+ if (end != null) {
+ view = end.view;
+ String[] properties = getTransitionProperties();
+ if (view != null && properties != null && properties.length > 0) {
+ infoValues = new TransitionValues();
+ infoValues.view = view;
+ TransitionValues newValues = endValues.viewValues.get(view);
+ if (newValues != null) {
+ for (int j = 0; j < properties.length; ++j) {
+ infoValues.values.put(properties[j],
+ newValues.values.get(properties[j]));
+ }
+ }
+ int numExistingAnims = runningAnimators.size();
+ for (int j = 0; j < numExistingAnims; ++j) {
+ Animator anim = runningAnimators.keyAt(j);
+ AnimationInfo info = runningAnimators.get(anim);
+ if (info.values != null && info.view == view &&
+ ((info.name == null && getName() == null) ||
+ info.name.equals(getName()))) {
+ if (info.values.equals(infoValues)) {
+ // Favor the old animator
+ animator = null;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ view = (start != null) ? start.view : null;
+ }
+ if (animator != null) {
+ AnimationInfo info = new AnimationInfo(view, getName(), infoValues);
+ runningAnimators.put(animator, info);
+ mAnimators.add(animator);
+ }
}
- } else if (DBG) {
- View view = (end != null) ? end.view : start.view;
- Log.d(LOG_TAG, " No change for view " + view);
}
}
}
@@ -389,6 +470,15 @@
return false;
}
+ private static ArrayMap<Animator, AnimationInfo> getRunningAnimators() {
+ ArrayMap<Animator, AnimationInfo> runningAnimators = sRunningAnimators.get();
+ if (runningAnimators == null) {
+ runningAnimators = new ArrayMap<Animator, AnimationInfo>();
+ sRunningAnimators.set(runningAnimators);
+ }
+ return runningAnimators;
+ }
+
/**
* This is called internally once all animations have been set up by the
* transition hierarchy. \
@@ -396,28 +486,27 @@
* @hide
*/
protected void runAnimations() {
- if (DBG && mPlayStartValuesList.size() > 0) {
- Log.d(LOG_TAG, "runAnimations (" + mPlayStartValuesList.size() + ") on " + this);
+ if (DBG) {
+ Log.d(LOG_TAG, "runAnimations() on " + this);
}
- startTransition();
- // Now walk the list of TransitionValues, calling play for each pair
- for (int i = 0; i < mPlayStartValuesList.size(); ++i) {
- TransitionValues start = mPlayStartValuesList.get(i);
- TransitionValues end = mPlayEndValuesList.get(i);
- Animator anim = mAnimatorMap.get(new Pair(start, end));
+ start();
+ ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+ // Now start every Animator that was previously created for this transition in play()
+ for (Animator anim : mAnimators) {
if (DBG) {
Log.d(LOG_TAG, " anim: " + anim);
}
- startTransition();
- runAnimator(anim);
+ if (runningAnimators.containsKey(anim)) {
+ start();
+ runAnimator(anim, runningAnimators);
+ }
}
- mPlayStartValuesList.clear();
- mPlayEndValuesList.clear();
- mAnimatorMap.clear();
- endTransition();
+ mAnimators.clear();
+ end();
}
- private void runAnimator(Animator animator) {
+ private void runAnimator(Animator animator,
+ final ArrayMap<Animator, AnimationInfo> runningAnimators) {
if (animator != null) {
// TODO: could be a single listener instance for all of them since it uses the param
animator.addListener(new AnimatorListenerAdapter() {
@@ -427,6 +516,7 @@
}
@Override
public void onAnimationEnd(Animator animation) {
+ runningAnimators.remove(animation);
mCurrentAnimators.remove(animation);
}
});
@@ -691,11 +781,112 @@
}
/**
+ * Pauses this transition, sending out calls to {@link
+ * TransitionListener#onTransitionPause(Transition)} to all listeners
+ * and pausing all running animators started by this transition.
+ *
+ * @hide
+ */
+ public void pause() {
+ ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+ int numOldAnims = runningAnimators.size();
+ for (int i = numOldAnims - 1; i >= 0; i--) {
+ Animator anim = runningAnimators.keyAt(i);
+ anim.pause();
+ }
+ if (mListeners != null && mListeners.size() > 0) {
+ ArrayList<TransitionListener> tmpListeners =
+ (ArrayList<TransitionListener>) mListeners.clone();
+ int numListeners = tmpListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ tmpListeners.get(i).onTransitionPause(this);
+ }
+ }
+ mPaused = true;
+ }
+
+ /**
+ * Resumes this transition, sending out calls to {@link
+ * TransitionListener#onTransitionPause(Transition)} to all listeners
+ * and pausing all running animators started by this transition.
+ *
+ * @hide
+ */
+ public void resume() {
+ if (mPaused) {
+ ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+ int numOldAnims = runningAnimators.size();
+ for (int i = numOldAnims - 1; i >= 0; i--) {
+ Animator anim = runningAnimators.keyAt(i);
+ anim.resume();
+ }
+ if (mListeners != null && mListeners.size() > 0) {
+ ArrayList<TransitionListener> tmpListeners =
+ (ArrayList<TransitionListener>) mListeners.clone();
+ int numListeners = tmpListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ tmpListeners.get(i).onTransitionResume(this);
+ }
+ }
+ mPaused = false;
+ }
+ }
+
+ /**
* Called by TransitionManager to play the transition. This calls
* play() to set things up and create all of the animations and then
* runAnimations() to actually start the animations.
*/
void playTransition(ViewGroup sceneRoot) {
+ ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+ int numOldAnims = runningAnimators.size();
+ for (int i = numOldAnims - 1; i >= 0; i--) {
+ Animator anim = runningAnimators.keyAt(i);
+ if (anim != null) {
+ anim.resume();
+ AnimationInfo oldInfo = runningAnimators.get(anim);
+ if (oldInfo != null) {
+ boolean cancel = false;
+ TransitionValues oldValues = oldInfo.values;
+ View oldView = oldInfo.view;
+ TransitionValues newValues = mEndValues.viewValues != null ?
+ mEndValues.viewValues.get(oldView) : null;
+ if (oldValues == null || newValues == null) {
+ if (oldValues != null || newValues != null) {
+ cancel = true;
+ }
+ } else {
+ for (String key : oldValues.values.keySet()) {
+ Object oldValue = oldValues.values.get(key);
+ Object newValue = newValues.values.get(key);
+ if ((oldValue == null && newValue != null) ||
+ (oldValue != null && !oldValue.equals(newValue))) {
+ cancel = true;
+ if (DBG) {
+ Log.d(LOG_TAG, "Transition.play: oldValue != newValue for " +
+ key + ": old, new = " + oldValue + ", " + newValue);
+ }
+ break;
+ }
+ }
+ }
+ if (cancel) {
+ if (anim.isRunning() || anim.isStarted()) {
+ if (DBG) {
+ Log.d(LOG_TAG, "Canceling anim " + anim);
+ }
+ anim.cancel();
+ } else {
+ if (DBG) {
+ Log.d(LOG_TAG, "removing anim from info list: " + anim);
+ }
+ runningAnimators.remove(anim);
+ }
+ }
+ }
+ }
+ }
+
// setup() must be called on entire transition hierarchy and set of views
// before calling play() on anything; every transition needs a chance to set up
// target views appropriately before transitions begin running
@@ -707,7 +898,7 @@
* This is a utility method used by subclasses to handle standard parts of
* setting up and running an Animator: it sets the {@link #getDuration()
* duration} and the {@link #getStartDelay() startDelay}, starts the
- * animation, and, when the animator ends, calls {@link #endTransition()}.
+ * animation, and, when the animator ends, calls {@link #end()}.
*
* @param animator The Animator to be run during this transition.
*
@@ -716,7 +907,7 @@
protected void animate(Animator animator) {
// TODO: maybe pass auto-end as a boolean parameter?
if (animator == null) {
- endTransition();
+ end();
} else {
if (getDuration() >= 0) {
animator.setDuration(getDuration());
@@ -730,7 +921,7 @@
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- endTransition();
+ end();
animation.removeListener(this);
}
});
@@ -739,39 +930,14 @@
}
/**
- * Subclasses may override to receive notice of when the transition starts.
- * This is equivalent to listening for the
- * {@link TransitionListener#onTransitionStart(Transition)} callback.
- */
- protected void onTransitionStart() {
- }
-
- /**
- * Subclasses may override to receive notice of when the transition is
- * canceled. This is equivalent to listening for the
- * {@link TransitionListener#onTransitionCancel(Transition)} callback.
- */
- protected void onTransitionCancel() {
- }
-
- /**
- * Subclasses may override to receive notice of when the transition ends.
- * This is equivalent to listening for the
- * {@link TransitionListener#onTransitionEnd(Transition)} callback.
- */
- protected void onTransitionEnd() {
- }
-
- /**
* This method is called automatically by the transition and
* TransitionGroup classes prior to a Transition subclass starting;
* subclasses should not need to call it directly.
*
* @hide
*/
- protected void startTransition() {
+ protected void start() {
if (mNumInstances == 0) {
- onTransitionStart();
if (mListeners != null && mListeners.size() > 0) {
ArrayList<TransitionListener> tmpListeners =
(ArrayList<TransitionListener>) mListeners.clone();
@@ -790,15 +956,14 @@
* a transition did nothing (returned a null Animator from
* {@link Transition#play(ViewGroup, TransitionValues,
* TransitionValues)}) or because the transition returned a valid
- * Animator and endTransition() was called in the onAnimationEnd()
+ * Animator and end() was called in the onAnimationEnd()
* callback of the AnimatorListener.
*
* @hide
*/
- protected void endTransition() {
+ protected void end() {
--mNumInstances;
if (mNumInstances == 0) {
- onTransitionEnd();
if (mListeners != null && mListeners.size() > 0) {
ArrayList<TransitionListener> tmpListeners =
(ArrayList<TransitionListener>) mListeners.clone();
@@ -828,7 +993,7 @@
* This method cancels a transition that is currently running.
* Implementation TBD.
*/
- protected void cancelTransition() {
+ protected void cancel() {
// TODO: how does this work with instances?
// TODO: this doesn't actually do *anything* yet
int numAnimators = mCurrentAnimators.size();
@@ -836,7 +1001,6 @@
Animator animator = mCurrentAnimators.get(i);
animator.cancel();
}
- onTransitionCancel();
if (mListeners != null && mListeners.size() > 0) {
ArrayList<TransitionListener> tmpListeners =
(ArrayList<TransitionListener>) mListeners.clone();
@@ -901,11 +1065,28 @@
Transition clone = null;
try {
clone = (Transition) super.clone();
+ clone.mAnimators = new ArrayList<Animator>();
} catch (CloneNotSupportedException e) {}
return clone;
}
+ /**
+ * Returns the name of this Transition. This name is used internally to distinguish
+ * between different transitions to determine when interrupting transitions overlap.
+ * For example, a Move running on the same target view as another Move should determine
+ * whether the old transition is animating to different end values and should be
+ * canceled in favor of the new transition.
+ *
+ * <p>By default, a Transition's name is simply the value of {@link Class#getName()},
+ * but subclasses are free to override and return something different.</p>
+ *
+ * @return The name of this transition.
+ */
+ public String getName() {
+ return mName;
+ }
+
String toString(String indent) {
String result = indent + getClass().getSimpleName() + "@" +
Integer.toHexString(hashCode()) + ": ";
@@ -943,8 +1124,7 @@
/**
* A transition listener receives notifications from a transition.
- * Notifications indicate transition lifecycle events: when the transition
- * begins, ends, or is canceled.
+ * Notifications indicate transition lifecycle events.
*/
public static interface TransitionListener {
/**
@@ -957,7 +1137,7 @@
/**
* Notification about the end of the transition. Canceled transitions
* will always notify listeners of both the cancellation and end
- * events. That is, {@link #onTransitionEnd()} is always called,
+ * events. That is, {@link #onTransitionEnd(Transition)} is always called,
* regardless of whether the transition was canceled or played
* through to completion.
*
@@ -967,10 +1147,38 @@
/**
* Notification about the cancellation of the transition.
+ * Note that cancel() may be called by a parent {@link TransitionGroup} on
+ * a child transition which has not yet started. This allows the child
+ * transition to restore state on target objects which was set at
+ * {@link #play(android.view.ViewGroup, TransitionValues, TransitionValues)
+ * play()} time.
*
* @param transition The transition which was canceled.
*/
void onTransitionCancel(Transition transition);
+
+ /**
+ * Notification when a transition is paused.
+ * Note that play() may be called by a parent {@link TransitionGroup} on
+ * a child transition which has not yet started. This allows the child
+ * transition to restore state on target objects which was set at
+ * {@link #play(android.view.ViewGroup, TransitionValues, TransitionValues)
+ * play()} time.
+ *
+ * @param transition The transition which was paused.
+ */
+ void onTransitionPause(Transition transition);
+
+ /**
+ * Notification when a transition is resumed.
+ * Note that resume() may be called by a parent {@link TransitionGroup} on
+ * a child transition which has not yet started. This allows the child
+ * transition to restore state which may have changed in an earlier call
+ * to {@link #onTransitionPause(Transition)}.
+ *
+ * @param transition The transition which was resumed.
+ */
+ void onTransitionResume(Transition transition);
}
/**
@@ -991,6 +1199,32 @@
@Override
public void onTransitionCancel(Transition transition) {
}
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ }
}
+ /**
+ * Holds information about each animator used when a new transition starts
+ * while other transitions are still running to determine whether a running
+ * animation should be canceled or a new animation noop'd. The structure holds
+ * information about the state that an animation is going to, to be compared to
+ * end state of a new animation.
+ */
+ private static class AnimationInfo {
+ View view;
+ String name;
+ TransitionValues values;
+
+ AnimationInfo(View view, String name, TransitionValues values) {
+ this.view = view;
+ this.name = name;
+ this.values = values;
+ }
+ }
}
diff --git a/core/java/android/view/transition/TransitionGroup.java b/core/java/android/view/transition/TransitionGroup.java
index 313e33e..b3bacde 100644
--- a/core/java/android/view/transition/TransitionGroup.java
+++ b/core/java/android/view/transition/TransitionGroup.java
@@ -164,7 +164,7 @@
@Override
public void onTransitionStart(Transition transition) {
if (!mTransitionGroup.mStarted) {
- mTransitionGroup.startTransition();
+ mTransitionGroup.start();
mTransitionGroup.mStarted = true;
}
}
@@ -175,7 +175,7 @@
if (mTransitionGroup.mCurrentListeners == 0) {
// All child trans
mTransitionGroup.mStarted = false;
- mTransitionGroup.endTransition();
+ mTransitionGroup.end();
}
transition.removeListener(this);
}
@@ -233,12 +233,32 @@
}
}
+ /** @hide */
@Override
- protected void cancelTransition() {
- super.cancelTransition();
+ public void pause() {
+ super.pause();
int numTransitions = mTransitions.size();
for (int i = 0; i < numTransitions; ++i) {
- mTransitions.get(i).cancelTransition();
+ mTransitions.get(i).pause();
+ }
+ }
+
+ /** @hide */
+ @Override
+ public void resume() {
+ super.resume();
+ int numTransitions = mTransitions.size();
+ for (int i = 0; i < numTransitions; ++i) {
+ mTransitions.get(i).resume();
+ }
+ }
+
+ @Override
+ protected void cancel() {
+ super.cancel();
+ int numTransitions = mTransitions.size();
+ for (int i = 0; i < numTransitions; ++i) {
+ mTransitions.get(i).cancel();
}
}
diff --git a/core/java/android/view/transition/TransitionManager.java b/core/java/android/view/transition/TransitionManager.java
index 7836268..3cb6f68 100644
--- a/core/java/android/view/transition/TransitionManager.java
+++ b/core/java/android/view/transition/TransitionManager.java
@@ -18,6 +18,7 @@
import android.util.ArrayMap;
import android.util.Log;
+import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -45,8 +46,8 @@
ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<Scene, Transition>();
ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions =
new ArrayMap<Scene, ArrayMap<Scene, Transition>>();
- static ArrayMap<ViewGroup, Transition> sRunningTransitions =
- new ArrayMap<ViewGroup, Transition>();
+ private static ThreadLocal<ArrayMap<ViewGroup, ArrayList<Transition>>> sRunningTransitions =
+ new ThreadLocal<ArrayMap<ViewGroup, ArrayList<Transition>>>();
private static ArrayList<ViewGroup> sPendingTransitions = new ArrayList<ViewGroup>();
@@ -160,6 +161,16 @@
sceneChangeRunTransition(sceneRoot, transitionClone);
}
+ private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() {
+ ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
+ sRunningTransitions.get();
+ if (runningTransitions == null) {
+ runningTransitions = new ArrayMap<ViewGroup, ArrayList<Transition>>();
+ sRunningTransitions.set(runningTransitions);
+ }
+ return runningTransitions;
+ }
+
private static void sceneChangeRunTransition(final ViewGroup sceneRoot,
final Transition transition) {
if (transition != null) {
@@ -169,16 +180,31 @@
sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
sPendingTransitions.remove(sceneRoot);
// Add to running list, handle end to remove it
- sRunningTransitions.put(sceneRoot, transition);
+ final ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
+ getRunningTransitions();
+ ArrayList<Transition> currentTransitions = runningTransitions.get(sceneRoot);
+ if (currentTransitions == null) {
+ currentTransitions = new ArrayList<Transition>();
+ runningTransitions.put(sceneRoot, currentTransitions);
+ }
+ currentTransitions.add(transition);
transition.addListener(new Transition.TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
- sRunningTransitions.remove(sceneRoot);
+ ArrayList<Transition> currentTransitions =
+ runningTransitions.get(sceneRoot);
+ currentTransitions.remove(transition);
}
});
transition.captureValues(sceneRoot, false);
transition.playTransition(sceneRoot);
- return true;
+
+ // Returning false from onPreDraw() skips the current frame. This is
+ // necessary to avoid artifacts caused by resetting target views
+ // to their proper end states for capturing. Waiting until the next
+ // frame to draw allows these views to have their mid-transition
+ // values set on them again and avoid artifacts.
+ return false;
}
});
}
@@ -187,16 +213,18 @@
private static void sceneChangeSetup(ViewGroup sceneRoot, Transition transition) {
// Capture current values
- Transition runningTransition = sRunningTransitions.get(sceneRoot);
+ ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot);
+
+ if (runningTransitions != null && runningTransitions.size() > 0) {
+ for (Transition runningTransition : runningTransitions) {
+ runningTransition.pause();
+ }
+ }
if (transition != null) {
transition.captureValues(sceneRoot, true);
}
- if (runningTransition != null) {
- runningTransition.cancelTransition();
- }
-
// Notify previous scene that it is being exited
Scene previousScene = sceneRoot.getCurrentScene();
if (previousScene != null) {
diff --git a/core/java/android/view/transition/Visibility.java b/core/java/android/view/transition/Visibility.java
index 6d39ab6..96ea044 100644
--- a/core/java/android/view/transition/Visibility.java
+++ b/core/java/android/view/transition/Visibility.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewOverlay;
import android.view.ViewParent;
/**
@@ -38,6 +39,10 @@
private static final String PROPNAME_VISIBILITY = "android:visibility:visibility";
private static final String PROPNAME_PARENT = "android:visibility:parent";
+ private static String[] sTransitionProperties = {
+ PROPNAME_VISIBILITY,
+ PROPNAME_PARENT,
+ };
private static class VisibilityInfo {
boolean visibilityChange;
@@ -52,12 +57,42 @@
private VisibilityInfo mTmpVisibilityInfo = new VisibilityInfo();
@Override
+ public String[] getTransitionProperties() {
+ return sTransitionProperties;
+ }
+
+ @Override
protected void captureValues(TransitionValues values, boolean start) {
int visibility = values.view.getVisibility();
values.values.put(PROPNAME_VISIBILITY, visibility);
values.values.put(PROPNAME_PARENT, values.view.getParent());
}
+ /**
+ * Returns whether the view is 'visible' according to the given values
+ * object. This is determined by testing the same properties in the values
+ * object that are used to determine whether the object is appearing or
+ * disappearing in the {@link
+ * #play(android.view.ViewGroup, TransitionValues, TransitionValues)}
+ * method. This method can be called by, for example, subclasses that want
+ * to know whether the object is visible in the same way that Visibility
+ * determines it for the actual animation.
+ *
+ * @param values The TransitionValues object that holds the information by
+ * which visibility is determined.
+ * @return True if the view reference by <code>values</code> is visible,
+ * false otherwise.
+ */
+ public boolean isVisible(TransitionValues values) {
+ if (values == null) {
+ return false;
+ }
+ int visibility = (Integer) values.values.get(PROPNAME_VISIBILITY);
+ View parent = (View) values.values.get(PROPNAME_PARENT);
+
+ return visibility == View.VISIBLE && parent != null;
+ }
+
private boolean isHierarchyVisibilityChanging(ViewGroup sceneRoot, ViewGroup view) {
if (view == sceneRoot) {
@@ -197,5 +232,4 @@
TransitionValues endValues, int endVisibility) {
return null;
}
-
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 07198c75..285e6f2 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1211,13 +1211,19 @@
}
/**
- * Enables fast scrolling by letting the user quickly scroll through lists by
- * dragging the fast scroll thumb. The adapter attached to the list may want
- * to implement {@link SectionIndexer} if it wishes to display alphabet preview and
- * jump between sections of the list.
+ * Specifies whether fast scrolling is enabled or disabled.
+ * <p>
+ * When fast scrolling is enabled, the user can quickly scroll through lists
+ * by dragging the fast scroll thumb.
+ * <p>
+ * If the adapter backing this list implements {@link SectionIndexer}, the
+ * fast scroller will display section header previews as the user scrolls.
+ * Additionally, the user will be able to quickly jump between sections by
+ * tapping along the length of the scroll bar.
+ *
* @see SectionIndexer
* @see #isFastScrollEnabled()
- * @param enabled whether or not to enable fast scrolling
+ * @param enabled true to enable fast scrolling, false otherwise
*/
public void setFastScrollEnabled(final boolean enabled) {
if (mFastScrollEnabled != enabled) {
@@ -1252,13 +1258,16 @@
}
/**
- * Set whether or not the fast scroller should always be shown in place of the
- * standard scrollbars. Fast scrollers shown in this way will not fade out and will
- * be a permanent fixture within the list. Best combined with an inset scroll bar style
- * that will ensure enough padding. This will enable fast scrolling if it is not
+ * Set whether or not the fast scroller should always be shown in place of
+ * the standard scroll bars. This will enable fast scrolling if it is not
* already enabled.
+ * <p>
+ * Fast scrollers shown in this way will not fade out and will be a
+ * permanent fixture within the list. This is best combined with an inset
+ * scroll bar style to ensure the scroll bar does not overlap content.
*
- * @param alwaysShow true if the fast scroller should always be displayed.
+ * @param alwaysShow true if the fast scroller should always be displayed,
+ * false otherwise
* @see #setScrollBarStyle(int)
* @see #setFastScrollEnabled(boolean)
*/
@@ -1297,10 +1306,9 @@
}
/**
- * Returns true if the fast scroller is set to always show on this view rather than
- * fade out when not in use.
+ * Returns true if the fast scroller is set to always show on this view.
*
- * @return true if the fast scroller will always show.
+ * @return true if the fast scroller will always show
* @see #setFastScrollAlwaysVisible(boolean)
*/
public boolean isFastScrollAlwaysVisible() {
@@ -1316,7 +1324,8 @@
}
/**
- * Returns the current state of the fast scroll feature.
+ * Returns true if the fast scroller is enabled.
+ *
* @see #setFastScrollEnabled(boolean)
* @return true if fast scroll is enabled, false otherwise
*/
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 414c318..2b4e520 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -16,6 +16,9 @@
package android.widget;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Rect;
@@ -23,6 +26,7 @@
import android.os.Handler;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.IntProperty;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -31,6 +35,7 @@
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.ViewParent;
+import android.view.animation.AccelerateDecelerateInterpolator;
import java.util.Locale;
@@ -956,6 +961,33 @@
}
/**
+ * Receives motion events forwarded from a source view. This is used
+ * internally to implement support for drag-to-open.
+ *
+ * @param src view from which the event was forwarded
+ * @param srcEvent forwarded motion event in source-local coordinates
+ * @param activePointerId id of the pointer that activated forwarding
+ * @return whether the event was handled
+ * @hide
+ */
+ public boolean onForwardedEvent(View src, MotionEvent srcEvent, int activePointerId) {
+ final DropDownListView dst = mDropDownList;
+ if (dst == null || !dst.isShown()) {
+ return false;
+ }
+
+ // Convert event to local coordinates.
+ final MotionEvent dstEvent = MotionEvent.obtainNoHistory(srcEvent);
+ src.toGlobalMotionEvent(dstEvent);
+ dst.toLocalMotionEvent(dstEvent);
+
+ // Forward converted event, then recycle it.
+ final boolean handled = dst.onForwardedEvent(dstEvent, activePointerId);
+ dstEvent.recycle();
+ return handled;
+ }
+
+ /**
* <p>Builds the popup window's content and returns the height the popup
* should have. Returns -1 when the content already exists.</p>
*
@@ -1130,6 +1162,27 @@
*/
private static class DropDownListView extends ListView {
private static final String TAG = ListPopupWindow.TAG + ".DropDownListView";
+
+ /** Duration in milliseconds of the drag-to-open click animation. */
+ private static final long CLICK_ANIM_DURATION = 150;
+
+ /** Target alpha value for drag-to-open click animation. */
+ private static final int CLICK_ANIM_ALPHA = 0x80;
+
+ /** Wrapper around Drawable's <code>alpha</code> property. */
+ private static final IntProperty<Drawable> DRAWABLE_ALPHA =
+ new IntProperty<Drawable>("alpha") {
+ @Override
+ public void setValue(Drawable object, int value) {
+ object.setAlpha(value);
+ }
+
+ @Override
+ public Integer get(Drawable object) {
+ return object.getAlpha();
+ }
+ };
+
/*
* WARNING: This is a workaround for a touch mode issue.
*
@@ -1165,6 +1218,12 @@
*/
private boolean mHijackFocus;
+ /** Whether to force drawing of the pressed state selector. */
+ private boolean mDrawsInPressedState;
+
+ /** Current drag-to-open click animation, if any. */
+ private Animator mClickAnimation;
+
/**
* <p>Creates a new list view wrapper.</p>
*
@@ -1178,6 +1237,119 @@
}
/**
+ * Handles forwarded events.
+ *
+ * @param activePointerId id of the pointer that activated forwarding
+ * @return whether the event was handled
+ */
+ public boolean onForwardedEvent(MotionEvent event, int activePointerId) {
+ boolean handledEvent = true;
+ boolean clearPressedItem = false;
+
+ final int actionMasked = event.getActionMasked();
+ switch (actionMasked) {
+ case MotionEvent.ACTION_CANCEL:
+ handledEvent = false;
+ break;
+ case MotionEvent.ACTION_UP:
+ handledEvent = false;
+ // $FALL-THROUGH$
+ case MotionEvent.ACTION_MOVE:
+ final int activeIndex = event.findPointerIndex(activePointerId);
+ if (activeIndex < 0) {
+ handledEvent = false;
+ break;
+ }
+
+ final int x = (int) event.getX(activeIndex);
+ final int y = (int) event.getY(activeIndex);
+ final int position = pointToPosition(x, y);
+ if (position == INVALID_POSITION) {
+ clearPressedItem = true;
+ break;
+ }
+
+ final View child = getChildAt(position - getFirstVisiblePosition());
+ setPressedItem(child, position);
+ handledEvent = true;
+
+ if (actionMasked == MotionEvent.ACTION_UP) {
+ clickPressedItem(child, position);
+ }
+ break;
+ }
+
+ // Failure to handle the event cancels forwarding.
+ if (!handledEvent || clearPressedItem) {
+ clearPressedItem();
+ }
+
+ return handledEvent;
+ }
+
+ /**
+ * Starts an alpha animation on the selector. When the animation ends,
+ * the list performs a click on the item.
+ */
+ private void clickPressedItem(final View child, final int position) {
+ final long id = getItemIdAtPosition(position);
+ final Animator anim = ObjectAnimator.ofInt(
+ mSelector, DRAWABLE_ALPHA, 0xFF, CLICK_ANIM_ALPHA, 0xFF);
+ anim.setDuration(CLICK_ANIM_DURATION);
+ anim.setInterpolator(new AccelerateDecelerateInterpolator());
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ performItemClick(child, position, id);
+ }
+ });
+ anim.start();
+
+ if (mClickAnimation != null) {
+ mClickAnimation.cancel();
+ }
+ mClickAnimation = anim;
+ }
+
+ private void clearPressedItem() {
+ mDrawsInPressedState = false;
+ setPressed(false);
+ updateSelectorState();
+
+ if (mClickAnimation != null) {
+ mClickAnimation.cancel();
+ mClickAnimation = null;
+ }
+ }
+
+ private void setPressedItem(View child, int position) {
+ mDrawsInPressedState = true;
+
+ // Ordering is essential. First update the pressed state and layout
+ // the children. This will ensure the selector actually gets drawn.
+ setPressed(true);
+ layoutChildren();
+
+ // Ensure that keyboard focus starts from the last touched position.
+ setSelectedPositionInt(position);
+ positionSelector(position, child);
+
+ // Refresh the drawable state to reflect the new pressed state,
+ // which will also update the selector state.
+ refreshDrawableState();
+
+ if (mClickAnimation != null) {
+ mClickAnimation.cancel();
+ mClickAnimation = null;
+ }
+ }
+
+ @Override
+ boolean touchModeDrawsInPressedState() {
+ return mDrawsInPressedState || super.touchModeDrawsInPressedState();
+ }
+
+ /**
* <p>Avoids jarring scrolling effect by ensuring that list elements
* made of a text view fit on a single line.</p>
*
diff --git a/core/java/android/widget/SectionIndexer.java b/core/java/android/widget/SectionIndexer.java
index a1c71f4..f6333d1 100644
--- a/core/java/android/widget/SectionIndexer.java
+++ b/core/java/android/widget/SectionIndexer.java
@@ -17,38 +17,62 @@
package android.widget;
/**
- * Interface that should be implemented on Adapters to enable fast scrolling
- * in an {@link AbsListView} between sections of the list. A section is a group of list items
- * to jump to that have something in common. For example, they may begin with the
- * same letter or they may be songs from the same artist. ExpandableListAdapters that
- * consider groups and sections as synonymous should account for collapsed groups and return
- * an appropriate section/position.
+ * Interface that may implemented on {@link Adapter}s to enable fast scrolling
+ * between sections of an {@link AbsListView}.
+ * <p>
+ * A section is a group of list items that have something in common. For
+ * example, they may begin with the same letter or they may be songs from the
+ * same artist.
+ * <p>
+ * {@link ExpandableListAdapter}s that consider groups and sections as
+ * synonymous should account for collapsed groups and return an appropriate
+ * section/position.
+ *
+ * @see AbsListView#setFastScrollEnabled(boolean)
*/
public interface SectionIndexer {
/**
- * This provides the list view with an array of section objects. In the simplest
- * case these are Strings, each containing one letter of the alphabet.
- * They could be more complex objects that indicate the grouping for the adapter's
- * consumption. The list view will call toString() on the objects to get the
- * preview letter to display while scrolling.
- * @return the array of objects that indicate the different sections of the list.
+ * Returns an array of objects representing sections of the list. The
+ * returned array and its contents should be non-null.
+ * <p>
+ * The list view will call toString() on the objects to get the preview text
+ * to display while scrolling. For example, an adapter may return an array
+ * of Strings representing letters of the alphabet. Or, it may return an
+ * array of objects whose toString() methods return their section titles.
+ *
+ * @return the array of section objects
*/
Object[] getSections();
-
+
/**
- * Provides the starting index in the list for a given section.
- * @param section the index of the section to jump to.
- * @return the starting position of that section. If the section is out of bounds, the
- * position must be clipped to fall within the size of the list.
+ * Given the index of a section within the array of section objects, returns
+ * the starting position of that section within the adapter.
+ * <p>
+ * If the section's starting position is outside of the adapter bounds, the
+ * position must be clipped to fall within the size of the adapter.
+ *
+ * @param sectionIndex the index of the section within the array of section
+ * objects
+ * @return the starting position of that section within the adapter,
+ * constrained to fall within the adapter bounds
*/
- int getPositionForSection(int section);
-
+ int getPositionForSection(int sectionIndex);
+
/**
- * This is a reverse mapping to fetch the section index for a given position
- * in the list.
- * @param position the position for which to return the section
- * @return the section index. If the position is out of bounds, the section index
+ * Given a position within the adapter, returns the index of the
+ * corresponding section within the array of section objects.
+ * <p>
+ * If the section index is outside of the section array bounds, the index
* must be clipped to fall within the size of the section array.
+ * <p>
+ * For example, consider an indexer where the section at array index 0
+ * starts at adapter position 100. Calling this method with position 10,
+ * which is before the first section, must return index 0.
+ *
+ * @param position the position within the adapter for which to return the
+ * corresponding section index
+ * @return the index of the corresponding section within the array of
+ * section objects, constrained to fall within the array bounds
*/
- int getSectionForPosition(int position);
+ int getSectionForPosition(int position);
}
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index e33c4d4..1c1d77a 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -22,10 +22,12 @@
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.inputmethod.EditorInfo;
@@ -105,6 +107,9 @@
private Locale mCurrentLocale;
+ private boolean mHourWithTwoDigit;
+ private char mHourFormat;
+
/**
* The callback interface used to indicate the time has been adjusted.
*/
@@ -164,7 +169,7 @@
// divider (only for the new widget style)
mDivider = (TextView) findViewById(R.id.divider);
if (mDivider != null) {
- mDivider.setText(R.string.time_picker_separator);
+ setDividerText();
}
// minute
@@ -235,6 +240,24 @@
mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
}
+ if (isAmPmAtStart()) {
+ // Move the am/pm view to the beginning
+ ViewGroup amPmParent = (ViewGroup) findViewById(R.id.timePickerLayout);
+ amPmParent.removeView(amPmView);
+ amPmParent.addView(amPmView, 0);
+ // Swap layout margins if needed. They may be not symmetrical (Old Standard Theme for
+ // example and not for Holo Theme)
+ ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) amPmView.getLayoutParams();
+ final int startMargin = lp.getMarginStart();
+ final int endMargin = lp.getMarginEnd();
+ if (startMargin != endMargin) {
+ lp.setMarginStart(endMargin);
+ lp.setMarginEnd(startMargin);
+ }
+ }
+
+ getHourFormatData();
+
// update controls to initial state
updateHourControl();
updateMinuteControl();
@@ -259,6 +282,35 @@
}
}
+ private void getHourFormatData() {
+ final Locale defaultLocale = Locale.getDefault();
+ final String bestDateTimePattern = DateFormat.getBestDateTimePattern(defaultLocale,
+ (mIs24HourView) ? "Hm" : "hm");
+ final int lengthPattern = bestDateTimePattern.length();
+ mHourWithTwoDigit = false;
+ char hourFormat = '\0';
+ // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save
+ // the hour format that we found.
+ for (int i = 0; i < lengthPattern; i++) {
+ final char c = bestDateTimePattern.charAt(i);
+ if (c == 'H' || c == 'h' || c == 'K' || c == 'k') {
+ mHourFormat = c;
+ if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) {
+ mHourWithTwoDigit = true;
+ }
+ break;
+ }
+ }
+ }
+
+ private boolean isAmPmAtStart() {
+ final Locale defaultLocale = Locale.getDefault();
+ final String bestDateTimePattern = DateFormat.getBestDateTimePattern(defaultLocale,
+ "hm" /* skeleton */);
+
+ return bestDateTimePattern.startsWith("a");
+ }
+
@Override
public void setEnabled(boolean enabled) {
if (mIsEnabled == enabled) {
@@ -423,9 +475,11 @@
if (mIs24HourView == is24HourView) {
return;
}
- mIs24HourView = is24HourView;
- // cache the current hour since spinner range changes
+ // cache the current hour since spinner range changes and BEFORE changing mIs24HourView!!
int currentHour = getCurrentHour();
+ // Order is important here.
+ mIs24HourView = is24HourView;
+ getHourFormatData();
updateHourControl();
// set value after spinner range is updated
setCurrentHour(currentHour);
@@ -458,6 +512,38 @@
onTimeChanged();
}
+ /**
+ * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":".
+ *
+ * See http://unicode.org/cldr/trac/browser/trunk/common/main
+ *
+ * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the
+ * separator as the character which is just after the hour marker in the returned pattern.
+ */
+ private void setDividerText() {
+ final Locale defaultLocale = Locale.getDefault();
+ final String skeleton = (mIs24HourView) ? "Hm" : "hm";
+ final String bestDateTimePattern = DateFormat.getBestDateTimePattern(defaultLocale,
+ skeleton);
+ final String separatorText;
+ int hourIndex = bestDateTimePattern.lastIndexOf('H');
+ if (hourIndex == -1) {
+ hourIndex = bestDateTimePattern.lastIndexOf('h');
+ }
+ if (hourIndex == -1) {
+ // Default case
+ separatorText = ":";
+ } else {
+ int minuteIndex = bestDateTimePattern.indexOf('m', hourIndex + 1);
+ if (minuteIndex == -1) {
+ separatorText = Character.toString(bestDateTimePattern.charAt(hourIndex + 1));
+ } else {
+ separatorText = bestDateTimePattern.substring(hourIndex + 1, minuteIndex);
+ }
+ }
+ mDivider.setText(separatorText);
+ }
+
@Override
public int getBaseline() {
return mHourSpinner.getBaseline();
@@ -500,14 +586,25 @@
private void updateHourControl() {
if (is24HourView()) {
- mHourSpinner.setMinValue(0);
- mHourSpinner.setMaxValue(23);
- mHourSpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
+ // 'k' means 1-24 hour
+ if (mHourFormat == 'k') {
+ mHourSpinner.setMinValue(1);
+ mHourSpinner.setMaxValue(24);
+ } else {
+ mHourSpinner.setMinValue(0);
+ mHourSpinner.setMaxValue(23);
+ }
} else {
- mHourSpinner.setMinValue(1);
- mHourSpinner.setMaxValue(12);
- mHourSpinner.setFormatter(null);
+ // 'K' means 0-11 hour
+ if (mHourFormat == 'K') {
+ mHourSpinner.setMinValue(0);
+ mHourSpinner.setMaxValue(11);
+ } else {
+ mHourSpinner.setMinValue(1);
+ mHourSpinner.setMaxValue(12);
+ }
}
+ mHourSpinner.setFormatter(mHourWithTwoDigit ? NumberPicker.getTwoDigitFormatter() : null);
}
private void updateMinuteControl() {
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index ff9678c..863d8cc 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -30,9 +30,7 @@
import android.view.ViewConfiguration;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
-import android.widget.AbsListView;
import android.widget.ImageButton;
-import android.widget.ListPopupWindow;
import com.android.internal.view.ActionBarPolicy;
import com.android.internal.view.menu.ActionMenuView.ActionMenuChildView;
@@ -694,32 +692,43 @@
}
@Override
- public boolean onTouchObserved(View v, MotionEvent ev) {
- if (ev.getActionMasked() == MotionEvent.ACTION_MOVE && v.isEnabled()
- && !v.pointInView(ev.getX(), ev.getY(), mScaledTouchSlop)) {
- mActivePointerId = ev.getPointerId(0);
- v.performClick();
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean onTouchForwarded(View v, MotionEvent ev) {
- if (!v.isEnabled() || mOverflowPopup == null || !mOverflowPopup.isShowing()) {
+ public boolean onTouchObserved(View src, MotionEvent srcEvent) {
+ if (!src.isEnabled()) {
return false;
}
- if (mActivePointerId != MotionEvent.INVALID_POINTER_ID) {
- if (mOverflowPopup.forwardMotionEvent(v, ev, mActivePointerId)) {
+ // Always start forwarding events when the source view is touched.
+ mActivePointerId = srcEvent.getPointerId(0);
+ src.performClick();
+ return true;
+ }
+
+ @Override
+ public boolean onTouchForwarded(View src, MotionEvent srcEvent) {
+ final OverflowPopup popup = mOverflowPopup;
+ if (popup != null && popup.isShowing()) {
+ final int activePointerId = mActivePointerId;
+ if (activePointerId != MotionEvent.INVALID_POINTER_ID && src.isEnabled()
+ && popup.forwardMotionEvent(src, srcEvent, activePointerId)) {
+ // Handled the motion event, continue forwarding.
return true;
}
- mActivePointerId = MotionEvent.INVALID_POINTER_ID;
+ final int activePointerIndex = srcEvent.findPointerIndex(activePointerId);
+ if (activePointerIndex >= 0) {
+ final float x = srcEvent.getX(activePointerIndex);
+ final float y = srcEvent.getY(activePointerIndex);
+ if (src.pointInView(x, y, mScaledTouchSlop)) {
+ // The user is touching the source view. Cancel
+ // forwarding, but don't dismiss the popup.
+ return false;
+ }
+ }
+
+ popup.dismiss();
}
- mOverflowPopup.dismiss();
+ // Cancel forwarding.
return false;
}
}
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 945f42b..9b266df 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -27,7 +27,6 @@
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
-import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
@@ -48,8 +47,6 @@
static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout;
- private final int[] mTempLocation = new int[2];
-
private final Context mContext;
private final LayoutInflater mInflater;
private final MenuBuilder mMenu;
@@ -162,67 +159,20 @@
return mPopup != null && mPopup.isShowing();
}
- public boolean forwardMotionEvent(View v, MotionEvent ev, int activePointerId) {
+ /**
+ * Forwards motion events from a source view to the popup window.
+ *
+ * @param src view from which the event was forwarded
+ * @param event forwarded motion event in source-local coordinates
+ * @param activePointerId id of the pointer that activated forwarding
+ * @return whether the event was handled
+ */
+ public boolean forwardMotionEvent(View src, MotionEvent event, int activePointerId) {
if (mPopup == null || !mPopup.isShowing()) {
return false;
}
- final AbsListView dstView = mPopup.getListView();
- if (dstView == null || !dstView.isShown()) {
- return false;
- }
-
- boolean cancelForwarding = false;
- final int actionMasked = ev.getActionMasked();
- switch (actionMasked) {
- case MotionEvent.ACTION_CANCEL:
- cancelForwarding = true;
- break;
- case MotionEvent.ACTION_UP:
- cancelForwarding = true;
- // $FALL-THROUGH$
- case MotionEvent.ACTION_MOVE:
- final int activeIndex = ev.findPointerIndex(activePointerId);
- if (activeIndex < 0) {
- return false;
- }
-
- final int[] location = mTempLocation;
- int x = (int) ev.getX(activeIndex);
- int y = (int) ev.getY(activeIndex);
-
- // Convert to global coordinates.
- v.getLocationOnScreen(location);
- x += location[0];
- y += location[1];
-
- // Convert to local coordinates.
- dstView.getLocationOnScreen(location);
- x -= location[0];
- y -= location[1];
-
- final int position = dstView.pointToPosition(x, y);
- if (position >= 0) {
- final int childCount = dstView.getChildCount();
- final int firstVisiblePosition = dstView.getFirstVisiblePosition();
- final int index = position - firstVisiblePosition;
- if (index < childCount) {
- final View child = dstView.getChildAt(index);
- if (actionMasked == MotionEvent.ACTION_UP) {
- // Touch ended, click highlighted item.
- final long id = dstView.getItemIdAtPosition(position);
- dstView.performItemClick(child, position, id);
- } else if (actionMasked == MotionEvent.ACTION_MOVE) {
- // TODO: Highlight touched item, activate after
- // long-hover. Consider forwarding events as HOVER and
- // letting ListView handle this.
- }
- }
- }
- break;
- }
-
- return true;
+ return mPopup.onForwardedEvent(src, event, activePointerId);
}
@Override
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 0efa227..65b3678 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -63,7 +63,6 @@
android_os_FileUtils.cpp \
android_os_MemoryFile.cpp \
android_os_MessageQueue.cpp \
- android_os_ParcelFileDescriptor.cpp \
android_os_Parcel.cpp \
android_os_SELinux.cpp \
android_os_SystemClock.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 91fdcc2..63310ab 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -135,7 +135,6 @@
extern int register_android_os_Debug(JNIEnv* env);
extern int register_android_os_MessageQueue(JNIEnv* env);
extern int register_android_os_Parcel(JNIEnv* env);
-extern int register_android_os_ParcelFileDescriptor(JNIEnv *env);
extern int register_android_os_SELinux(JNIEnv* env);
extern int register_android_os_SystemProperties(JNIEnv *env);
extern int register_android_os_SystemClock(JNIEnv* env);
@@ -1178,7 +1177,6 @@
REG_JNI(register_android_os_FileObserver),
REG_JNI(register_android_os_FileUtils),
REG_JNI(register_android_os_MessageQueue),
- REG_JNI(register_android_os_ParcelFileDescriptor),
REG_JNI(register_android_os_SELinux),
REG_JNI(register_android_os_Trace),
REG_JNI(register_android_os_UEventObserver),
diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp
deleted file mode 100644
index 99a2d04..0000000
--- a/core/jni/android_os_ParcelFileDescriptor.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-
-#include "JNIHelp.h"
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <stdio.h>
-
-#include <utils/Log.h>
-
-#include <android_runtime/AndroidRuntime.h>
-
-namespace android
-{
-
-static struct parcel_file_descriptor_offsets_t
-{
- jfieldID mFileDescriptor;
-} gParcelFileDescriptorOffsets;
-
-static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromFd(JNIEnv* env,
- jobject clazz, jint origfd)
-{
- int fd = dup(origfd);
- if (fd < 0) {
- jniThrowException(env, "java/io/IOException", strerror(errno));
- return NULL;
- }
- return jniCreateFileDescriptor(env, fd);
-}
-
-static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromFdNoDup(JNIEnv* env,
- jobject clazz, jint fd)
-{
- return jniCreateFileDescriptor(env, fd);
-}
-
-static void android_os_ParcelFileDescriptor_createPipeNative(JNIEnv* env,
- jobject clazz, jobjectArray outFds)
-{
- int fds[2];
- if (pipe(fds) < 0) {
- int therr = errno;
- jniThrowException(env, "java/io/IOException", strerror(therr));
- return;
- }
-
- for (int i=0; i<2; i++) {
- jobject fdObj = jniCreateFileDescriptor(env, fds[i]);
- env->SetObjectArrayElement(outFds, i, fdObj);
- }
-}
-
-static jint getFd(JNIEnv* env, jobject clazz)
-{
- jobject descriptor = env->GetObjectField(clazz, gParcelFileDescriptorOffsets.mFileDescriptor);
- if (descriptor == NULL) return -1;
- return jniGetFDFromFileDescriptor(env, descriptor);
-}
-
-static jlong android_os_ParcelFileDescriptor_getStatSize(JNIEnv* env,
- jobject clazz)
-{
- jint fd = getFd(env, clazz);
- if (fd < 0) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
- return -1;
- }
-
- struct stat st;
- if (fstat(fd, &st) != 0) {
- return -1;
- }
-
- if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
- return st.st_size;
- }
-
- return -1;
-}
-
-static jlong android_os_ParcelFileDescriptor_seekTo(JNIEnv* env,
- jobject clazz, jlong pos)
-{
- jint fd = getFd(env, clazz);
- if (fd < 0) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
- return -1;
- }
-
- return lseek(fd, pos, SEEK_SET);
-}
-
-static jlong android_os_ParcelFileDescriptor_getFdNative(JNIEnv* env, jobject clazz)
-{
- jint fd = getFd(env, clazz);
- if (fd < 0) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
- return -1;
- }
-
- return fd;
-}
-
-static const JNINativeMethod gParcelFileDescriptorMethods[] = {
- {"getFileDescriptorFromFd", "(I)Ljava/io/FileDescriptor;",
- (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromFd},
- {"getFileDescriptorFromFdNoDup", "(I)Ljava/io/FileDescriptor;",
- (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromFdNoDup},
- {"createPipeNative", "([Ljava/io/FileDescriptor;)V",
- (void*)android_os_ParcelFileDescriptor_createPipeNative},
- {"getStatSize", "()J",
- (void*)android_os_ParcelFileDescriptor_getStatSize},
- {"seekTo", "(J)J",
- (void*)android_os_ParcelFileDescriptor_seekTo},
- {"getFdNative", "()I",
- (void*)android_os_ParcelFileDescriptor_getFdNative}
-};
-
-const char* const kParcelFileDescriptorPathName = "android/os/ParcelFileDescriptor";
-
-int register_android_os_ParcelFileDescriptor(JNIEnv* env)
-{
- jclass clazz = env->FindClass(kParcelFileDescriptorPathName);
- LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
- gParcelFileDescriptorOffsets.mFileDescriptor = env->GetFieldID(clazz, "mFileDescriptor", "Ljava/io/FileDescriptor;");
- LOG_FATAL_IF(gParcelFileDescriptorOffsets.mFileDescriptor == NULL,
- "Unable to find mFileDescriptor field in android.os.ParcelFileDescriptor");
-
- return AndroidRuntime::registerNativeMethods(
- env, kParcelFileDescriptorPathName,
- gParcelFileDescriptorMethods, NELEM(gParcelFileDescriptorMethods));
-}
-
-}
diff --git a/core/res/res/layout/time_picker.xml b/core/res/res/layout/time_picker.xml
index a78cd85..4fa94f3 100644
--- a/core/res/res/layout/time_picker.xml
+++ b/core/res/res/layout/time_picker.xml
@@ -20,6 +20,7 @@
<!-- Layout of time picker-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/timePickerLayout"
android:orientation="horizontal"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_holo.xml
index 7d8900e..c6b7d3a 100644
--- a/core/res/res/layout/time_picker_holo.xml
+++ b/core/res/res/layout/time_picker_holo.xml
@@ -20,14 +20,19 @@
<!-- Layout of time picker -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/timePickerLayout"
android:orientation="horizontal"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:paddingStart="8dip"
+ android:paddingEnd="8dip">
<LinearLayout android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:paddingStart="8dip"
+ android:paddingEnd="8dip"
android:layoutDirection="ltr">
<!-- hour -->
@@ -37,8 +42,6 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dip"
android:layout_marginBottom="16dip"
- android:layout_marginStart="16dip"
- android:layout_marginEnd="6dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
@@ -48,6 +51,8 @@
android:id="@+id/divider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginStart="6dip"
+ android:layout_marginEnd="6dip"
android:layout_gravity="center_vertical"
android:importantForAccessibility="no"
/>
@@ -59,8 +64,6 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dip"
android:layout_marginBottom="16dip"
- android:layout_marginStart="6dip"
- android:layout_marginEnd="8dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
@@ -75,7 +78,7 @@
android:layout_marginTop="16dip"
android:layout_marginBottom="16dip"
android:layout_marginStart="8dip"
- android:layout_marginEnd="16dip"
+ android:layout_marginEnd="8dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 03e9045..50ea08b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2378,6 +2378,9 @@
<!-- Set to true in all of the configurations for which this input
method should be considered an option as the default. -->
<attr name="isDefault" format="boolean" />
+ <!-- Set to true if this input method supports ways to switch to
+ a next input method (e.g. a globe key.). -->
+ <attr name="supportsSwitchingToNextInputMethod" format="boolean" />
</declare-styleable>
<!-- This is the subtype of InputMethod. Subtype can describe locales (e.g. en_US, fr_FR...)
diff --git a/core/res/res/values/donottranslate.xml b/core/res/res/values/donottranslate.xml
index b49e7bd..a7288e1 100644
--- a/core/res/res/values/donottranslate.xml
+++ b/core/res/res/values/donottranslate.xml
@@ -24,8 +24,6 @@
<bool name="lockscreen_isPortrait">true</bool>
<!-- @hide DO NOT TRANSLATE. Control aspect ratio of lock pattern -->
<string name="lock_pattern_view_aspect">square</string>
- <!-- @hide DO NOT TRANSLATE. Separator between the hour and minute elements in a TimePicker widget -->
- <string name="time_picker_separator">:</string>
<!-- @hide DO NOT TRANSLATE. ICU pattern for "Mon, 14 January" -->
<string name="icu_abbrev_wday_month_day_no_year">eeeMMMMd</string>
<!-- @hide DO NOT TRANSLATE. date formatting pattern for system ui.-->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 80c9184..f2ec04f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2072,5 +2072,6 @@
<public type="attr" name="isAsciiCapable" />
<public type="attr" name="customRoots" />
<public type="attr" name="autoMirrored" />
+ <public type="attr" name="supportsSwitchingToNextInputMethod" />
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 14ae1e6..ca93d1c 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -217,6 +217,7 @@
<java-symbol type="id" name="pin_new_text" />
<java-symbol type="id" name="pin_confirm_text" />
<java-symbol type="id" name="pin_error_message" />
+ <java-symbol type="id" name="timePickerLayout" />
<java-symbol type="attr" name="actionModeShareDrawable" />
<java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -773,7 +774,6 @@
<java-symbol type="string" name="time_picker_increment_hour_button" />
<java-symbol type="string" name="time_picker_increment_minute_button" />
<java-symbol type="string" name="time_picker_increment_set_pm_button" />
- <java-symbol type="string" name="time_picker_separator" />
<java-symbol type="string" name="upload_file" />
<java-symbol type="string" name="user_switched" />
<java-symbol type="string" name="volume_alarm" />
diff --git a/docs/downloads/design/roboto-1.100141.zip b/docs/downloads/design/roboto-1.100141.zip
new file mode 100644
index 0000000..93dfda7
--- /dev/null
+++ b/docs/downloads/design/roboto-1.100141.zip
Binary files differ
diff --git a/docs/html/design/downloads/index.jd b/docs/html/design/downloads/index.jd
index b13ba62..6d9a60d 100644
--- a/docs/html/design/downloads/index.jd
+++ b/docs/html/design/downloads/index.jd
@@ -102,7 +102,7 @@
<p>
<a class="download-button" onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Roboto ZIP']);"
- href="https://github.com/google/roboto/archive/latest-hinted.zip">Roboto</a>
+ href="{@docRoot}downloads/design/roboto-1.100141.zip">Roboto</a>
<a class="download-button" onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Roboto Specemin Book']);"
href="{@docRoot}downloads/design/Roboto_Specimen_Book_20111129.pdf">Specimen Book</a>
</p>
diff --git a/docs/html/design/style/typography.jd b/docs/html/design/style/typography.jd
index 0d681ab..818af4c 100644
--- a/docs/html/design/style/typography.jd
+++ b/docs/html/design/style/typography.jd
@@ -12,7 +12,7 @@
<p>
<a class="download-button" onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Roboto ZIP']);"
- href="https://github.com/google/roboto/archive/latest-hinted.zip">Download Roboto</a>
+ href="{@docRoot}downloads/design/roboto-1.100141.zip">Download Roboto</a>
</p>
<p>The Android design language relies on traditional typographic tools such as scale, space, rhythm,
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index df966e1..f9cf9a2 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -331,6 +331,11 @@
void Caches::flush(FlushMode mode) {
FLUSH_LOGD("Flushing caches (mode %d)", mode);
+ // We must stop tasks before clearing caches
+ if (mode > kFlushMode_Layers) {
+ tasks.stop();
+ }
+
switch (mode) {
case kFlushMode_Full:
textureCache.clear();
@@ -338,13 +343,13 @@
dropShadowCache.clear();
gradientCache.clear();
fontRenderer->clear();
+ fboCache.clear();
dither.clear();
// fall through
case kFlushMode_Moderate:
fontRenderer->flush();
textureCache.flush();
pathCache.clear();
- tasks.stop();
// fall through
case kFlushMode_Layers:
layerCache.clear();
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index ee748d39..c9162fe 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -146,7 +146,7 @@
private long mExpireAt = Long.MAX_VALUE; // no expiry
private int mNumUpdates = Integer.MAX_VALUE; // no expiry
private float mSmallestDisplacement = 0.0f; // meters
- private WorkSource mWorkSource = new WorkSource();
+ private WorkSource mWorkSource = null;
private boolean mHideFromAppOps = false; // True if this request shouldn't be counted by AppOps
private String mProvider = LocationManager.FUSED_PROVIDER; // for deprecated APIs that explicitly request a provider
@@ -498,7 +498,16 @@
return mSmallestDisplacement;
}
- /** @hide */
+ /**
+ * Sets the WorkSource to use for power blaming of this location request.
+ *
+ * <p>No permissions are required to make this call, however the LocationManager
+ * will throw a SecurityException when requesting location updates if the caller
+ * doesn't have the {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission.
+ *
+ * @param workSource WorkSource defining power blame for this location request.
+ * @hide
+ */
public void setWorkSource(WorkSource workSource) {
mWorkSource = workSource;
}
@@ -508,7 +517,20 @@
return mWorkSource;
}
- /** @hide */
+ /**
+ * Sets whether or not this location request should be hidden from AppOps.
+ *
+ * <p>Hiding a location request from AppOps will remove user visibility in the UI as to this
+ * request's existence. It does not affect power blaming in the Battery page.
+ *
+ * <p>No permissions are required to make this call, however the LocationManager
+ * will throw a SecurityException when requesting location updates if the caller
+ * doesn't have the {@link android.Manifest.permission#UPDATE_APP_OPS_STATS} permission.
+ *
+ * @param hideFromAppOps If true AppOps won't keep track of this location request.
+ * @see android.app.AppOpsManager
+ * @hide
+ */
public void setHideFromAppOps(boolean hideFromAppOps) {
mHideFromAppOps = hideFromAppOps;
}
@@ -564,7 +586,7 @@
request.setHideFromAppOps(in.readInt() != 0);
String provider = in.readString();
if (provider != null) request.setProvider(provider);
- WorkSource workSource = in.readParcelable(WorkSource.class.getClassLoader());
+ WorkSource workSource = in.readParcelable(null);
if (workSource != null) request.setWorkSource(workSource);
return request;
}
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 8ddc094..f3356c9 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -20,7 +20,6 @@
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Looper;
-import android.os.Message;
import android.view.Surface;
import java.lang.ref.WeakReference;
@@ -130,11 +129,26 @@
}
/**
- * <p>Get the next Image from the ImageReader's queue. Returns {@code null}
- * if no new image is available.</p>
+ * <p>
+ * Get the next Image from the ImageReader's queue. Returns {@code null} if
+ * no new image is available.
+ * </p>
+ * <p>
+ * This operation will fail by throwing an
+ * {@link Surface.OutOfResourcesException OutOfResourcesException} if too
+ * many images have been acquired with {@link #getNextImage}. In particular
+ * a sequence of {@link #getNextImage} calls greater than {@link #getMaxImages}
+ * without calling {@link Image#close} or {@link #releaseImage} in-between
+ * will exhaust the underlying queue. At such a time,
+ * {@link Surface.OutOfResourcesException OutOfResourcesException} will be
+ * thrown until more images are released with {@link Image#close} or
+ * {@link #releaseImage}.
+ * </p>
*
* @return a new frame of image data, or {@code null} if no image data is
- * available.
+ * available.
+ * @throws Surface.OutOfResourcesException if too many images are currently
+ * acquired
*/
public Image getNextImage() {
SurfaceImage si = new SurfaceImage();
@@ -172,6 +186,8 @@
* @param listener the listener that will be run
* @param handler The handler on which the listener should be invoked, or null
* if the listener should be invoked on the calling thread's looper.
+ *
+ * @throws IllegalArgumentException if no handler specified and the calling thread has no looper
*/
public void setImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
mImageListener = listener;
@@ -260,8 +276,9 @@
* Called from Native code when an Event happens.
*/
private static void postEventFromNative(Object selfRef) {
- WeakReference weakSelf = (WeakReference)selfRef;
- final ImageReader ir = (ImageReader)weakSelf.get();
+ @SuppressWarnings("unchecked")
+ WeakReference<ImageReader> weakSelf = (WeakReference<ImageReader>)selfRef;
+ final ImageReader ir = weakSelf.get();
if (ir == null) {
return;
}
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 3fbaf69..278d661 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -26,7 +26,7 @@
*
* The format of the media data is specified as string/value pairs.
*
- * Keys common to all formats, <b>all keys not marked optional are mandatory</b>:
+ * Keys common to all audio/video formats, <b>all keys not marked optional are mandatory</b>:
*
* <table>
* <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
@@ -57,6 +57,11 @@
* <tr><td>{@link #KEY_FLAC_COMPRESSION_LEVEL}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is FLAC audio, specifies the desired compression level.</td></tr>
* </table>
*
+ * Subtitle formats have the following keys:
+ * <table>
+ * <tr><td>{@link #KEY_MIME}</td><td>String</td><td>The type of the format.</td></tr>
+ * <tr><td>{@link #KEY_LANGUAGE}</td><td>String</td><td>The language of the content.</td></tr>
+ * </table>
*/
public final class MediaFormat {
private Map<String, Object> mMap;
@@ -68,6 +73,12 @@
public static final String KEY_MIME = "mime";
/**
+ * A key describing the language of the content.
+ * The associated value is a string.
+ */
+ public static final String KEY_LANGUAGE = "language";
+
+ /**
* A key describing the sample rate of an audio format.
* The associated value is an integer
*/
@@ -277,6 +288,23 @@
}
/**
+ * Creates a minimal subtitle format.
+ * @param mime The mime type of the content.
+ * @param language The language of the content. Specify "und" if language
+ * information is only included in the content (similarly, if there
+ * are multiple language tracks in the content.)
+ */
+ public static final MediaFormat createSubtitleFormat(
+ String mime,
+ String language) {
+ MediaFormat format = new MediaFormat();
+ format.setString(KEY_MIME, mime);
+ format.setString(KEY_LANGUAGE, language);
+
+ return format;
+ }
+
+ /**
* Creates a minimal video format.
* @param mime The mime type of the content.
* @param width The width of the content (in pixels)
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index cd589de..7d914d2 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -44,6 +44,9 @@
using namespace android;
+static const char* const OutOfResourcesException =
+ "android/view/Surface$OutOfResourcesException";
+
enum {
IMAGE_READER_MAX_NUM_PLANES = 3,
};
@@ -609,7 +612,8 @@
nativeFormat = Image_getPixelFormat(env, format);
sp<BufferQueue> bq = new BufferQueue();
- sp<CpuConsumer> consumer = new CpuConsumer(bq, true, maxImages);
+ sp<CpuConsumer> consumer = new CpuConsumer(bq, maxImages,
+ /*controlledByApp*/true);
// TODO: throw dvm exOutOfMemoryError?
if (consumer == NULL) {
jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer");
@@ -702,7 +706,17 @@
status_t res = consumer->lockNextBuffer(buffer);
if (res != NO_ERROR) {
if (res != BAD_VALUE /*no buffers*/) {
- ALOGE("%s Fail to lockNextBuffer with error: %d ", __FUNCTION__, res);
+ if (res == NOT_ENOUGH_DATA) {
+ jniThrowException(env, OutOfResourcesException,
+ "Too many outstanding images, close existing images"
+ " to be able to acquire more.");
+ } else {
+ ALOGE("%s Fail to lockNextBuffer with error: %d ",
+ __FUNCTION__, res);
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Unknown error (%d) when we tried to lock buffer.",
+ res);
+ }
}
return false;
}
@@ -714,6 +728,7 @@
ALOGE("crop left: %d, top = %d", lt.x, lt.y);
jniThrowException(env, "java/lang/UnsupportedOperationException",
"crop left top corner need to at origin");
+ return false;
}
// Check if the producer buffer configurations match what ImageReader configured.
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 16a1e48..60142cd 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -753,7 +753,9 @@
status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
- throwExceptionAsNecessary(env, err, "Failed to handle key response");
+ if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
+ return NULL;
+ }
return VectorToJByteArray(env, keySetId);
}
@@ -1104,7 +1106,9 @@
status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
- throwExceptionAsNecessary(env, err, "Failed to encrypt");
+ if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
+ return NULL;
+ }
return VectorToJByteArray(env, output);
}
@@ -1132,7 +1136,9 @@
Vector<uint8_t> output;
status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
- throwExceptionAsNecessary(env, err, "Failed to decrypt");
+ if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
+ return NULL;
+ }
return VectorToJByteArray(env, output);
}
@@ -1160,7 +1166,9 @@
status_t err = drm->sign(sessionId, keyId, message, signature);
- throwExceptionAsNecessary(env, err, "Failed to sign");
+ if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
+ return NULL;
+ }
return VectorToJByteArray(env, signature);
}
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 9b2c127..2bed730 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OUTO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Kennisgewings verskyn hier"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Verkry enige tyd toegang tot hulle deur af te sleep.\nSleep weer af vir stelselkontroles."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Sleep rand van skerm om balk te wys"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Sleep van rand van skerm af om stelselbalk te wys"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 4aa452d..ebbad16 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -164,7 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ተያይዟል"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"ለGPS በመፈለግ ላይ"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"በ GPS የተዘጋጀ ሥፍራ"</string>
- <string name="accessibility_location_active" msgid="2427290146138169014">"ገባሪ የአካባቢ ጥያቄዎች"</string>
+ <string name="accessibility_location_active" msgid="2427290146138169014">"የአካባቢ ጥያቄዎች ነቅተዋል"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"ሁሉንም ማሳወቂያዎች አጽዳ"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"የመተግበሪያ መረጃ"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ማያ ገጽ በራስ ሰር ይዞራል።"</string>
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ራስ-ሰር"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"ማሳወቂያዎች እዚህ ላይ ይታያሉ"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"ወደ ታች በማንሸራተት በማንኛውም ጊዜ ይድረሱባቸው።\nSwipe የስርዓት መቆጣጠሪያዎችን ለማምጣት እንደገና ወደ ታች ያንሸራትቱ።"</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"አሞሌውን ለማሳየት የማያ ገጹን ጠርዝ ላይ ያንሸራትቱ"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"አሞሌውን ለማሳየት ከማያ ገጹ ጠርዝ ጀምረው ያንሸራትቱ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index f7f5e37..7aac94e 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"تلقائي"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"تظهر الإشعارات هنا"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"يمكنك الدخول إليها في أي وقت بالتمرير السريع إلى أسفل.\nيمكنك التمرير السريع إلى أسفل مرة أخرى للوصول إلى عناصر تحكم النظام."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"مرر سريعًا لحافة الشاشة لإظهار الشريط"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"مرر سريعًا من حافة الشاشة لإظهار شريط النظام"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index aaca584..76d0580 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -206,8 +206,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АЎТА"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Апавяшчэнні з\'яўляюцца тут"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Атрымлівайце доступ да іх у любы час, праводзячы пальцам уніз.\nПравядзіце пальцам уніз яшчэ раз, каб атрымаць доступ да сродкаў кіравання сістэмай."</string>
- <!-- no translation found for hiding_navigation_confirmation_message (3227814171674734332) -->
- <skip />
- <!-- no translation found for hiding_navigation_confirmation_message_long (7854368870786524950) -->
- <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index b10f5ff..605dd97 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: Има връзка"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Търси се GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Местоположението е зададено от GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Активни заявки за местоположение"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Изчистване на всички известия."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Информация за приложението"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екранът ще се завърта автоматично."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТ."</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Известията се показват тук"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Осъществявайте достъп до тях по всяко време, като прекарате пръст надолу.\nНаправете го отново за системните контроли."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Прекарайте пръст по ръба на екрана, за да се покаже лентата"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Прекарайте пръст от ръба на екрана, за да се покаже системната лента"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 0a95005..83e7020 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -166,8 +166,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: connectada"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"S\'està cercant un GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"S\'ha establert la ubicació per GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Sol·licituds d\'ubicació actives"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Esborra totes les notificacions."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informació de l\'aplicació"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girarà automàticament."</string>
@@ -204,6 +203,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÀTICA"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Les notificacions apareixen aquí"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Accedeix-hi en qualsevol moment: només has de fer lliscar el dit cap avall.\nTorna a fer lliscar el dit cap avall per fer que es mostrin els controls del sistema."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Fes lliscar el dit per la vora de la pantalla perquè es mostri la barra"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Fes lliscar el dit des de la vora de la pantalla perquè es mostri la barra del sistema"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 178238f..4497735 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -203,6 +203,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Zde se zobrazují oznámení"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Můžete je kdykoli zobrazit tím, že přejedete prstem dolů.\nPřejedete-li prstem dolů ještě jednou, zobrazí se ovládací prvky systému."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Panel zobrazíte přejetím přes okraj obrazovky"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Systémový panel zobrazíte přejetím přes okraj obrazovky"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 1c772b5..be42612 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi er forbundet"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Søger efter GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Placeringen er angivet ved hjælp af GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Aktive placeringsanmodninger"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle meddelelser."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Oplysninger om appen"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skærmen roterer automatisk."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Underretninger vises her"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Få adgang til dem når som helst ved at stryge ned.\nStryg ned igen for at komme til systemindstillingerne."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Stryg fra skærmkanten for at se bjælken"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Stryg med fingeren fra skærmens kant for at få vist systembjælken"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 86ea82d..052990c 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -166,8 +166,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS wird gesucht"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Standort durch GPS festgelegt"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Standortanfragen aktiv"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Alle Benachrichtigungen löschen"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"App-Details"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Bildschirm wird automatisch gedreht."</string>
@@ -204,6 +203,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Benachrichtigungen erscheinen hier"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Greifen Sie jederzeit auf sie zu, indem Sie nach unten wischen.\nWischen Sie für Systemeinstellungen erneut nach unten."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Zum Einblenden der Leiste vom Rand weg wischen"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Zum Einblenden der Systemleiste vom Display-Rand weg wischen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index f965773..d23b8d5 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -203,6 +203,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ΑΥΤΟΜΑΤΗ"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Οι ειδοποιήσεις εμφανίζονται εδώ"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Μεταβείτε σε αυτές ανά πάσα στιγμή σύροντας προς τα κάτω.\nΣύρετε ξανά προς τα κάτω για τα στοιχεία ελέγχου συστήματος."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Σύρετε από την άκρη της οθόνης για να εμφανίσετε τη γραμμή"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Σύρετε από την άκρη της οθόνης για να εμφανίσετε τη γραμμή συστήματος"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index a7d621352..2ac1040 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Notifications appear here"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Access them any time by swiping down.\nSwipe down again for system controls."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Swipe edge of screen to reveal bar"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Swipe from edge of screen to reveal system bar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index bdd0363..d11d413 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -166,8 +166,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"La ubicación se estableció por GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Solicitudes de ubicación activas"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Eliminar todas las notificaciones"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Información de la aplicación"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girará automáticamente."</string>
@@ -204,6 +203,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Las notificaciones aparecen aquí."</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Desliza el dedo hacia abajo para acceder al contenido.\nVuelve a deslizar el dedo hacia abajo para acceder a los controles del sistema."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Desliza el dedo desde el borde de la pantalla para mostrar la barra."</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Desliza el dedo desde el borde de la pantalla para mostrar la barra del sistema."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a81a2b4..068af45 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Las notificaciones aparecen aquí"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Desliza el dedo hacia abajo para acceder al contenido.\nVuelve a deslizar el dedo hacia abajo para acceder a los controles del sistema."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Desliza el borde de la pantalla para mostrar la barra"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Desliza el borde de la pantalla para mostrar la barra del sistema"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index c4fda13..28ece65 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAATNE"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Märguanded ilmuvad siia"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Juurdepääs igal ajal sõrmega alla pühkides.\nSüsteemi juhtnuppude jaoks pühkige uuesti alla."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Riba kuvamiseks pühkige ekraani serva"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Süsteemiriba kuvamiseks pühkige ekraani servast"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index a84b9b4..2ba0427 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"خودکار"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"اعلانها در اینجا نمایش داده میشوند"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"با کشیدن انگشت به طرف پایین به آنها دسترسی پیدا کنید.\nبرای کنترلهای سیستم دوباره انگشت خود را به سمت پایین بکشید."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"برای نمایش نوار، انگشت خود را از لبه صفحه به داخل بکشید"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"برای نمایش نوار سیستم، انگشت خود را از لبه صفحه به داخل بکشید"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index f2cce06..b652cb0 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Ilmoitukset näkyvät tässä"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Näet ilmoitukset liu\'uttamalla sormea alas ruudulla.\nVoit palauttaa järjestelmän ohjaimet näkyviin liu\'uttamalla sormea alas uudelleen."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Tuo palkki näkyviin liu\'uttamalla ruudun reunasta"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Tuo järjestelmäpalkki näkyviin liu\'uttamalla ruudun reunasta"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 7fe1143..d00e4a3 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -166,8 +166,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Recherche de GPS..."</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Position définie par GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Demandes de localisation actives"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Supprimer toutes les notifications"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informations sur l\'application"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"L\'écran pivote automatiquement."</string>
@@ -204,6 +203,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Les notifications s’affichent ici"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Accédez-y à tout moment en faisant glisser le doigt vers le bas.\nRépétez l\'opération pour accéder aux commandes du système."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Faites glisser le doigt sur le côté de l\'écran pour afficher la barre."</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Faites glisser le doigt à partir d\'un côté de l\'écran pour afficher la barre système."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index a1de7a1..45b5813 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वत:"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"सूचनाएं यहां दिखाई देती हैं"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"नीचे स्वाइप करके उन तक कभी भी पहुंचें.\nसिस्टम नियंत्रणों के लिए पुन: नीचे स्वाइप करें."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"बार को प्रदर्शित करने के लिए स्क्रीन के किनारे को स्वाइप करें"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"सिस्टम बार को प्रदर्शित करने के लिए स्क्रीन के किनारे से स्वाइप करें"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index f8ff35d..9f8559c 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATSKI"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Obavijesti se prikazuju ovdje"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Pristupite im u bilo kojem trenutku tako da prstom trznete prema dolje. \nPonovo prstom trznite prema dolje za kontrole sustava."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Prijeđite prstom po rubu zaslona da bi se prikazala traka"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Prijeđite prstom od ruba zaslona da bi se prikazala traka sustava"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 118baed..f2dcd93 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"automatikus"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Az értesítések itt jelennek meg."</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Bármikor elérheti őket, ha lefelé húzza az ujját.\nHúzza le az ujját még egyszer a rendszerbeállítások eléréséhez."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Csúsztassa ujját a képernyő szélén a sáv megjelenítéséhez"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Csúsztassa ujját a képernyő szélétől a rendszersáv megjelenítéséhez"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 013bd99..6846056 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tersambung"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Menelusuri GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi yang disetel oleh GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Permintaan lokasi aktif"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Menghapus semua pemberitahuan."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Info aplikasi"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Layar akan diputar secara otomatis."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATIS"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Pemberitahuan muncul di sini"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Akses kapan saja dengan menggesek ke bawah.\nGesek ke bawah sekali lagi untuk kontrol sistem."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Gesek tepi layar untuk membuka bilah"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Gesek dari bagian tepi layar untuk membuka bilah sistem"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index ff539be..a889342 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -203,6 +203,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Le notifiche vengono visualizzate qui"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Puoi accedervi in qualsiasi momento scorrendo verso il basso.\nFai scorrere di nuovo verso il basso per visualizzare i controlli del sistema."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Fai scorrere il bordo dello schermo per visualizzare la barra"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Fai scorrere il dito dal bordo dello schermo per visualizzare la barra di sistema"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index c80ad7c..899f092 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi מחובר"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"מחפש GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"מיקום מוגדר על ידי GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"בקשות מיקום פעילות"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"נקה את כל ההתראות."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"פרטי יישום"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"המסך יסתובב באופן אוטומטי."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"אוטומטי"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"הודעות מופיעות כאן"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"גש אליהם בכל עת על ידי החלקה למטה.\nהחלק למטה שוב למעבר למרכז הבקרה של המערכת."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"החלק מקצה המסך כדי להציג את הסרגל"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"החלק מקצה המסך כדי להציג את סרגל המערכת"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 73aa558..e92e8be 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -166,8 +166,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi接続済み"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSで検索中"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPSにより現在地が設定されました"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"現在地リクエストがアクティブ"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"通知をすべて消去。"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"アプリ情報"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"画面は自動的に回転します。"</string>
@@ -204,6 +203,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"ここに通知が表示されます"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"下にスワイプすると、いつでも通知を表示できます。\nシステムを管理するにはもう一度下にスワイプしてください。"</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"バーを表示するには、画面の端からスワイプします"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"システムバーを表示するには、画面の端からスワイプします"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 403c94b..6319184 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 연결됨"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS 검색 중"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS에서 위치 설정"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"위치 요청 있음"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"모든 알림 지우기"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"앱 정보"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"화면이 자동으로 회전됩니다."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"자동"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"알림이 여기에 표시됨"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"아래로 스와이프하여 언제든 액세스하세요.\n한 번 더 아래로 스와이프하면 시스템 관리로 이동합니다."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"화면 가장자리에서 스와이프하여 표시줄 표시"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"화면 가장자리에서 스와이프하여 시스템 표시줄 표시"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 11b67ed..4400d37 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Prisij. prie „Wi-Fi“"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Ieškoma GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS nustatyta vieta"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Vietovės užklausos aktyvios"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Išvalyti visus pranešimus."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Programos informacija"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekranas bus sukamas automatiškai."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATINIS"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Pranešimai rodomi čia"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Perbraukę žemyn bet kuriuo metu pasieksite pranešimus.\nJei norite naudoti sistemos valdiklius, perbraukite žemyn dar kartą."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Jei norite, kad būtų rodoma juosta, perbraukite ekrano krašte"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Jei norite, kad būtų rodoma sistemos juosta, perbraukite iš ekrano krašto"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 85ab3fd..b2bee8c 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Izv. sav. ar Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Notiek GPS meklēšana..."</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS iestatītā atrašanās vieta"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Aktīvi atrašanās vietu pieprasījumi"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Notīrīt visus paziņojumus"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informācija par lietotni"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekrāns tiks pagriezts automātiski."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMĀTISKI"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Šeit tiek rādīti paziņojumi"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Piekļūstiet tiem jebkurā laikā, velkot uz leju.\nVēlreiz velciet, lai tiktu parādītas sistēmas vadīklas."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Velciet no ekrāna malas, lai piekļūtu joslai."</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Velciet no ekrāna malas, lai piekļūtu sistēmas joslai."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index b6b3577..9c76eae 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Pemberitahuan dipaparkan di sini"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Akses panel pada bila-bila masa dengan meleret ke bawah.\nLeret ke bawah sekali lagi untuk mendapatkan kawalan sistem."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Leret ke bahagian tepi skrin untuk menampakkan bar"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Leret dari tepi skrin untuk menampakkan bar sistem"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 6f7d727..d850cf3 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tilkoblet"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Søker etter GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Posisjon angitt av GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Aktive stedsforespørsler"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Fjern alle varslinger."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Info om app"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skjermen roterer automatisk."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Varslene vises her"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Bruk dem når som helst ved å sveipe nedover.\nSveip nedover igjen for å gå til systemkontrollene."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Sveip på kanten av skjermen for å få frem feltet"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Sveip fra kanten på skjermen for å få frem systemfeltet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 02a5b45..5b6ebab 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATISCH"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Meldingen worden hier weergegeven"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"U kunt de meldingen op elk gewenst moment openen door met uw vinger omlaag te vegen.\nVeeg nogmaals met uw vinger omlaag om de systeembesturingselementen weer te geven."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Veeg vanaf de rand om balk weer te geven"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Veeg vanaf de rand van het scherm om de systeembalk weer te geven"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index d17c45e..6bff7af 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: połączono"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Wyszukiwanie sygnału GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokalizacja z GPSa"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Prośby o lokalizację są aktywne"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Usuń wszystkie powiadomienia."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"O aplikacji"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran zostanie obrócony automatycznie."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATYCZNA"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Tutaj pokazują się powiadomienia"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Możesz je otworzyć w dowolnej chwili, przesuwając w dół.\nPrzesuń jeszcze raz w dół, by otworzyć ustawienia systemowe."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Przesuń palcem od krawędzi ekranu, by odkryć pasek"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Przesuń palcem od krawędzi ekranu, by odkryć pasek systemu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index b520319..6aa94e0 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ligado"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"A procurar GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Localização definida por GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Pedidos de localização ativos"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informações da aplicação"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"O ecrã será rodado automaticamente."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"As notificações são apresentadas aqui"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Pode aceder em qualquer altura, deslizando rapidamente para baixo com o dedo.\nDeslize novamente para baixo para aceder aos controlos do sistema."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Deslize da extremidade do ecrã para revelar a barra"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Deslize da extremidade do ecrã para revelar a barra do sistema"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 2a2f336..aa972fb 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -166,8 +166,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Local definido por GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Solicitações de localização ativas"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informações do aplicativo"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"A tela girará automaticamente."</string>
@@ -204,6 +203,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"As notificações aparecem aqui"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Acesse a qualquer momento deslizando para baixo.\nDeslize para baixo novamente para acessar os controles do sistema."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Deslize a borda da tela para ver a barra"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Deslize a partir da borda da tela ver a barra do sistema"</string>
</resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 22a857e..05b7453 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -372,8 +372,4 @@
<skip />
<!-- no translation found for status_bar_help_text (7874607155052076323) -->
<skip />
- <!-- no translation found for hiding_navigation_confirmation_message (3227814171674734332) -->
- <skip />
- <!-- no translation found for hiding_navigation_confirmation_message_long (7854368870786524950) -->
- <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 375d12cb..9c5ad00 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectat"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Se caută GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Locaţie setată prin GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Solicitări locație active"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Ștergeţi toate notificările."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informaţii despre aplicaţie"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ecranul se va roti în mod automat."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAT"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Notificările se afişează aici"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Accesaţi-le oricând glisând în jos.\nGlisaţi în jos din nou pentru comenzile sistemului."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Glisați dinspre marginea ecranului pentru a afișa bara"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Glisați dinspre marginea ecranului pentru a afișa bara de sistem"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 15adf90..3020624 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -166,8 +166,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi подключено"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Поиск GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Координаты по GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Есть активные запросы на определение местоположения"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Удалить все уведомления"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"О приложении"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран будет поворачиваться автоматически."</string>
@@ -206,6 +205,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОНАСТРОЙКА"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Это панель уведомлений"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Ее можно открыть, пролистнув экран вниз.\nЧтобы открыть настройки, проведите пальцем вниз ещё раз."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Чтобы открыть панель, проведите пальцем от края к центру экрана"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Чтобы открыть панель навигации, проведите пальцем от края к центру экрана"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index bb70f36..59af9ab 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -166,8 +166,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: pripojené"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Vyhľadávanie satelitov GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Poloha nastavená pomocou GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Žiadosti o polohu sú aktívne"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Vymazať všetky upozornenia."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informácie o aplikácii"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Obrazovka sa automaticky otočí."</string>
@@ -204,6 +203,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Tu sa zobrazujú upozornenia"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Môžete ich kedykoľvek zobraziť tak, že posuniete prstom nadol.\nAk posuniete prstom nadol ešte raz, zobrazia sa ovládacie prvky systému."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Panel zobrazíte posunutím cez okraj obrazovky"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Systémový panel zobrazíte posunutím cez okraj obrazovky"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 46a5826..338ff44 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Iskanje GPS-a"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokacija nastavljena z GPS-om"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Aktivne zahteve za lokacijo"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Izbriši vsa obvestila."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Podatki o aplikaciji"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Zaslon se bo samodejno zasukal."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"SAMODEJNO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Obvestila so prikazana tukaj"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Do njih lahko kadar koli dostopate tako, da povlečete navzdol.\nZa prikaz sistemskih kontrolnikov znova povlecite navzdol."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Vrstico prikažete tako, da povlečete z roba zaslona"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Sistemsko vrstico prikažete tako, da povlečete z roba zaslona"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 163bc06..b501d69 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АУТОМАТСКА"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Обавештења се појављују овде"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Приступите им у било ком тренутку листањем надоле.\nПоново листајте надоле да би се приказале системске контроле."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Превуците по ивици екрана да би се приказала трака"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Превуците од ивице екрана да би се приказала системска трака"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index c5335f4..560a00e 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ansluten"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Sökning efter GPS pågår"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Platsen har identifierats av GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Det finns aktiva platsbegäranden"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Ta bort alla meddelanden."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Info om appen"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skärmen roteras automatiskt."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Meddelanden visas här"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Du kommer åt dem när som helst genom att dra nedåt.\nDra nedåt igen om du vill visa systemkontroller."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Dra från kanten av skärmen om du vill visa fältet"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Dra från kanten av skärmen om du vill visa systemfältet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index a0fb0a8..e3338de 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -199,6 +199,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"KIOTOMATIKI"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Arifa zitaonekana hapa"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Zifikie wakati wowote kwa kutelezesha chini.\nTelezesha chini tena kupata vidhibiti vya mfumo."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Telezesha kidole kutoka ukingo wa skrini ili kuonyesha upau"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Telezesha kidole kutoka ukingo wa skrini ili kuonyesha upau wa mfumo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 2552e5c..3127eb3 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"อัตโนมัติ"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"การแจ้งเตือนจะแสดงขึ้นที่นี่"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"เข้าถึงได้ทุกเมื่อด้วยการกวาดนิ้วลง\nกวาดนิ้วลงอีกครั้งสำหรับการควบคุมระบบ"</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"กวาดขอบของหน้าจอเพื่อแสดงแถบ"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"กวาดจากขอบของหน้าจอเพื่อแสดงแถบระบบ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index dfc6c7d..9d4d9de 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Dito lumalabas ang mga notification"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"I-access ang mga ito anumang oras sa pamamagitan ng pag-swipe pababa.\nMuling mag-swipe pababa para sa mga kontrol ng system."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Mag-swipe sa gilid ng screen upang ipakita ang bar"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Mag-swipe mula sa gilid ng screen upang ipakita ang system bar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index f7b34de..b885344 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Kablosuz bağlandı"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS aranıyor"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Konum GPS ile belirlendi"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Konum bilgisi istekleri etkin"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Tüm bildirimleri temizle"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Uygulama bilgileri"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran otomatik olarak dönecektir."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATİK"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Bildirimler burada görünür"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Aşağıya hızlıca kaydırarak bunlara istediğiniz zaman erişebilirsiniz.\nSistem denetimleri için tekrar hızlıca aşağı kaydırın."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Çubuğu görüntülemek için ekranın kenarından hızlıca kaydırın"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Sistem çubuğunu görüntülemek için ekranın kenarından hızlıca kaydırın"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 23e276b..1f3c131 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi під’єднано"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Виконується пошук GPS-сигналу"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Місцезнаходження встановлено за допомогою GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Запити про місцезнаходження активні"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Очистити всі сповіщення."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Інформація про програму"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екран обертатиметься автоматично."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТО"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Сповіщення з’являються тут"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Отримуйте до них доступ будь-коли, провівши пальцем униз.\nЗнову проведіть униз, щоб відкрити елементи керування системи."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Гортайте від краю екрана, щоб з’явилась панель"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Проведіть пальцем від краю екрана, щоб з’явилась навігаційна панель"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 31fc2c8..01ec999 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -164,8 +164,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Đã kết nối Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Đang tìm kiếm GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Vị trí đặt bởi GPS"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Yêu cầu về thông tin vị trí hiện hoạt"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Xóa tất cả thông báo."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Thông tin về ứng dụng"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Màn hình sẽ xoay tự động."</string>
@@ -202,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"TỰ ĐỘNG"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Thông báo xuất hiện tại đây"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Truy cập vào chúng bất kỳ lúc nào bằng cách vuốt xuống.\nVuốt lại xuống để hiển thị các điều khiển hệ thống."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Vuốt cạnh màn hình để hiển thị thanh"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Vuốt từ cạnh màn hình để hiển thị thanh hệ thống"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index b8b56c9..867cb17 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -166,8 +166,7 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN 已连接"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜索 GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"已通过 GPS 确定位置"</string>
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
+ <string name="accessibility_location_active" msgid="2427290146138169014">"应用发出了有效位置信息请求"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"应用信息"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"屏幕会自动旋转。"</string>
@@ -204,6 +203,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自动"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"通知会显示在这里"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"向下滑动可随时查看通知。\n再次向下滑动可使用系统控制功能。"</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"从屏幕边缘向里滑可显示系统栏"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"从屏幕边缘向里滑动即可显示系统栏"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index a0bb92a..1d5b2ac 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -203,6 +203,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"系統會在這裡顯示通知"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"向下滑動即可隨時存取通知。\n再次向下滑動即可使用系統控制項。"</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"從螢幕邊緣向內滑動即可顯示導覽列"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"從螢幕邊緣向內滑動即可顯示導覽列"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 53e7db0..662d3cb 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -201,6 +201,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OKUZENZAKALELAYO"</string>
<string name="status_bar_help_title" msgid="1199237744086469217">"Izaziso zivela lapha"</string>
<string name="status_bar_help_text" msgid="7874607155052076323">"Kufinyelele noma kunini ngokuswayiphela phansi.\nSwayiphela phansi futhi ngezilawuli zesistimu."</string>
- <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Swayipha kunqenqema lwesikrini ukuze uveze ibha"</string>
- <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Swayipha kusuka kunqenqema ukuze uveze ibha yesistimu"</string>
</resources>
diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java
index ee5b890..a6b69a2 100644
--- a/services/java/com/android/server/content/SyncManager.java
+++ b/services/java/com/android/server/content/SyncManager.java
@@ -2889,11 +2889,12 @@
// determine if we need to set or cancel the alarm
boolean shouldSet = false;
boolean shouldCancel = false;
- final boolean alarmIsActive = mAlarmScheduleTime != null;
+ final boolean alarmIsActive = (mAlarmScheduleTime != null) && (now < mAlarmScheduleTime);
final boolean needAlarm = alarmTime != Long.MAX_VALUE;
if (needAlarm) {
- // Need the alarm if it's currently not set, or if our time is before the currently
- // set time.
+ // Need the alarm if
+ // - it's currently not set
+ // - if the alarm is set in the past.
if (!alarmIsActive || alarmTime < mAlarmScheduleTime) {
shouldSet = true;
}
@@ -2910,7 +2911,7 @@
+ " secs from now");
}
mAlarmScheduleTime = alarmTime;
- mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime,
+ mAlarmService.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime,
mSyncAlarmIntent);
} else if (shouldCancel) {
mAlarmScheduleTime = null;
diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java
index 25529a6..e3693f8 100644
--- a/services/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/java/com/android/server/content/SyncStorageEngine.java
@@ -53,6 +53,7 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
@@ -71,7 +72,7 @@
private static final String TAG = "SyncManager";
private static final boolean DEBUG = true;
- private static final boolean DEBUG_FILE = true;
+ private static final String TAG_FILE = "SyncManagerFile";
private static final String XML_ATTR_NEXT_AUTHORITY_ID = "nextAuthorityId";
private static final String XML_ATTR_LISTEN_FOR_TICKLES = "listen-for-tickles";
@@ -420,9 +421,12 @@
File systemDir = new File(dataDir, "system");
File syncDir = new File(systemDir, "sync");
syncDir.mkdirs();
+
+ maybeDeleteLegacyPendingInfoLocked(syncDir);
+
mAccountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
mStatusFile = new AtomicFile(new File(syncDir, "status.bin"));
- mPendingFile = new AtomicFile(new File(syncDir, "pending.bin"));
+ mPendingFile = new AtomicFile(new File(syncDir, "pending.xml"));
mStatisticsFile = new AtomicFile(new File(syncDir, "stats.bin"));
readAccountInfoLocked();
@@ -676,7 +680,8 @@
continue;
}
for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
- if (providerName != null && !providerName.equals(authorityInfo.authority)) {
+ if (providerName != null
+ && !providerName.equals(authorityInfo.authority)) {
continue;
}
if (authorityInfo.backoffTime != nextSyncTime
@@ -774,10 +779,12 @@
}
synchronized (mAuthorities) {
if (toUpdate.period <= 0 && add) {
- Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-" + add);
+ Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-"
+ + add);
}
if (toUpdate.extras == null) {
- Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-" + add);
+ Log.e(TAG, "null extras, should never happen in updateOrRemovePeriodicSync: add-"
+ + add);
}
try {
AuthorityInfo authority =
@@ -806,7 +813,7 @@
if (!alreadyPresent) {
authority.periodicSyncs.add(new PeriodicSync(toUpdate));
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
- status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0);
+ status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0L);
}
} else {
// Remove any periodic syncs that match the authority and extras.
@@ -824,7 +831,8 @@
if (status != null) {
status.removePeriodicSyncTime(i);
} else {
- Log.e(TAG, "Tried removing sync status on remove periodic sync but did not find it.");
+ Log.e(TAG, "Tried removing sync status on remove periodic sync but"
+ + "did not find it.");
}
} else {
i++;
@@ -942,7 +950,7 @@
op = new PendingOperation(op);
op.authorityId = authority.ident;
mPendingOperations.add(op);
- writePendingOperationsLocked();
+ appendPendingOperationLocked(op);
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
status.pending = true;
@@ -1660,7 +1668,9 @@
FileInputStream fis = null;
try {
fis = mAccountInfoFile.openRead();
- if (DEBUG_FILE) Log.v(TAG, "Reading " + mAccountInfoFile.getBaseFile());
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG, "Reading " + mAccountInfoFile.getBaseFile());
+ }
XmlPullParser parser = Xml.newPullParser();
parser.setInput(fis, null);
int eventType = parser.getEventType();
@@ -1745,6 +1755,20 @@
}
/**
+ * Ensure the old pending.bin is deleted, as it has been changed to pending.xml.
+ * pending.xml was used starting in KLP.
+ * @param syncDir directory where the sync files are located.
+ */
+ private void maybeDeleteLegacyPendingInfoLocked(File syncDir) {
+ File file = new File(syncDir, "pending.bin");
+ if (!file.exists()) {
+ return;
+ } else {
+ file.delete();
+ }
+ }
+
+ /**
* some authority names have changed. copy over their settings and delete the old ones
* @return true if a change was made
*/
@@ -1832,18 +1856,21 @@
syncable = "unknown";
}
authority = mAuthorities.get(id);
- if (DEBUG_FILE) Log.v(TAG, "Adding authority: account="
- + accountName + " auth=" + authorityName
- + " user=" + userId
- + " enabled=" + enabled
- + " syncable=" + syncable);
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG, "Adding authority: account="
+ + accountName + " auth=" + authorityName
+ + " user=" + userId
+ + " enabled=" + enabled
+ + " syncable=" + syncable);
+ }
if (authority == null) {
- if (DEBUG_FILE) {
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
Log.v(TAG, "Creating entry");
}
if (accountName != null && accountType != null) {
authority = getOrCreateAuthorityLocked(
- new Account(accountName, accountType), userId, authorityName, id, false);
+ new Account(accountName, accountType), userId, authorityName, id,
+ false);
} else {
authority = getOrCreateAuthorityLocked(
new ComponentName(packageName, className), userId, id, false);
@@ -1943,7 +1970,9 @@
* Write all account information to the account file.
*/
private void writeAccountInfoLocked() {
- if (DEBUG_FILE) Log.v(TAG, "Writing new " + mAccountInfoFile.getBaseFile());
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG, "Writing new " + mAccountInfoFile.getBaseFile());
+ }
FileOutputStream fos = null;
try {
@@ -2041,7 +2070,9 @@
final boolean hasType = db.getVersion() >= 11;
// Copy in all of the status information, as well as accounts.
- if (DEBUG_FILE) Log.v(TAG, "Reading legacy sync accounts db");
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG, "Reading legacy sync accounts db");
+ }
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables("stats, status");
HashMap<String,String> map = new HashMap<String,String>();
@@ -2151,7 +2182,9 @@
* Read all sync status back in to the initial engine state.
*/
private void readStatusLocked() {
- if (DEBUG_FILE) Log.v(TAG, "Reading " + mStatusFile.getBaseFile());
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG, "Reading " + mStatusFile.getBaseFile());
+ }
try {
byte[] data = mStatusFile.readFully();
Parcel in = Parcel.obtain();
@@ -2163,8 +2196,10 @@
SyncStatusInfo status = new SyncStatusInfo(in);
if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
status.pending = false;
- if (DEBUG_FILE) Log.v(TAG, "Adding status for id "
- + status.authorityId);
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG, "Adding status for id "
+ + status.authorityId);
+ }
mSyncStatus.put(status.authorityId, status);
}
} else {
@@ -2182,7 +2217,9 @@
* Write all sync status to the sync status file.
*/
private void writeStatusLocked() {
- if (DEBUG_FILE) Log.v(TAG, "Writing new " + mStatusFile.getBaseFile());
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG, "Writing new " + mStatusFile.getBaseFile());
+ }
// The file is being written, so we don't need to have a scheduled
// write until the next change.
@@ -2211,103 +2248,97 @@
}
}
- public static final int PENDING_OPERATION_VERSION = 4;
+ public static final int PENDING_OPERATION_VERSION = 3;
- /**
- * Read all pending operations back in to the initial engine state.
- */
+ /** Read all pending operations back in to the initial engine state. */
private void readPendingOperationsLocked() {
- if (DEBUG_FILE) Log.v(TAG, "Reading " + mPendingFile.getBaseFile());
- try {
- readPendingAsXml();
- } catch (XmlPullParserException e) {
- Log.d(TAG, "Error parsing pending as xml, trying as parcel.");
- try {
- readPendingAsParcelled();
- } catch (java.io.IOException e1) {
- Log.i(TAG, "No initial pending operations");
+ FileInputStream fis = null;
+ if (!mPendingFile.getBaseFile().exists()) {
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG_FILE, "No pending operation file.");
+ return;
}
}
- }
-
- private void readPendingAsXml() throws XmlPullParserException {
- FileInputStream fis = null;
try {
fis = mPendingFile.openRead();
- XmlPullParser parser = Xml.newPullParser();
+ XmlPullParser parser;
+ parser = Xml.newPullParser();
parser.setInput(fis, null);
+
int eventType = parser.getEventType();
while (eventType != XmlPullParser.START_TAG &&
eventType != XmlPullParser.END_DOCUMENT) {
eventType = parser.next();
}
- if (eventType == XmlPullParser.END_DOCUMENT) return;
+ if (eventType == XmlPullParser.END_DOCUMENT) return; // Nothing to read.
String tagName = parser.getName();
- if ("pending".equals(tagName)) {
- int version = -1;
- String versionString = parser.getAttributeValue(null, "version");
- if (versionString == null ||
- Integer.parseInt(versionString) != PENDING_OPERATION_VERSION) {
- Log.w(TAG, "Unknown pending operation version "
- + version + "; trying to read as binary.");
- throw new XmlPullParserException("Unknown version.");
- }
- eventType = parser.next();
+ do {
PendingOperation pop = null;
- do {
- if (eventType == XmlPullParser.START_TAG) {
- try {
- tagName = parser.getName();
- if (parser.getDepth() == 2 && "op".equals(tagName)) {
- int authorityId = Integer.valueOf(parser.getAttributeValue(
- null, XML_ATTR_AUTHORITYID));
- boolean expedited = Boolean.valueOf(parser.getAttributeValue(
- null, XML_ATTR_EXPEDITED));
- int syncSource = Integer.valueOf(parser.getAttributeValue(
- null, XML_ATTR_SOURCE));
- int reason = Integer.valueOf(parser.getAttributeValue(
- null, XML_ATTR_REASON));
- AuthorityInfo authority = mAuthorities.get(authorityId);
- if (DEBUG_FILE) {
- Log.v(TAG, authorityId + " " + expedited + " " + syncSource + " " + reason);
- }
- if (authority != null) {
- pop = new PendingOperation(
- authority.account, authority.userId, reason, syncSource,
- authority.authority, new Bundle(), expedited);
- pop.authorityId = authorityId;
- pop.flatExtras = null; // No longer used.
- mPendingOperations.add(pop);
- if (DEBUG_FILE) Log.v(TAG, "Adding pending op: account=" + pop.account
- + " auth=" + pop.authority
+ if (eventType == XmlPullParser.START_TAG) {
+ try {
+ tagName = parser.getName();
+ if (parser.getDepth() == 1 && "op".equals(tagName)) {
+ // Verify version.
+ String versionString =
+ parser.getAttributeValue(null, XML_ATTR_VERSION);
+ if (versionString == null ||
+ Integer.parseInt(versionString) != PENDING_OPERATION_VERSION) {
+ Log.w(TAG, "Unknown pending operation version " + versionString);
+ throw new java.io.IOException("Unknown version.");
+ }
+ int authorityId = Integer.valueOf(parser.getAttributeValue(
+ null, XML_ATTR_AUTHORITYID));
+ boolean expedited = Boolean.valueOf(parser.getAttributeValue(
+ null, XML_ATTR_EXPEDITED));
+ int syncSource = Integer.valueOf(parser.getAttributeValue(
+ null, XML_ATTR_SOURCE));
+ int reason = Integer.valueOf(parser.getAttributeValue(
+ null, XML_ATTR_REASON));
+ AuthorityInfo authority = mAuthorities.get(authorityId);
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG_FILE, authorityId + " " + expedited + " " + syncSource + " "
+ + reason);
+ }
+ if (authority != null) {
+ pop = new PendingOperation(
+ authority.account, authority.userId, reason,
+ syncSource, authority.authority, new Bundle(),
+ expedited);
+ pop.flatExtras = null; // No longer used.
+ mPendingOperations.add(pop);
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG_FILE, "Adding pending op: "
+ + pop.authority
+ " src=" + pop.syncSource
+ " reason=" + pop.reason
+ " expedited=" + pop.expedited);
- } else {
- // Skip non-existent authority;
- pop = null;
- if (DEBUG_FILE) {
- Log.v(TAG, "No authority found for " + authorityId
- + ", skipping");
- }
}
- } else if (parser.getDepth() == 3 &&
- pop != null &&
- "extra".equals(tagName)) {
- parseExtra(parser, pop.extras);
+ } else {
+ // Skip non-existent authority.
+ pop = null;
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG_FILE, "No authority found for " + authorityId
+ + ", skipping");
+ }
}
- } catch (NumberFormatException e) {
- Log.d(TAG, "Invalid data in xml file.", e);
+ } else if (parser.getDepth() == 2 &&
+ pop != null &&
+ "extra".equals(tagName)) {
+ parseExtra(parser, pop.extras);
}
+ } catch (NumberFormatException e) {
+ Log.d(TAG, "Invalid data in xml file.", e);
}
- eventType = parser.next();
- } while(eventType != XmlPullParser.END_DOCUMENT);
- }
+ }
+ eventType = parser.next();
+ } while(eventType != XmlPullParser.END_DOCUMENT);
} catch (java.io.IOException e) {
- if (fis == null) Log.i(TAG, "No initial pending operations.");
- else Log.w(TAG, "Error reading pending data.", e);
- return;
+ Log.w(TAG_FILE, "Error reading pending data.", e);
+ } catch (XmlPullParserException e) {
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.w(TAG_FILE, "Error parsing pending ops xml.", e);
+ }
} finally {
if (fis != null) {
try {
@@ -2316,57 +2347,96 @@
}
}
}
+
+ private static final String XML_ATTR_AUTHORITYID = "authority_id";
+ private static final String XML_ATTR_SOURCE = "source";
+ private static final String XML_ATTR_EXPEDITED = "expedited";
+ private static final String XML_ATTR_REASON = "reason";
+ private static final String XML_ATTR_VERSION = "version";
+
/**
- * Old format of reading pending.bin as a parcelled file. Replaced in lieu of JSON because
- * persisting parcels is unsafe.
- * @throws java.io.IOException
+ * Write all currently pending ops to the pending ops file.
*/
- private void readPendingAsParcelled() throws java.io.IOException {
- byte[] data = mPendingFile.readFully();
- Parcel in = Parcel.obtain();
- in.unmarshall(data, 0, data.length);
- in.setDataPosition(0);
- final int SIZE = in.dataSize();
- while (in.dataPosition() < SIZE) {
- int version = in.readInt();
- if (version != 3 && version != 1) {
- Log.w(TAG, "Unknown pending operation version "
- + version + "; dropping all ops");
- break;
- }
- int authorityId = in.readInt();
- int syncSource = in.readInt();
- byte[] flatExtras = in.createByteArray();
- boolean expedited;
- if (version == PENDING_OPERATION_VERSION) {
- expedited = in.readInt() != 0;
- } else {
- expedited = false;
- }
- int reason = in.readInt();
- AuthorityInfo authority = mAuthorities.get(authorityId);
- if (authority != null) {
- Bundle extras;
- if (flatExtras != null) {
- extras = unflattenBundle(flatExtras);
- } else {
- // if we are unable to parse the extras for whatever reason convert this
- // to a regular sync by creating an empty extras
- extras = new Bundle();
+ private void writePendingOperationsLocked() {
+ final int N = mPendingOperations.size();
+ FileOutputStream fos = null;
+ try {
+ if (N == 0) {
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG_FILE, "Truncating " + mPendingFile.getBaseFile());
}
- PendingOperation op = new PendingOperation(
- authority.account, authority.userId, reason, syncSource,
- authority.authority, extras, expedited);
- op.authorityId = authorityId;
- op.flatExtras = flatExtras;
- if (DEBUG_FILE) Log.v(TAG, "Adding pending op: account=" + op.account
- + " auth=" + op.authority
- + " src=" + op.syncSource
- + " reason=" + op.reason
- + " expedited=" + op.expedited
- + " extras=" + op.extras);
- mPendingOperations.add(op);
+ mPendingFile.truncate();
+ return;
}
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG_FILE, "Writing new " + mPendingFile.getBaseFile());
+ }
+ fos = mPendingFile.startWrite();
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(fos, "utf-8");
+
+ for (int i = 0; i < N; i++) {
+ PendingOperation pop = mPendingOperations.get(i);
+ writePendingOperationLocked(pop, out);
+ }
+ out.endDocument();
+ mPendingFile.finishWrite(fos);
+ } catch (java.io.IOException e1) {
+ Log.w(TAG, "Error writing pending operations", e1);
+ if (fos != null) {
+ mPendingFile.failWrite(fos);
+ }
+ }
+ }
+
+ /** Write all currently pending ops to the pending ops file. */
+ private void writePendingOperationLocked(PendingOperation pop, XmlSerializer out)
+ throws IOException {
+ // Pending operation.
+ out.startTag(null, "op");
+
+ out.attribute(null, XML_ATTR_VERSION, Integer.toString(PENDING_OPERATION_VERSION));
+ out.attribute(null, XML_ATTR_AUTHORITYID, Integer.toString(pop.authorityId));
+ out.attribute(null, XML_ATTR_SOURCE, Integer.toString(pop.syncSource));
+ out.attribute(null, XML_ATTR_EXPEDITED, Boolean.toString(pop.expedited));
+ out.attribute(null, XML_ATTR_REASON, Integer.toString(pop.reason));
+ extrasToXml(out, pop.extras);
+
+ out.endTag(null, "op");
+ }
+
+ /**
+ * Append the given operation to the pending ops file; if unable to,
+ * write all pending ops.
+ */
+ private void appendPendingOperationLocked(PendingOperation op) {
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG, "Appending to " + mPendingFile.getBaseFile());
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = mPendingFile.openAppend();
+ } catch (java.io.IOException e) {
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG, "Failed append; writing full file");
+ }
+ writePendingOperationsLocked();
+ return;
+ }
+
+ try {
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(fos, "utf-8");
+ writePendingOperationLocked(op, out);
+ out.endDocument();
+ mPendingFile.finishWrite(fos);
+ } catch (java.io.IOException e1) {
+ Log.w(TAG, "Error writing appending operation", e1);
+ mPendingFile.failWrite(fos);
+ } finally {
+ try {
+ fos.close();
+ } catch (IOException e) {}
}
}
@@ -2399,54 +2469,6 @@
return bundle;
}
- private static final String XML_ATTR_AUTHORITYID = "authority_id";
- private static final String XML_ATTR_SOURCE = "source";
- private static final String XML_ATTR_EXPEDITED = "expedited";
- private static final String XML_ATTR_REASON = "reason";
- /**
- * Write all currently pending ops to the pending ops file. TODO: Change this from xml
- * so that we can append to this file as before.
- */
- private void writePendingOperationsLocked() {
- final int N = mPendingOperations.size();
- FileOutputStream fos = null;
- try {
- if (N == 0) {
- if (DEBUG_FILE) Log.v(TAG, "Truncating " + mPendingFile.getBaseFile());
- mPendingFile.truncate();
- return;
- }
- if (DEBUG_FILE) Log.v(TAG, "Writing new " + mPendingFile.getBaseFile());
- fos = mPendingFile.startWrite();
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(fos, "utf-8");
- out.startDocument(null, true);
- out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
- out.startTag(null, "pending");
- out.attribute(null, "version", Integer.toString(PENDING_OPERATION_VERSION));
-
- for (int i = 0; i < N; i++) {
- PendingOperation pop = mPendingOperations.get(i);
- out.startTag(null, "op");
- out.attribute(null, XML_ATTR_AUTHORITYID, Integer.toString(pop.authorityId));
- out.attribute(null, XML_ATTR_SOURCE, Integer.toString(pop.syncSource));
- out.attribute(null, XML_ATTR_EXPEDITED, Boolean.toString(pop.expedited));
- out.attribute(null, XML_ATTR_REASON, Integer.toString(pop.reason));
- extrasToXml(out, pop.extras);
- out.endTag(null, "op");
- }
- out.endTag(null, "pending");
- out.endDocument();
- mPendingFile.finishWrite(fos);
- } catch (java.io.IOException e1) {
- Log.w(TAG, "Error writing pending operations", e1);
- if (fos != null) {
- mPendingFile.failWrite(fos);
- }
- }
- }
-
private void extrasToXml(XmlSerializer out, Bundle extras) throws java.io.IOException {
for (String key : extras.keySet()) {
out.startTag(null, "extra");
@@ -2479,35 +2501,6 @@
}
}
-// /**
-// * Update the pending ops file, if e
-// */
-// private void appendPendingOperationLocked(PendingOperation op) {
-// if (DEBUG_FILE) Log.v(TAG, "Appending to " + mPendingFile.getBaseFile());
-// FileOutputStream fos = null;
-// try {
-// fos = mPendingFile.openAppend();
-// } catch (java.io.IOException e) {
-// if (DEBUG_FILE) Log.v(TAG, "Failed append; writing full file");
-// writePendingOperationsLocked();
-// return;
-// }
-//
-// try {
-// Parcel out = Parcel.obtain();
-// writePendingOperationLocked(op, out);
-// fos.write(out.marshall());
-// out.recycle();
-// } catch (java.io.IOException e1) {
-// Log.w(TAG, "Error writing pending operations", e1);
-// } finally {
-// try {
-// fos.close();
-// } catch (java.io.IOException e2) {
-// }
-// }
-// }
-
private void requestSync(Account account, int userId, int reason, String authority,
Bundle extras) {
// If this is happening in the system process, then call the syncrequest listener
@@ -2568,7 +2561,9 @@
* Write all sync statistics to the sync status file.
*/
private void writeStatisticsLocked() {
- if (DEBUG_FILE) Log.v(TAG, "Writing new " + mStatisticsFile.getBaseFile());
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG, "Writing new " + mStatisticsFile.getBaseFile());
+ }
// The file is being written, so we don't need to have a scheduled
// write until the next change.
@@ -2611,7 +2606,7 @@
sb.append("Pending Ops: ").append(mPendingOperations.size()).append(" operation(s)\n");
for (PendingOperation pop : mPendingOperations) {
sb.append("(" + pop.account)
- .append(", " + pop.userId)
+ .append(", u" + pop.userId)
.append(", " + pop.authority)
.append(", " + pop.extras)
.append(")\n");
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index db030f1..c215f40 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -345,6 +345,12 @@
return mBatchedScanSupported;
}
+ public void pollBatchedScan() {
+ enforceChangePermission();
+ if (mBatchedScanSupported == false) return;
+ mWifiStateMachine.requestBatchedScanPoll();
+ }
+
/**
* see {@link android.net.wifi.WifiManager#requestBatchedScan()}
*/
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
index dff6661..e44652f 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
@@ -67,7 +67,7 @@
/**
* Test that we handle the case of a history row being old enough to purge before the
- * correcponding sync is finished. This can happen if the clock changes while we are syncing.
+ * corresponding sync is finished. This can happen if the clock changes while we are syncing.
*
*/
// TODO: this test causes AidlTest to fail. Omit for now
@@ -104,6 +104,17 @@
engine.clearAndReadState();
assert(engine.getPendingOperationCount() == 1);
+ List<SyncStorageEngine.PendingOperation> pops = engine.getPendingOperations();
+ SyncStorageEngine.PendingOperation popRetrieved = pops.get(0);
+ assertEquals(pop.account, popRetrieved.account);
+ assertEquals(pop.reason, popRetrieved.reason);
+ assertEquals(pop.userId, popRetrieved.userId);
+ assertEquals(pop.syncSource, popRetrieved.syncSource);
+ assertEquals(pop.authority, popRetrieved.authority);
+ assertEquals(pop.expedited, popRetrieved.expedited);
+ assertEquals(pop.serviceName, popRetrieved.serviceName);
+ assert(android.content.PeriodicSync.syncExtrasEquals(pop.extras, popRetrieved.extras));
+
}
/**
diff --git a/wifi/java/android/net/wifi/BatchedScanSettings.java b/wifi/java/android/net/wifi/BatchedScanSettings.java
index 82945d6..44a2ab4 100644
--- a/wifi/java/android/net/wifi/BatchedScanSettings.java
+++ b/wifi/java/android/net/wifi/BatchedScanSettings.java
@@ -51,6 +51,7 @@
public final static int MAX_AP_FOR_DISTANCE = MAX_AP_PER_SCAN;
public final static int DEFAULT_AP_FOR_DISTANCE = 0;
+ public final static int MAX_WIFI_CHANNEL = 196;
/** The expected number of scans per batch. Note that the firmware may drop scans
* leading to fewer scans during the normal batch scan duration. This value need not
@@ -113,7 +114,7 @@
for (String channel : channelSet) {
try {
int i = Integer.parseInt(channel);
- if (i > 0 && i < 197) continue;
+ if (i > 0 && i <= MAX_WIFI_CHANNEL) continue;
} catch (NumberFormatException e) {}
if (channel.equals("A") || channel.equals("B")) continue;
return false;
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index c8cf323..4f68ca0 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -124,5 +124,7 @@
List<BatchedScanResult> getBatchedScanResults(String callingPackage);
boolean isBatchedScanSupported();
+
+ void pollBatchedScan();
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 01ca378..a15b664 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -840,6 +840,32 @@
}
/**
+ * Force a re-reading of batched scan results. This will attempt
+ * to read more information from the chip, but will do so at the expense
+ * of previous data. Rate limited to the current scan frequency.
+ *
+ * pollBatchedScan will always wait 1 period from the start of the batch
+ * before trying to read from the chip, so if your #scans/batch == 1 this will
+ * have no effect.
+ *
+ * If you had already waited 1 period before calling, this should have
+ * immediate (though async) effect.
+ *
+ * If you call before that 1 period is up this will set up a timer and fetch
+ * results when the 1 period is up.
+ *
+ * Servicing a pollBatchedScan request (immediate or after timed delay) starts a
+ * new batch, so if you were doing 10 scans/batch and called in the 4th scan, you
+ * would get data in the 4th and then again 10 scans later.
+ * @hide
+ */
+ public void pollBatchedScan() {
+ try {
+ mService.pollBatchedScan();
+ } catch (RemoteException e) { }
+ }
+
+ /**
* Return dynamic information about the current Wi-Fi connection, if any is active.
* @return the Wi-Fi information, contained in {@link WifiInfo}.
*/
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 0359076..c3ed03c 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -82,8 +82,13 @@
public WifiNative(String interfaceName) {
mInterfaceName = interfaceName;
- mInterfacePrefix = "IFNAME=" + interfaceName + " ";
mTAG = "WifiNative-" + interfaceName;
+ if (!interfaceName.equals("p2p0")) {
+ mInterfacePrefix = "IFNAME=" + interfaceName + " ";
+ } else {
+ // commands for p2p0 interface don't need prefix
+ mInterfacePrefix = "";
+ }
}
public boolean connectToSupplicant() {
@@ -221,8 +226,9 @@
/**
* Format of command
- * DRIVER WLS_BATCHING SET SCAN_FRQ=x BESTN=y CHANNEL=<z, w, t> RTT=s
+ * DRIVER WLS_BATCHING SET SCAN_FRQ=x MSCAN=r BESTN=y CHANNEL=<z, w, t> RTT=s
* where x is an ascii representation of an integer number of seconds between scans
+ * r is an ascii representation of an integer number of scans per batch
* y is an ascii representation of an integer number of the max AP to remember per scan
* z, w, t represent a 1..n size list of channel numbers and/or 'A', 'B' values
* indicating entire ranges of channels
@@ -235,8 +241,9 @@
public String setBatchedScanSettings(BatchedScanSettings settings) {
if (settings == null) return doStringCommand("DRIVER WLS_BATCHING STOP");
String cmd = "DRIVER WLS_BATCHING SET SCAN_FRQ=" + settings.scanIntervalSec;
+ cmd += " MSCAN=" + settings.maxScansPerBatch;
if (settings.maxApPerScan != BatchedScanSettings.UNSPECIFIED) {
- cmd += " BESTN " + settings.maxApPerScan;
+ cmd += " BESTN=" + settings.maxApPerScan;
}
if (settings.channelSet != null && !settings.channelSet.isEmpty()) {
cmd += " CHANNEL=<";
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 764c00a..8b7b8ae 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -127,6 +127,8 @@
private final List<BatchedScanResult> mBatchedScanResults =
new ArrayList<BatchedScanResult>();
private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE;
+ private int mExpectedBatchedScans = 0;
+ private long mBatchedScanMinPollTime = 0;
/* Chipset supports background scan */
private final boolean mBackgroundScanSupported;
@@ -366,8 +368,9 @@
* arg1 = responsible UID
* obj = the new settings
*/
- public static final int CMD_SET_BATCH_SCAN = BASE + 135;
+ public static final int CMD_SET_BATCHED_SCAN = BASE + 135;
public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136;
+ public static final int CMD_POLL_BATCHED_SCAN = BASE + 137;
public static final int CONNECT_MODE = 1;
public static final int SCAN_ONLY_MODE = 2;
@@ -766,7 +769,7 @@
* start or stop batched scanning using the given settings
*/
public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid) {
- sendMessage(CMD_SET_BATCH_SCAN, callingUid, 0, settings);
+ sendMessage(CMD_SET_BATCHED_SCAN, callingUid, 0, settings);
}
public List<BatchedScanResult> syncGetBatchedScanResultsList() {
@@ -780,6 +783,10 @@
}
}
+ public void requestBatchedScanPoll() {
+ sendMessage(CMD_POLL_BATCHED_SCAN);
+ }
+
private void startBatchedScan() {
// first grab any existing data
retrieveBatchedScanData();
@@ -789,8 +796,8 @@
String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings);
try {
- int expected = Integer.parseInt(scansExpected);
- setNextBatchedAlarm(expected);
+ mExpectedBatchedScans = Integer.parseInt(scansExpected);
+ setNextBatchedAlarm(mExpectedBatchedScans);
} catch (NumberFormatException e) {
loge("Exception parsing WifiNative.setBatchedScanSettings response " + e);
}
@@ -803,9 +810,27 @@
private void startNextBatchedScan() {
// first grab any existing data
- int nextCount = retrieveBatchedScanData();
+ retrieveBatchedScanData();
- setNextBatchedAlarm(nextCount);
+ setNextBatchedAlarm(mExpectedBatchedScans);
+ }
+
+ private void handleBatchedScanPollRequest() {
+ // if there is no appropriate PollTime that's because we either aren't
+ // batching or we've already set a time for a poll request
+ if (mBatchedScanMinPollTime == 0) return;
+ if (mBatchedScanSettings == null) return;
+
+ long now = System.currentTimeMillis();
+
+ if (now > mBatchedScanMinPollTime) {
+ // do the poll and reset our timers
+ startNextBatchedScan();
+ } else {
+ mAlarmManager.set(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime,
+ mBatchedScanIntervalIntent);
+ mBatchedScanMinPollTime = 0;
+ }
}
// return true if new/different
@@ -832,6 +857,9 @@
if (mBatchedScanSettings == null || scansExpected < 1) return;
+ mBatchedScanMinPollTime = System.currentTimeMillis() +
+ mBatchedScanSettings.scanIntervalSec * 1000;
+
if (mBatchedScanSettings.maxScansPerBatch < scansExpected) {
scansExpected = mBatchedScanSettings.maxScansPerBatch;
}
@@ -876,22 +904,18 @@
* etc
* "----"
*/
- private int retrieveBatchedScanData() {
+ private void retrieveBatchedScanData() {
String rawData = mWifiNative.getBatchedScanResults();
+ mBatchedScanMinPollTime = 0;
if (rawData == null) {
loge("Unexpected null BatchedScanResults");
- return 0;
+ return;
}
- int nextCount = 0;
int scanCount = 0;
- final String END_OF_SCAN = "====";
- final String END_OF_BATCH = "%%%%";
final String END_OF_BATCHES = "----";
final String SCANCOUNT = "scancount=";
- final String NEXTCOUNT = "nextcount=";
final String TRUNCATED = "trunc";
- final String APCOUNT = "apcount=";
final String AGE = "age=";
final String DIST = "dist=";
final String DISTSD = "distsd=";
@@ -905,16 +929,7 @@
}
if (scanCount == 0) {
loge("scanCount not found");
- return 0;
- }
- if (splitData[n].startsWith(NEXTCOUNT)) {
- try {
- nextCount = Integer.parseInt(splitData[n++].substring(NEXTCOUNT.length()));
- } catch (NumberFormatException e) {}
- }
- if (nextCount == 0) {
- loge("nextCount not found");
- return 0;
+ return;
}
final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION);
@@ -942,9 +957,9 @@
if (mBatchedScanResults.size() > 0) {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- return nextCount;
+ return;
}
- if ((splitData[n].equals(END_OF_SCAN)) || splitData[n].equals(END_OF_BATCH)) {
+ if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) {
if (bssid != null) {
batchedScanResult.scanResults.add(new ScanResult(
wifiSsid, bssid, "", level, freq, tsf, dist, distSd));
@@ -955,7 +970,7 @@
tsf = 0;
dist = distSd = ScanResult.UNSPECIFIED;
}
- if (splitData[n].equals(END_OF_BATCH)) {
+ if (splitData[n].equals(END_STR)) {
if (batchedScanResult.scanResults.size() != 0) {
mBatchedScanResults.add(batchedScanResult);
batchedScanResult = new BatchedScanResult();
@@ -1010,7 +1025,7 @@
rawData = mWifiNative.getBatchedScanResults();
if (rawData == null) {
loge("Unexpected null BatchedScanResults");
- return nextCount;
+ return;
}
splitData = rawData.split("\n");
if (splitData.length == 0 || splitData[0].equals("ok")) {
@@ -1018,7 +1033,7 @@
if (mBatchedScanResults.size() > 0) {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- return nextCount;
+ return;
}
n = 0;
}
@@ -2266,9 +2281,11 @@
sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, countryCode);
}
break;
- case CMD_SET_BATCH_SCAN:
+ case CMD_SET_BATCHED_SCAN:
recordBatchedScanSettings((BatchedScanSettings)message.obj);
break;
+ case CMD_POLL_BATCHED_SCAN:
+ handleBatchedScanPollRequest();
case CMD_START_NEXT_BATCHED_SCAN:
startNextBatchedScan();
break;
@@ -2808,7 +2825,7 @@
noteScanStart(message.arg1, (WorkSource) message.obj);
startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
break;
- case CMD_SET_BATCH_SCAN:
+ case CMD_SET_BATCHED_SCAN:
recordBatchedScanSettings((BatchedScanSettings)message.obj);
startBatchedScan();
break;