diff options
65 files changed, 1560 insertions, 836 deletions
diff --git a/Android.mk b/Android.mk index 7dfa6a0c67a8..278e67f9649a 100644 --- a/Android.mk +++ b/Android.mk @@ -297,6 +297,7 @@ LOCAL_SRC_FILES += \ location/java/android/location/IGeocodeProvider.aidl \ location/java/android/location/IGeofenceProvider.aidl \ location/java/android/location/IGpsMeasurementsListener.aidl \ + location/java/android/location/IGpsNavigationMessageListener.aidl \ location/java/android/location/IGpsStatusListener.aidl \ location/java/android/location/IGpsStatusProvider.aidl \ location/java/android/location/ILocationListener.aidl \ diff --git a/api/current.txt b/api/current.txt index f1c42e77e707..84f9912e4071 100644 --- a/api/current.txt +++ b/api/current.txt @@ -16202,7 +16202,7 @@ package android.media.browse { method public int describeContents(); method public android.os.Bundle getExtras(); method public int getFlags(); - method public int getIconResId(); + method public int getIconResourceId(); method public android.net.Uri getIconUri(); method public java.lang.CharSequence getSummary(); method public java.lang.CharSequence getTitle(); @@ -16219,7 +16219,7 @@ package android.media.browse { ctor public MediaBrowserItem.Builder(android.net.Uri, int, java.lang.CharSequence); method public android.media.browse.MediaBrowserItem build(); method public android.media.browse.MediaBrowserItem.Builder setExtras(android.os.Bundle); - method public android.media.browse.MediaBrowserItem.Builder setIconResId(int); + method public android.media.browse.MediaBrowserItem.Builder setIconResourceId(int); method public android.media.browse.MediaBrowserItem.Builder setIconUri(android.net.Uri); method public android.media.browse.MediaBrowserItem.Builder setSummary(java.lang.CharSequence); } @@ -16230,15 +16230,17 @@ package android.media.browse { method public android.media.session.MediaSession.Token getSessionToken(); method public void notifyChildrenChanged(android.net.Uri); method public android.os.IBinder onBind(android.content.Intent); - method protected abstract android.media.browse.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle); - method protected abstract android.graphics.Bitmap onGetThumbnail(android.net.Uri, int, int); - method protected abstract java.util.List<android.media.browse.MediaBrowserItem> onLoadChildren(android.net.Uri); + method public abstract android.media.browse.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle); + method public abstract android.graphics.Bitmap onGetThumbnail(android.net.Uri, int, int); + method public abstract java.util.List<android.media.browse.MediaBrowserItem> onLoadChildren(android.net.Uri); method public void setSessionToken(android.media.session.MediaSession.Token); field public static final java.lang.String SERVICE_ACTION = "android.media.browse.MediaBrowserService"; } - public static class MediaBrowserService.BrowserRoot { + public static final class MediaBrowserService.BrowserRoot { ctor public MediaBrowserService.BrowserRoot(android.net.Uri, android.os.Bundle); + method public android.os.Bundle getExtras(); + method public android.net.Uri getRootUri(); } } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 3f705ac66541..287ea35e31e0 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2682,8 +2682,7 @@ public class Intent implements Parcelable, Cloneable { "android.intent.action.QUICK_CLOCK"; /** - * Broadcast Action: This is broadcast when a user action should request the - * brightness setting dialog. + * Activity Action: Shows the brightness setting dialog. * @hide */ public static final String ACTION_SHOW_BRIGHTNESS_DIALOG = diff --git a/core/java/android/hardware/hdmi/HdmiRecordSources.java b/core/java/android/hardware/hdmi/HdmiRecordSources.java index 5a02c34ae59a..685eb170fddb 100644 --- a/core/java/android/hardware/hdmi/HdmiRecordSources.java +++ b/core/java/android/hardware/hdmi/HdmiRecordSources.java @@ -483,6 +483,7 @@ public final class HdmiRecordSources { * </ul> * @hide */ + @SystemApi public static final class DigitalServiceSource extends RecordSource { /** Indicates that a service is identified by digital service IDs. */ private static final int DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID = 0; @@ -604,6 +605,7 @@ public final class HdmiRecordSources { * </ul> * @hide */ + @SystemApi public static final class AnalogueServiceSource extends RecordSource { private static final int EXTRA_DATA_SIZE = 4; @@ -662,6 +664,7 @@ public final class HdmiRecordSources { * </ul> * @hide */ + @SystemApi public static final class ExternalPlugData extends RecordSource { private static final int EXTRA_DATA_SIZE = 1; @@ -706,6 +709,7 @@ public final class HdmiRecordSources { * </ul> * @hide */ + @SystemApi public static final class ExternalPhysicalAddress extends RecordSource { private static final int EXTRA_DATA_SIZE = 2; diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java index f4a044861191..c36421db9b06 100644 --- a/core/java/android/util/PathParser.java +++ b/core/java/android/util/PathParser.java @@ -54,9 +54,11 @@ public class PathParser { ArrayList<PathDataNode> list = new ArrayList<PathDataNode>(); while (end < pathData.length()) { end = nextStart(pathData, end); - String s = pathData.substring(start, end); - float[] val = getFloats(s); - addNode(list, s.charAt(0), val); + String s = pathData.substring(start, end).trim(); + if (s.length() > 0) { + float[] val = getFloats(s); + addNode(list, s.charAt(0), val); + } start = end; end++; @@ -135,6 +137,12 @@ public class PathParser { list.add(new PathDataNode(cmd, val)); } + private static class ExtractFloatResult { + // We need to return the position of the next separator and whether the + // next float starts with a '-'. + int mEndPosition; + boolean mEndWithNegSign; + } /** * Parse the floats in the string. @@ -148,42 +156,73 @@ public class PathParser { return new float[0]; } try { - float[] tmp = new float[s.length()]; + float[] results = new float[s.length()]; int count = 0; - int pos = 1, end; - while ((end = extract(s, pos)) >= 0) { - if (pos < end) { - tmp[count++] = Float.parseFloat(s.substring(pos, end)); + int startPosition = 1; + int endPosition = 0; + + ExtractFloatResult result = new ExtractFloatResult(); + int totalLength = s.length(); + + // The startPosition should always be the first character of the + // current number, and endPosition is the character after the current + // number. + while (startPosition < totalLength) { + extract(s, startPosition, result); + endPosition = result.mEndPosition; + + if (startPosition < endPosition) { + results[count++] = Float.parseFloat( + s.substring(startPosition, endPosition)); + } + + if (result.mEndWithNegSign) { + // Keep the '-' sign with next number. + startPosition = endPosition; + } else { + startPosition = endPosition + 1; } - pos = end + 1; - } - // handle the final float if there is one - if (pos < s.length()) { - tmp[count++] = Float.parseFloat(s.substring(pos, s.length())); } - return Arrays.copyOf(tmp, count); - } catch (NumberFormatException e){ - Log.e(LOGTAG,"error in parsing \""+s+"\""); + return Arrays.copyOf(results, count); + } catch (NumberFormatException e) { + Log.e(LOGTAG, "error in parsing \"" + s + "\""); throw e; } } /** - * Calculate the position of the next comma or space + * Calculate the position of the next comma or space or negative sign * @param s the string to search * @param start the position to start searching - * @return the position of the next comma or space or -1 if none found + * @param result the result of the extraction, including the position of the + * the starting position of next number, whether it is ending with a '-'. */ - private static int extract(String s, int start) { - int space = s.indexOf(' ', start); - int comma = s.indexOf(',', start); - if (space == -1) { - return comma; - } - if (comma == -1) { - return space; + private static void extract(String s, int start, ExtractFloatResult result) { + // Now looking for ' ', ',' or '-' from the start. + int currentIndex = start; + boolean foundSeparator = false; + result.mEndWithNegSign = false; + for (; currentIndex < s.length(); currentIndex++) { + char currentChar = s.charAt(currentIndex); + switch (currentChar) { + case ' ': + case ',': + foundSeparator = true; + break; + case '-': + if (currentIndex != start) { + foundSeparator = true; + result.mEndWithNegSign = true; + } + break; + } + if (foundSeparator) { + break; + } } - return (comma > space) ? space : comma; + // When there is nothing found, then we put the end position to the end + // of the string. + result.mEndPosition = currentIndex; } /** diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index b41e37c56b7f..31920fa8baa0 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4310,8 +4310,9 @@ <!-- Description of a wireless display route. [CHAR LIMIT=50] --> <string name="wireless_display_route_description">Wireless display</string> - <!-- Content description of a MediaRouteButton for accessibility support --> - <string name="media_route_button_content_description">Media output</string> + <!-- Content description of a MediaRouteButton for accessibility support. + Cast is the standard android verb for sending content to a remote device. [CHAR LIMIT=50] --> + <string name="media_route_button_content_description">Cast</string> <!-- Title of the media route chooser dialog. [CHAR LIMIT=40] --> <string name="media_route_chooser_title">Connect to device</string> diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index 13ef89bc4eb1..8ed6776d395a 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -740,9 +740,7 @@ public class VectorDrawable extends Drawable { final float minScale = Math.min(scaleX, scaleY); mFinalPathMatrix.set(vGroup.mStackedMatrix); - mFinalPathMatrix.postScale(scaleX, scaleY, mViewportWidth / 2f, mViewportHeight / 2f); - mFinalPathMatrix.postTranslate( - w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f); + mFinalPathMatrix.postScale(scaleX, scaleY); vPath.toPath(mPath); final Path path = mPath; diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index dd34e095738d..763e72747e83 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -85,8 +85,7 @@ int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos void DrawFrameTask::postAndWait() { AutoMutex _lock(mLock); - mRenderThread->queue(this); - mSignal.wait(mLock); + mRenderThread->queueAndWait(this, mSignal, mLock); } void DrawFrameTask::run() { diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 6cd3d0bdb96b..91f5801d8b60 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -405,8 +405,7 @@ void* RenderProxy::postAndWait(MethodInvokeRenderTask* task) { task->setReturnPtr(&retval); SignalingRenderTask syncTask(task, &mSyncMutex, &mSyncCondition); AutoMutex _lock(mSyncMutex); - mRenderThread.queue(&syncTask); - mSyncCondition.wait(mSyncMutex); + mRenderThread.queueAndWait(&syncTask, mSyncCondition, mSyncMutex); return retval; } diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 03e98d5b2f03..32dc46ee57eb 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -20,6 +20,7 @@ #include <gui/DisplayEventReceiver.h> #include <utils/Log.h> +#include <pthread.h> #include "../RenderState.h" #include "CanvasContext.h" @@ -136,6 +137,7 @@ public: }; RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>() + , mThreadId(0) , mNextWakeup(LLONG_MAX) , mDisplayEventReceiver(0) , mVsyncRequested(false) @@ -244,6 +246,7 @@ void RenderThread::requestVsync() { } bool RenderThread::threadLoop() { + mThreadId = pthread_self(); initThreadLocals(); int timeoutMillis = -1; @@ -289,6 +292,16 @@ void RenderThread::queue(RenderTask* task) { } } +void RenderThread::queueAndWait(RenderTask* task, Condition& signal, Mutex& lock) { + static nsecs_t sTimeout = milliseconds(500); + queue(task); + status_t err = signal.waitRelative(lock, sTimeout); + if (CC_UNLIKELY(err != NO_ERROR)) { + ALOGE("Timeout waiting for RenderTherad! err=%d", err); + nukeFromOrbit(); + } +} + void RenderThread::queueAtFront(RenderTask* task) { AutoMutex _lock(mLock); mQueue.queueAtFront(task); @@ -341,6 +354,10 @@ RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { return next; } +void RenderThread::nukeFromOrbit() { + pthread_kill(mThreadId, SIGABRT); +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 0b91e9dd97aa..59843736f048 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -23,6 +23,7 @@ #include <set> #include <cutils/compiler.h> +#include <utils/Condition.h> #include <utils/Looper.h> #include <utils/Mutex.h> #include <utils/Singleton.h> @@ -73,6 +74,7 @@ public: // RenderThread takes complete ownership of tasks that are queued // and will delete them after they are run ANDROID_API void queue(RenderTask* task); + void queueAndWait(RenderTask* task, Condition& signal, Mutex& lock); ANDROID_API void queueAtFront(RenderTask* task); void queueDelayed(RenderTask* task, int delayMs); void remove(RenderTask* task); @@ -106,11 +108,15 @@ private: void dispatchFrameCallbacks(); void requestVsync(); + // VERY DANGEROUS HANDLE WITH EXTREME CARE + void nukeFromOrbit(); + // Returns the next task to be run. If this returns NULL nextWakeup is set // to the time to requery for the nextTask to run. mNextWakeup is also // set to this time RenderTask* nextTask(nsecs_t* nextWakeup); + pthread_t mThreadId; sp<Looper> mLooper; Mutex mLock; diff --git a/location/java/android/location/GpsMeasurementListenerTransport.java b/location/java/android/location/GpsMeasurementListenerTransport.java index 48a4b4422998..2d9a37273fea 100644 --- a/location/java/android/location/GpsMeasurementListenerTransport.java +++ b/location/java/android/location/GpsMeasurementListenerTransport.java @@ -16,99 +16,51 @@ package android.location; -import com.android.internal.util.Preconditions; - -import android.annotation.NonNull; import android.content.Context; import android.os.RemoteException; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; /** - * A handler class to manage transport listeners for {@link GpsMeasurementsEvent.Listener}, - * and post the events in a handler. + * A handler class to manage transport listeners for {@link GpsMeasurementsEvent.Listener}. * * @hide */ -class GpsMeasurementListenerTransport { - private static final String TAG = "GpsMeasurementListenerTransport"; - +class GpsMeasurementListenerTransport + extends LocalListenerHelper<GpsMeasurementsEvent.Listener> { private final Context mContext; private final ILocationManager mLocationManager; private final IGpsMeasurementsListener mListenerTransport = new ListenerTransport(); - private final HashSet<GpsMeasurementsEvent.Listener> mListeners = - new HashSet<GpsMeasurementsEvent.Listener>(); public GpsMeasurementListenerTransport(Context context, ILocationManager locationManager) { + super("GpsMeasurementListenerTransport"); mContext = context; mLocationManager = locationManager; } - public boolean add(@NonNull GpsMeasurementsEvent.Listener listener) { - Preconditions.checkNotNull(listener); - - synchronized (mListeners) { - // we need to register with the service first, because we need to find out if the - // service will actually support the request before we attempt anything - if (mListeners.isEmpty()) { - boolean registeredWithServer; - try { - registeredWithServer = mLocationManager.addGpsMeasurementsListener( - mListenerTransport, - mContext.getPackageName()); - } catch (RemoteException e) { - Log.e(TAG, "Error handling first listener.", e); - return false; - } - - if (!registeredWithServer) { - Log.e(TAG, "Unable to register listener transport."); - return false; - } - } - - if (mListeners.contains(listener)) { - return true; - } - - mListeners.add(listener); - } - - return true; + @Override + protected boolean registerWithServer() throws RemoteException { + return mLocationManager.addGpsMeasurementsListener( + mListenerTransport, + mContext.getPackageName()); } - public void remove(@NonNull GpsMeasurementsEvent.Listener listener) { - Preconditions.checkNotNull(listener); - - synchronized (mListeners) { - boolean removed = mListeners.remove(listener); - - boolean isLastListener = removed && mListeners.isEmpty(); - if (isLastListener) { - try { - mLocationManager.removeGpsMeasurementsListener(mListenerTransport); - } catch (RemoteException e) { - Log.e(TAG, "Error handling last listener.", e); - } - } - } + @Override + protected void unregisterFromServer() throws RemoteException { + mLocationManager.removeGpsMeasurementsListener(mListenerTransport); } private class ListenerTransport extends IGpsMeasurementsListener.Stub { @Override - public void onGpsMeasurementsReceived(final GpsMeasurementsEvent eventArgs) { - Collection<GpsMeasurementsEvent.Listener> listeners; - synchronized (mListeners) { - listeners = new ArrayList<GpsMeasurementsEvent.Listener>(mListeners); - } + public void onGpsMeasurementsReceived(final GpsMeasurementsEvent event) { + ListenerOperation<GpsMeasurementsEvent.Listener> operation = + new ListenerOperation<GpsMeasurementsEvent.Listener>() { + @Override + public void execute(GpsMeasurementsEvent.Listener listener) throws RemoteException { + listener.onGpsMeasurementsReceived(event); + } + }; - for (final GpsMeasurementsEvent.Listener listener : listeners) { - listener.onGpsMeasurementsReceived(eventArgs); - } + foreach(operation); } } } diff --git a/location/java/android/location/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java new file mode 100644 index 000000000000..2eb4708164d7 --- /dev/null +++ b/location/java/android/location/GpsNavigationMessage.java @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.location; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +import java.security.InvalidParameterException; + +/** + * A class containing a GPS satellite Navigation Message. + * + * @hide + */ +public class GpsNavigationMessage implements Parcelable { + private static final String TAG = "GpsNavigationMessage"; + private static final byte[] EMPTY_ARRAY = new byte[0]; + + // The following enumerations must be in sync with the values declared in gps.h + + /** + * The type of the navigation message is not available or unknown. + */ + public static final byte TYPE_UNKNOWN = 0; + + /** + * The Navigation Message is of type L1 C/A. + */ + public static final byte TYPE_L1CA = 1; + + /** + * The Navigation Message is of type L1-CNAV. + */ + public static final byte TYPE_L2CNAV = 2; + + /** + * The Navigation Message is of type L5-CNAV. + */ + public static final byte TYPE_L5CNAV = 3; + + /** + * The Navigation Message is of type CNAV-2. + */ + public static final byte TYPE_CNAV2 = 4; + + // End enumerations in sync with gps.h + + private byte mType; + private byte mPrn; + private short mMessageId; + private short mSubmessageId; + private byte[] mData; + + GpsNavigationMessage() { + initialize(); + } + + /** + * Sets all contents to the values stored in the provided object. + */ + public void set(GpsNavigationMessage navigationMessage) { + mType = navigationMessage.mType; + mPrn = navigationMessage.mPrn; + mMessageId = navigationMessage.mMessageId; + mSubmessageId = navigationMessage.mSubmessageId; + mData = navigationMessage.mData; + } + + /** + * Resets all the contents to its original state. + */ + public void reset() { + initialize(); + } + + /** + * Gets the type of the navigation message contained in the object. + */ + public byte getType() { + return mType; + } + + /** + * Sets the type of the navigation message. + */ + public void setType(byte value) { + switch (value) { + case TYPE_UNKNOWN: + case TYPE_L1CA: + case TYPE_L2CNAV: + case TYPE_L5CNAV: + case TYPE_CNAV2: + mType = value; + break; + default: + Log.d(TAG, "Sanitizing invalid 'type': " + value); + mType = TYPE_UNKNOWN; + break; + } + } + + /** + * Gets a string representation of the 'type'. + * For internal and logging use only. + */ + private String getTypeString() { + switch (mType) { + case TYPE_UNKNOWN: + return "Unknown"; + case TYPE_L1CA: + return "L1 C/A"; + case TYPE_L2CNAV: + return "L2-CNAV"; + case TYPE_L5CNAV: + return "L5-CNAV"; + case TYPE_CNAV2: + return "CNAV-2"; + default: + return "<Invalid>"; + } + } + + /** + * Gets the Pseudo-random number. + * Range: [1, 32]. + */ + public byte getPrn() { + return mPrn; + } + + /** + * Sets the Pseud-random number. + */ + public void setPrn(byte value) { + mPrn = value; + } + + /** + * Gets the Message Identifier. + * It provides an index so the complete Navigation Message can be assembled. i.e. for L1 C/A + * subframe 4 and 5, this value corresponds to the 'frame id' of the navigation message. + * Subframe 1, 2, 3 does not contain a 'frame id' and this might be reported as -1. + */ + public short getMessageId() { + return mMessageId; + } + + /** + * Sets the Message Identifier. + */ + public void setMessageId(short value) { + mMessageId = value; + } + + /** + * Gets the Sub-message Identifier. + * If required by {@link #getType()}, this value contains a sub-index within the current message + * (or frame) that is being transmitted. i.e. for L1 C/A the sub-message identifier corresponds + * to the sub-frame Id of the navigation message. + */ + public short getSubmessageId() { + return mSubmessageId; + } + + /** + * Sets the Sub-message identifier. + */ + public void setSubmessageId(short value) { + mSubmessageId = value; + } + + /** + * Gets the data associated with the Navigation Message. + * The bytes (or words) specified using big endian format (MSB first). + */ + @NonNull + public byte[] getData() { + return mData; + } + + /** + * Sets the data associated with the Navigation Message. + */ + public void setData(byte[] value) { + if (value == null) { + throw new InvalidParameterException("Data must be a non-null array"); + } + + mData = value; + } + + public static final Creator<GpsNavigationMessage> CREATOR = + new Creator<GpsNavigationMessage>() { + @Override + public GpsNavigationMessage createFromParcel(Parcel parcel) { + GpsNavigationMessage navigationMessage = new GpsNavigationMessage(); + + navigationMessage.setType(parcel.readByte()); + navigationMessage.setPrn(parcel.readByte()); + navigationMessage.setMessageId((short) parcel.readInt()); + navigationMessage.setSubmessageId((short) parcel.readInt()); + + int dataLength = parcel.readInt(); + byte[] data = new byte[dataLength]; + parcel.readByteArray(data); + navigationMessage.setData(data); + + return navigationMessage; + } + + @Override + public GpsNavigationMessage[] newArray(int size) { + return new GpsNavigationMessage[size]; + } + }; + + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeByte(mType); + parcel.writeByte(mPrn); + parcel.writeInt(mMessageId); + parcel.writeInt(mSubmessageId); + parcel.writeInt(mData.length); + parcel.writeByteArray(mData); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + final String format = " %-15s = %s\n"; + StringBuilder builder = new StringBuilder("GpsNavigationMessage:\n"); + + builder.append(String.format(format, "Type", getTypeString())); + builder.append(String.format(format, "Prn", mPrn)); + builder.append(String.format(format, "MessageId", mMessageId)); + builder.append(String.format(format, "SubmessageId", mSubmessageId)); + + builder.append(String.format(format, "Data", "{")); + String prefix = " "; + for(byte value : mData) { + builder.append(prefix); + builder.append(value); + prefix = ", "; + } + builder.append(" }"); + + return builder.toString(); + } + + private void initialize() { + mType = TYPE_UNKNOWN; + mPrn = 0; + mMessageId = -1; + mSubmessageId = -1; + mData = EMPTY_ARRAY; + } +} diff --git a/location/java/android/location/GpsNavigationMessageEvent.aidl b/location/java/android/location/GpsNavigationMessageEvent.aidl new file mode 100644 index 000000000000..f84c2f72ca17 --- /dev/null +++ b/location/java/android/location/GpsNavigationMessageEvent.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +parcelable GpsNavigationMessageEvent; diff --git a/location/java/android/location/GpsNavigationMessageEvent.java b/location/java/android/location/GpsNavigationMessageEvent.java new file mode 100644 index 000000000000..50ffa75d3fa4 --- /dev/null +++ b/location/java/android/location/GpsNavigationMessageEvent.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.location; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.security.InvalidParameterException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +/** + * A class implementing a container for data associated with a navigation message event. + * Events are delivered to registered instances of {@link Listener}. + * + * @hide + */ +public class GpsNavigationMessageEvent implements Parcelable { + private final GpsNavigationMessage mNavigationMessage; + + /** + * Used for receiving GPS satellite Navigation Messages from the GPS engine. + * You can implement this interface and call + * {@link LocationManager#addGpsNavigationMessageListener}. + * + * @hide + */ + public interface Listener { + void onGpsNavigationMessageReceived(GpsNavigationMessageEvent event); + } + + public GpsNavigationMessageEvent(GpsNavigationMessage message) { + if (message == null) { + throw new InvalidParameterException("Parameter 'message' must not be null."); + } + mNavigationMessage = message; + } + + @NonNull + public GpsNavigationMessage getNavigationMessage() { + return mNavigationMessage; + } + + public static final Creator<GpsNavigationMessageEvent> CREATOR = + new Creator<GpsNavigationMessageEvent>() { + @Override + public GpsNavigationMessageEvent createFromParcel(Parcel in) { + ClassLoader classLoader = getClass().getClassLoader(); + GpsNavigationMessage navigationMessage = in.readParcelable(classLoader); + return new GpsNavigationMessageEvent(navigationMessage); + } + + @Override + public GpsNavigationMessageEvent[] newArray(int size) { + return new GpsNavigationMessageEvent[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeParcelable(mNavigationMessage, flags); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("[ GpsNavigationMessageEvent:\n\n"); + builder.append(mNavigationMessage.toString()); + builder.append("\n]"); + return builder.toString(); + } +} diff --git a/location/java/android/location/GpsNavigationMessageListenerTransport.java b/location/java/android/location/GpsNavigationMessageListenerTransport.java new file mode 100644 index 000000000000..ec4812bca7c7 --- /dev/null +++ b/location/java/android/location/GpsNavigationMessageListenerTransport.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.location; + +import android.content.Context; +import android.os.RemoteException; + +/** + * A handler class to manage transport listeners for {@link GpsNavigationMessageEvent.Listener}. + * + * @hide + */ +class GpsNavigationMessageListenerTransport + extends LocalListenerHelper<GpsNavigationMessageEvent.Listener> { + private final Context mContext; + private final ILocationManager mLocationManager; + + private final IGpsNavigationMessageListener mListenerTransport = new ListenerTransport(); + + public GpsNavigationMessageListenerTransport( + Context context, + ILocationManager locationManager) { + super("GpsNavigationMessageListenerTransport"); + mContext = context; + mLocationManager = locationManager; + } + + @Override + protected boolean registerWithServer() throws RemoteException { + return mLocationManager.addGpsNavigationMessageListener( + mListenerTransport, + mContext.getPackageName()); + } + + @Override + protected void unregisterFromServer() throws RemoteException { + mLocationManager.removeGpsNavigationMessageListener(mListenerTransport); + } + + private class ListenerTransport extends IGpsNavigationMessageListener.Stub { + @Override + public void onGpsNavigationMessageReceived(final GpsNavigationMessageEvent event) { + ListenerOperation<GpsNavigationMessageEvent.Listener> operation = + new ListenerOperation<GpsNavigationMessageEvent.Listener>() { + @Override + public void execute(GpsNavigationMessageEvent.Listener listener) + throws RemoteException { + listener.onGpsNavigationMessageReceived(event); + } + }; + + foreach(operation); + } + } +} diff --git a/location/java/android/location/IGpsNavigationMessageListener.aidl b/location/java/android/location/IGpsNavigationMessageListener.aidl new file mode 100644 index 000000000000..18603feb1967 --- /dev/null +++ b/location/java/android/location/IGpsNavigationMessageListener.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +import android.location.GpsNavigationMessageEvent; + +/** + * {@hide} + */ +oneway interface IGpsNavigationMessageListener { + void onGpsNavigationMessageReceived(in GpsNavigationMessageEvent event); +} diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index a1acaf12371c..150171028958 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -22,6 +22,7 @@ import android.location.Criteria; import android.location.GeocoderParams; import android.location.Geofence; import android.location.IGpsMeasurementsListener; +import android.location.IGpsNavigationMessageListener; import android.location.IGpsStatusListener; import android.location.ILocationListener; import android.location.Location; @@ -63,6 +64,11 @@ interface ILocationManager boolean addGpsMeasurementsListener(in IGpsMeasurementsListener listener, in String packageName); boolean removeGpsMeasurementsListener(in IGpsMeasurementsListener listener); + boolean addGpsNavigationMessageListener( + in IGpsNavigationMessageListener listener, + in String packageName); + boolean removeGpsNavigationMessageListener(in IGpsNavigationMessageListener listener); + // --- deprecated --- List<String> getAllProviders(); List<String> getProviders(in Criteria criteria, boolean enabledOnly); diff --git a/location/java/android/location/LocalListenerHelper.java b/location/java/android/location/LocalListenerHelper.java new file mode 100644 index 000000000000..1f3bf6792812 --- /dev/null +++ b/location/java/android/location/LocalListenerHelper.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.location; + +import com.android.internal.util.Preconditions; + +import android.annotation.NonNull; +import android.os.RemoteException; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; + +/** + * A base handler class to manage transport and local listeners. + * + * @hide + */ +abstract class LocalListenerHelper<TListener> { + private final HashSet<TListener> mListeners = new HashSet<TListener>(); + private final String mTag; + + protected LocalListenerHelper(String name) { + Preconditions.checkNotNull(name); + mTag = name; + } + + public boolean add(@NonNull TListener listener) { + Preconditions.checkNotNull(listener); + + synchronized (mListeners) { + // we need to register with the service first, because we need to find out if the + // service will actually support the request before we attempt anything + if (mListeners.isEmpty()) { + boolean registeredWithService; + try { + registeredWithService = registerWithServer(); + } catch (RemoteException e) { + Log.e(mTag, "Error handling first listener.", e); + return false; + } + if (!registeredWithService) { + Log.e(mTag, "Unable to register listener transport."); + return false; + } + } + + if (mListeners.contains(listener)) { + return true; + } + mListeners.add(listener); + } + return true; + } + + public void remove(@NonNull TListener listener) { + Preconditions.checkNotNull(listener); + + synchronized (mListeners) { + boolean removed = mListeners.remove(listener); + boolean isLastRemoved = removed && mListeners.isEmpty(); + if (isLastRemoved) { + try { + unregisterFromServer(); + } catch (RemoteException e) { + + } + } + } + } + + protected abstract boolean registerWithServer() throws RemoteException; + protected abstract void unregisterFromServer() throws RemoteException; + + protected interface ListenerOperation<TListener> { + void execute(TListener listener) throws RemoteException; + } + + protected void foreach(ListenerOperation operation) { + Collection<TListener> listeners; + synchronized (mListeners) { + listeners = new ArrayList<TListener>(mListeners); + } + + for (TListener listener : listeners) { + try { + operation.execute(listener); + } catch (RemoteException e) { + Log.e(mTag, "Error in monitored listener.", e); + // don't return, give a fair chance to all listeners to receive the event + } + } + } +} diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index d6a8fb8eda05..082a158dbb2c 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -59,6 +59,7 @@ public class LocationManager { private final Context mContext; private final ILocationManager mService; private final GpsMeasurementListenerTransport mGpsMeasurementListenerTransport; + private final GpsNavigationMessageListenerTransport mGpsNavigationMessageListenerTransport; private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners = new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>(); private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners = @@ -310,6 +311,8 @@ public class LocationManager { mService = service; mContext = context; mGpsMeasurementListenerTransport = new GpsMeasurementListenerTransport(mContext, mService); + mGpsNavigationMessageListenerTransport = + new GpsNavigationMessageListenerTransport(mContext, mService); } private LocationProvider createProvider(String name, ProviderProperties properties) { @@ -1573,7 +1576,7 @@ public class LocationManager { /** * Adds a GPS Measurement listener. * - * @param listener a {@link android.location.GpsMeasurementsEvent.Listener} object to register. + * @param listener a {@link GpsMeasurementsEvent.Listener} object to register. * @return {@code true} if the listener was successfully registered, {@code false} otherwise. * * @hide @@ -1593,6 +1596,30 @@ public class LocationManager { mGpsMeasurementListenerTransport.remove(listener); } + /** + * Adds a GPS Navigation Message listener. + * + * @param listener a {@link GpsNavigationMessageEvent.Listener} object to register. + * @return {@code true} if the listener was successfully registered, {@code false} otherwise. + * + * @hide + */ + public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) { + return mGpsNavigationMessageListenerTransport.add(listener); + } + + /** + * Removes a GPS Navigation Message listener. + * + * @param listener a {@link GpsNavigationMessageEvent.Listener} object to remove. + * + * @hide + */ + public void removeGpsNavigationMessageListener( + GpsNavigationMessageEvent.Listener listener) { + mGpsNavigationMessageListenerTransport.remove(listener); + } + /** * Retrieves information about the current status of the GPS engine. * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged} diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java index 3c09782b046d..75a89528374d 100644 --- a/media/java/android/media/RemoteController.java +++ b/media/java/android/media/RemoteController.java @@ -395,12 +395,6 @@ import java.util.List; mArtworkWidth = -1; mArtworkHeight = -1; } - if (mIsRegistered) { - mAudioManager.remoteControlDisplayUsesBitmapSize(mRcd, - mArtworkWidth, mArtworkHeight); - } // else new values have been stored, and will be read by AudioManager with - // RemoteController.getArtworkSize() when AudioManager.registerRemoteController() - // is called. } return true; } @@ -1042,7 +1036,8 @@ import java.util.List; boolean canRate = mCurrentSession != null && mCurrentSession.getRatingType() != Rating.RATING_NONE; long editableKeys = canRate ? MediaMetadataEditor.RATING_KEY_BY_USER : 0; - Bundle legacyMetadata = MediaSessionLegacyHelper.getOldMetadata(metadata); + Bundle legacyMetadata = MediaSessionLegacyHelper.getOldMetadata(metadata, + mArtworkWidth, mArtworkHeight); mMetadataEditor = new MetadataEditor(legacyMetadata, editableKeys); metadataEditor = mMetadataEditor; } diff --git a/media/java/android/media/browse/MediaBrowserItem.java b/media/java/android/media/browse/MediaBrowserItem.java index 38e765ffb03a..d0a03426f444 100644 --- a/media/java/android/media/browse/MediaBrowserItem.java +++ b/media/java/android/media/browse/MediaBrowserItem.java @@ -16,6 +16,7 @@ package android.media.browse; +import android.annotation.DrawableRes; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -32,11 +33,11 @@ import java.lang.annotation.RetentionPolicy; */ public final class MediaBrowserItem implements Parcelable { private final Uri mUri; - private final Uri mIconUri; - private final int mIconResId; private final int mFlags; private final CharSequence mTitle; private final CharSequence mSummary; + private final Uri mIconUri; + private final int mIconResourceId; private final Bundle mExtras; /** @hide */ @@ -61,8 +62,8 @@ public final class MediaBrowserItem implements Parcelable { /** * Initialize a MediaBrowserItem object. */ - private MediaBrowserItem(@NonNull Uri uri, @Nullable Uri iconUri, int iconResId, int flags, - @NonNull CharSequence title, CharSequence summary, Bundle extras) { + private MediaBrowserItem(@NonNull Uri uri, int flags, @NonNull CharSequence title, + CharSequence summary, @Nullable Uri iconUri, int iconResourceId, Bundle extras) { if (uri == null) { throw new IllegalArgumentException("uri can not be null"); } @@ -70,11 +71,11 @@ public final class MediaBrowserItem implements Parcelable { throw new IllegalArgumentException("title can not be null"); } mUri = uri; - mIconUri = iconUri; - mIconResId = iconResId; mFlags = flags; mTitle = title; mSummary = summary; + mIconUri = iconUri; + mIconResourceId = iconResourceId; mExtras = extras; } @@ -83,8 +84,6 @@ public final class MediaBrowserItem implements Parcelable { */ private MediaBrowserItem(Parcel in) { mUri = Uri.CREATOR.createFromParcel(in); - mIconUri = Uri.CREATOR.createFromParcel(in); - mIconResId = in.readInt(); mFlags = in.readInt(); mTitle = in.readCharSequence(); if (in.readInt() != 0) { @@ -93,6 +92,12 @@ public final class MediaBrowserItem implements Parcelable { mSummary = null; } if (in.readInt() != 0) { + mIconUri = Uri.CREATOR.createFromParcel(in); + } else { + mIconUri = null; + } + mIconResourceId = in.readInt(); + if (in.readInt() != 0) { mExtras = Bundle.CREATOR.createFromParcel(in); } else { mExtras = null; @@ -107,8 +112,6 @@ public final class MediaBrowserItem implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { mUri.writeToParcel(out, flags); - mIconUri.writeToParcel(out, flags); - out.writeInt(mIconResId); out.writeInt(mFlags); out.writeCharSequence(mTitle); if (mSummary != null) { @@ -117,6 +120,13 @@ public final class MediaBrowserItem implements Parcelable { } else { out.writeInt(0); } + if (mIconUri != null) { + out.writeInt(1); + mIconUri.writeToParcel(out, flags); + } else { + out.writeInt(0); + } + out.writeInt(mIconResourceId); if (mExtras != null) { out.writeInt(1); mExtras.writeToParcel(out, flags); @@ -127,16 +137,16 @@ public final class MediaBrowserItem implements Parcelable { public static final Parcelable.Creator<MediaBrowserItem> CREATOR = new Parcelable.Creator<MediaBrowserItem>() { - @Override - public MediaBrowserItem createFromParcel(Parcel in) { - return new MediaBrowserItem(in); - } + @Override + public MediaBrowserItem createFromParcel(Parcel in) { + return new MediaBrowserItem(in); + } - @Override - public MediaBrowserItem[] newArray(int size) { - return new MediaBrowserItem[size]; - } - }; + @Override + public MediaBrowserItem[] newArray(int size) { + return new MediaBrowserItem[size]; + } + }; /** * Gets the Uri of the item. @@ -146,20 +156,6 @@ public final class MediaBrowserItem implements Parcelable { } /** - * Gets the Uri of the icon. - */ - public @Nullable Uri getIconUri() { - return mIconUri; - } - - /** - * Gets the resource id of the icon. - */ - public int getIconResId() { - return mIconResId; - } - - /** * Gets the flags of the item. */ public @Flags int getFlags() { @@ -203,6 +199,20 @@ public final class MediaBrowserItem implements Parcelable { } /** + * Gets the Uri of the icon. + */ + public @Nullable Uri getIconUri() { + return mIconUri; + } + + /** + * Gets the resource id of the icon. + */ + public @DrawableRes int getIconResourceId() { + return mIconResourceId; + } + + /** * Gets additional service-specified extras about the * item or its content, or null if none. */ @@ -217,9 +227,9 @@ public final class MediaBrowserItem implements Parcelable { private final Uri mUri; private final int mFlags; private final CharSequence mTitle; - private Uri mIconUri; - private int mIconResId; private CharSequence mSummary; + private Uri mIconUri; + private int mIconResourceId; private Bundle mExtras; /** @@ -238,10 +248,18 @@ public final class MediaBrowserItem implements Parcelable { } /** + * Sets summary of the item, or null if none. + */ + public @NonNull Builder setSummary(@Nullable CharSequence summary) { + mSummary = summary; + return this; + } + + /** * Sets the uri of the icon. * <p> - * If both {@link #setIconUri(Uri)} and {@link #setIconResId(int)} are called, - * the resource id will be used to load the icon. + * Either {@link #setIconUri(Uri)} or {@link #setIconResourceId(int)} should be called. + * If both are specified, the resource id will be used to load the icon. * </p> */ public @NonNull Builder setIconUri(@Nullable Uri iconUri) { @@ -251,35 +269,31 @@ public final class MediaBrowserItem implements Parcelable { /** * Sets the resource id of the icon. + * <p> + * Either {@link #setIconUri(Uri)} or {@link #setIconResourceId(int)} should be specified. + * If both are specified, the resource id will be used to load the icon. + * </p> */ - public @NonNull Builder setIconResId(int resId) { - mIconResId = resId; + public @NonNull Builder setIconResourceId(@DrawableRes int ResourceId) { + mIconResourceId = ResourceId; return this; } /** - * Sets summary of the item, or null if none. + * Sets additional service-specified extras about the + * item or its content. */ - public @NonNull Builder setSummary(@Nullable CharSequence summary) { - mSummary = summary; - return this; - } - - /** - * Sets additional service-specified extras about the - * item or its content, or null if none. - */ public @NonNull Builder setExtras(@Nullable Bundle extras) { mExtras = extras; return this; } /** - * Builds the item. - */ + * Builds the item. + */ public @NonNull MediaBrowserItem build() { - return new MediaBrowserItem(mUri, mIconUri, mIconResId, - mFlags, mTitle, mSummary, mExtras); + return new MediaBrowserItem(mUri, mFlags, mTitle, mSummary, mIconUri, + mIconResourceId, mExtras); } } } diff --git a/media/java/android/media/browse/MediaBrowserService.java b/media/java/android/media/browse/MediaBrowserService.java index 57befe7acca2..95a133f8877f 100644 --- a/media/java/android/media/browse/MediaBrowserService.java +++ b/media/java/android/media/browse/MediaBrowserService.java @@ -256,7 +256,7 @@ public abstract class MediaBrowserService extends Service { * for browsing, or null if none. The contents of this bundle may affect * the information returned when browsing. */ - protected abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName, + public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints); /** @@ -266,7 +266,7 @@ public abstract class MediaBrowserService extends Service { * children are to be queried. * @return The list of children, or null if the uri is invalid. */ - protected abstract @Nullable List<MediaBrowserItem> onLoadChildren(@NonNull Uri parentUri); + public abstract @Nullable List<MediaBrowserItem> onLoadChildren(@NonNull Uri parentUri); /** * Called to get the thumbnail of a particular media item. @@ -278,7 +278,7 @@ public abstract class MediaBrowserService extends Service { * @return The file descriptor of the thumbnail, which may then be loaded * using a bitmap factory, or null if the item does not have a thumbnail. */ - protected abstract @Nullable Bitmap onGetThumbnail(@NonNull Uri uri, int width, int height); + public abstract @Nullable Bitmap onGetThumbnail(@NonNull Uri uri, int width, int height); /** * Call to set the media session. @@ -311,20 +311,21 @@ public abstract class MediaBrowserService extends Service { * @param parentUri The uri of the parent media item whose * children changed. */ - public void notifyChildrenChanged(@NonNull Uri parentUri) { + public void notifyChildrenChanged(@NonNull final Uri parentUri) { if (parentUri == null) { throw new IllegalArgumentException("parentUri cannot be null in notifyChildrenChanged"); } - for (IBinder binder : mConnections.keySet()) { - ConnectionRecord connection = mConnections.get(binder); - Set<Uri> uris = connection.subscriptions; - for (Uri uri : uris) { - if (uri.equals(parentUri)) { - performLoadChildren(uri, connection); - break; + mHandler.post(new Runnable() { + @Override + public void run() { + for (IBinder binder : mConnections.keySet()) { + ConnectionRecord connection = mConnections.get(binder); + if (connection.subscriptions.contains(parentUri)) { + performLoadChildren(parentUri, connection); + } } } - } + }); } /** @@ -380,9 +381,19 @@ public abstract class MediaBrowserService extends Service { } } - public static class BrowserRoot { + /** + * Contains information that the browser service needs to send to the client + * when first connected. + */ + public static final class BrowserRoot { final private Uri mUri; final private Bundle mExtras; + + /** + * Constructs a browser root. + * @param uri The root Uri for browsing. + * @param extras Any extras about the browser service. + */ public BrowserRoot(@NonNull Uri uri, @Nullable Bundle extras) { if (uri == null) { throw new IllegalArgumentException("The root uri in BrowserRoot cannot be null. " + @@ -392,11 +403,17 @@ public abstract class MediaBrowserService extends Service { mExtras = extras; } - Uri getRootUri() { + /** + * Gets the root uri for browsing. + */ + public Uri getRootUri() { return mUri; } - Bundle getExtras() { + /** + * Gets any extras about the brwoser service. + */ + public Bundle getExtras() { return mExtras; } } diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java index da1a6edbe7e4..a6963cfe98af 100644 --- a/media/java/android/media/session/MediaSessionLegacyHelper.java +++ b/media/java/android/media/session/MediaSessionLegacyHelper.java @@ -21,6 +21,10 @@ import android.app.PendingIntent.CanceledException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; import android.media.AudioManager; import android.media.MediaMetadata; import android.media.MediaMetadataEditor; @@ -73,19 +77,23 @@ public class MediaSessionLegacyHelper { return sInstance; } - public static Bundle getOldMetadata(MediaMetadata metadata) { + public static Bundle getOldMetadata(MediaMetadata metadata, int artworkWidth, + int artworkHeight) { + boolean includeArtwork = artworkWidth != -1 && artworkHeight != -1; Bundle oldMetadata = new Bundle(); if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM)) { oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ALBUM), metadata.getString(MediaMetadata.METADATA_KEY_ALBUM)); } - if (metadata.containsKey(MediaMetadata.METADATA_KEY_ART)) { + if (includeArtwork && metadata.containsKey(MediaMetadata.METADATA_KEY_ART)) { + Bitmap art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ART); oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK), - metadata.getBitmap(MediaMetadata.METADATA_KEY_ART)); - } else if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART)) { + scaleBitmapIfTooBig(art, artworkWidth, artworkHeight)); + } else if (includeArtwork && metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART)) { // Fall back to album art if the track art wasn't available + Bitmap art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK), - metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)); + scaleBitmapIfTooBig(art, artworkWidth, artworkHeight)); } if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ARTIST)) { oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST), @@ -322,6 +330,41 @@ public class MediaSessionLegacyHelper { } } + /** + * Scale a bitmap to fit the smallest dimension by uniformly scaling the + * incoming bitmap. If the bitmap fits, then do nothing and return the + * original. + * + * @param bitmap + * @param maxWidth + * @param maxHeight + * @return + */ + private static Bitmap scaleBitmapIfTooBig(Bitmap bitmap, int maxWidth, int maxHeight) { + if (bitmap != null) { + final int width = bitmap.getWidth(); + final int height = bitmap.getHeight(); + if (width > maxWidth || height > maxHeight) { + float scale = Math.min((float) maxWidth / width, (float) maxHeight / height); + int newWidth = Math.round(scale * width); + int newHeight = Math.round(scale * height); + Bitmap.Config newConfig = bitmap.getConfig(); + if (newConfig == null) { + newConfig = Bitmap.Config.ARGB_8888; + } + Bitmap outBitmap = Bitmap.createBitmap(newWidth, newHeight, newConfig); + Canvas canvas = new Canvas(outBitmap); + Paint paint = new Paint(); + paint.setAntiAlias(true); + paint.setFilterBitmap(true); + canvas.drawBitmap(bitmap, null, + new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint); + bitmap = outBitmap; + } + } + return bitmap; + } + private SessionHolder getHolder(PendingIntent pi, boolean createIfMissing) { SessionHolder holder = mSessions.get(pi); if (holder == null && createIfMissing) { diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 686f86547cc1..5ce35792b384 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -323,6 +323,19 @@ </intent-filter> </activity> + <activity + android:name=".settings.BrightnessDialog" + android:label="@string/quick_settings_brightness_dialog_title" + android:theme="@android:style/Theme.DeviceDefault.Light.Dialog" + android:finishOnCloseSystemDialogs="true" + android:launchMode="singleInstance" + android:excludeFromRecents="true" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.SHOW_BRIGHTNESS_DIALOG" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> <!-- I dream of notifications --> <service diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml index 85668de3c854..93c55387812c 100644 --- a/packages/SystemUI/res/layout/recents_task_view.xml +++ b/packages/SystemUI/res/layout/recents_task_view.xml @@ -67,8 +67,7 @@ android:layout_width="match_parent" android:layout_height="@dimen/recents_task_view_lock_to_app_button_height" android:layout_gravity="center_horizontal|bottom" - android:background="@drawable/recents_lock_to_task_button_bg" - android:visibility="invisible"> + android:background="@drawable/recents_lock_to_task_button_bg"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 8b11ef173993..230f4af0d4c0 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -159,8 +159,14 @@ <!-- Set to true to enable the user switcher on the keyguard. --> <bool name="config_keyguardUserSwitcher">false</bool> + <!-- Doze: does this device support STATE_DOZE and STATE_DOZE_SUSPEND? --> + <bool name="doze_display_state_supported">false</bool> + <!-- Doze: should the significant motion sensor be used as a tease signal? --> - <bool name="doze_tease_on_significant_motion">true</bool> + <bool name="doze_tease_on_significant_motion">false</bool> + + <!-- Doze: maximum brightness to use when teasing --> + <integer name="doze_tease_brightness">80</integer> <!-- Volume: time to delay dismissing the volume panel after a click is performed --> <integer name="volume_panel_dismiss_delay">200</integer> diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 630ba133183b..b3f90d7027bd 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -46,8 +46,7 @@ public class SystemUIApplication extends Application { com.android.systemui.statusbar.SystemBars.class, com.android.systemui.usb.StorageNotification.class, com.android.systemui.power.PowerUI.class, - com.android.systemui.media.RingtonePlayer.class, - com.android.systemui.settings.SettingsUI.class, + com.android.systemui.media.RingtonePlayer.class }; /** diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java index 269b4ed495e6..333b8b483142 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java @@ -16,20 +16,27 @@ package com.android.systemui.doze; +import static android.os.PowerManager.BRIGHTNESS_OFF; +import static android.os.PowerManager.BRIGHTNESS_ON; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.hardware.Sensor; import android.hardware.SensorManager; import android.hardware.TriggerEvent; import android.hardware.TriggerEventListener; +import android.os.Handler; import android.os.PowerManager; import android.os.SystemProperties; import android.os.Vibrator; import android.service.dreams.DozeHardware; import android.service.dreams.DreamService; import android.util.Log; +import android.util.MathUtils; +import android.view.Display; import com.android.systemui.R; import com.android.systemui.SystemUIApplication; @@ -38,12 +45,14 @@ import java.io.FileDescriptor; import java.io.PrintWriter; public class DozeService extends DreamService { - private static final boolean DEBUG = false; + private static final String TAG = "DozeService"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final String TEASE_ACTION = "com.android.systemui.doze.tease"; - private final String mTag = String.format("DozeService.%08x", hashCode()); + private final String mTag = String.format(TAG + ".%08x", hashCode()); private final Context mContext = this; + private final Handler mHandler = new Handler(); private Host mHost; private DozeHardware mDozeHardware; @@ -51,10 +60,13 @@ public class DozeService extends DreamService { private Sensor mSigMotionSensor; private PowerManager mPowerManager; private PowerManager.WakeLock mWakeLock; + private int mMaxBrightness; private boolean mDreaming; private boolean mTeaseReceiverRegistered; private boolean mSigMotionConfigured; private boolean mSigMotionEnabled; + private boolean mDisplayStateSupported; + private int mDisplayStateWhenOn; public DozeService() { if (DEBUG) Log.d(mTag, "new DozeService()"); @@ -70,6 +82,8 @@ public class DozeService extends DreamService { pw.print(" mSigMotionSensor: "); pw.println(mSigMotionSensor); pw.print(" mSigMotionConfigured: "); pw.println(mSigMotionConfigured); pw.print(" mSigMotionEnabled: "); pw.println(mSigMotionEnabled); + pw.print(" mMaxBrightness: "); pw.println(mMaxBrightness); + pw.print(" mDisplayStateSupported: "); pw.println(mDisplayStateSupported); } @Override @@ -88,8 +102,16 @@ public class DozeService extends DreamService { mSigMotionSensor = mSensors.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION); mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag); + final Resources res = mContext.getResources(); mSigMotionConfigured = SystemProperties.getBoolean("doze.tease.sigmotion", - mContext.getResources().getBoolean(R.bool.doze_tease_on_significant_motion)); + res.getBoolean(R.bool.doze_tease_on_significant_motion)); + mDisplayStateSupported = SystemProperties.getBoolean("doze.display.supported", + res.getBoolean(R.bool.doze_display_state_supported)); + mMaxBrightness = MathUtils.constrain(res.getInteger(R.integer.doze_tease_brightness), + BRIGHTNESS_OFF, BRIGHTNESS_ON); + + mDisplayStateWhenOn = mDisplayStateSupported ? Display.STATE_DOZE : Display.STATE_ON; + setDozeScreenState(mDisplayStateWhenOn); } @Override @@ -112,9 +134,18 @@ public class DozeService extends DreamService { public void stayAwake(long millis) { if (mDreaming && millis > 0) { mWakeLock.acquire(millis); + setDozeScreenState(mDisplayStateWhenOn); + setDozeScreenBrightness(mMaxBrightness); + rescheduleOff(millis); } } + private void rescheduleOff(long millis) { + if (DEBUG) Log.d(TAG, "rescheduleOff millis=" + millis); + mHandler.removeCallbacks(mDisplayOff); + mHandler.postDelayed(mDisplayOff, millis); + } + public void startDozing() { if (DEBUG) Log.d(mTag, "startDozing mDreaming=" + mDreaming); if (!mDreaming) { @@ -225,6 +256,15 @@ public class DozeService extends DreamService { return sb.append(']').toString(); } + private final Runnable mDisplayOff = new Runnable() { + @Override + public void run() { + if (DEBUG) Log.d(TAG, "Display off"); + setDozeScreenState(Display.STATE_OFF); + setDozeScreenBrightness(PowerManager.BRIGHTNESS_DEFAULT); + } + }; + private final TriggerEventListener mSigMotionListener = new TriggerEventListener() { @Override public void onTrigger(TriggerEvent event) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 7d69b9469bee..18dad3a81815 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -431,6 +431,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView super.onNewIntent(intent); setIntent(intent); + // Reinitialize the configuration + RecentsConfiguration.reinitialize(this, RecentsTaskLoader.getInstance().getSystemServicesProxy()); + // Clear any debug rects if (mDebugOverlay != null) { mDebugOverlay.clear(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index 55711cf0ad70..bffc23047a17 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -305,6 +305,11 @@ public class RecentsConfiguration { (!transposeRecentsLayoutWithOrientation || !isLandscape); } + /** Returns whether the current layout is horizontal. */ + public boolean hasHorizontalLayout() { + return isLandscape && transposeRecentsLayoutWithOrientation; + } + /** * Returns the task stack bounds in the current orientation. These bounds do not account for * the system insets. diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java index 9076818cec8e..34f73c6bb516 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java @@ -17,6 +17,7 @@ package com.android.systemui.recents.views; import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.graphics.Outline; import android.graphics.Rect; import android.view.View; @@ -34,6 +35,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider { int mCornerRadius; ObjectAnimator mClipTopAnimator; + ObjectAnimator mClipRightAnimator; ObjectAnimator mClipBottomAnimator; public AnimateableViewBounds(View source, int cornerRadius) { @@ -42,6 +44,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider { mCornerRadius = cornerRadius; mSourceView.setClipToOutline(true); setClipTop(getClipTop()); + setClipRight(getClipRight()); setClipBottom(getClipBottom()); setOutlineClipBottom(getOutlineClipBottom()); } @@ -56,7 +59,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider { } /** Animates the top clip. */ - void animateClipTop(int top, int duration) { + void animateClipTop(int top, int duration, ValueAnimator.AnimatorUpdateListener updateListener) { if (mClipTopAnimator != null) { mClipTopAnimator.removeAllListeners(); mClipTopAnimator.cancel(); @@ -64,6 +67,9 @@ public class AnimateableViewBounds extends ViewOutlineProvider { mClipTopAnimator = ObjectAnimator.ofInt(this, "clipTop", top); mClipTopAnimator.setDuration(duration); mClipTopAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); + if (updateListener != null) { + mClipTopAnimator.addUpdateListener(updateListener); + } mClipTopAnimator.start(); } @@ -80,16 +86,41 @@ public class AnimateableViewBounds extends ViewOutlineProvider { return mClipRect.top; } + /** Animates the right clip. */ + void animateClipRight(int right, int duration) { + if (mClipRightAnimator != null) { + mClipRightAnimator.removeAllListeners(); + mClipRightAnimator.cancel(); + } + mClipRightAnimator = ObjectAnimator.ofInt(this, "clipRight", right); + mClipRightAnimator.setDuration(duration); + mClipRightAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); + mClipRightAnimator.start(); + } + + /** Sets the right clip. */ + public void setClipRight(int right) { + if (right != mClipRect.right) { + mClipRect.right = right; + mSourceView.invalidateOutline(); + } + } + + /** Returns the right clip. */ + public int getClipRight() { + return mClipRect.right; + } + /** Animates the bottom clip. */ void animateClipBottom(int bottom, int duration) { - if (mClipTopAnimator != null) { - mClipTopAnimator.removeAllListeners(); - mClipTopAnimator.cancel(); + if (mClipBottomAnimator != null) { + mClipBottomAnimator.removeAllListeners(); + mClipBottomAnimator.cancel(); } - mClipTopAnimator = ObjectAnimator.ofInt(this, "clipBottom", bottom); - mClipTopAnimator.setDuration(duration); - mClipTopAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); - mClipTopAnimator.start(); + mClipBottomAnimator = ObjectAnimator.ofInt(this, "clipBottom", bottom); + mClipBottomAnimator.setDuration(duration); + mClipBottomAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); + mClipBottomAnimator.start(); } /** Sets the bottom clip. */ @@ -105,6 +136,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider { return mClipRect.bottom; } + /** Sets the outline bottom clip. */ public void setOutlineClipBottom(int bottom) { if (bottom != mOutlineClipRect.bottom) { mOutlineClipRect.bottom = bottom; @@ -112,6 +144,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider { } } + /** Gets the outline bottom clip. */ public int getOutlineClipBottom() { return mOutlineClipRect.bottom; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskFooterView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskFooterView.java index 95af1c951baa..881bbcfceebe 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskFooterView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskFooterView.java @@ -16,12 +16,9 @@ package com.android.systemui.recents.views; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; import android.util.AttributeSet; -import android.view.View; import android.widget.FrameLayout; import com.android.systemui.recents.RecentsConfiguration; @@ -82,9 +79,6 @@ public class TaskFooterView extends FrameLayout { void animateFooterVisibility(final boolean visible, int duration) { // Return early if there is no footer if (mMaxFooterHeight <= 0) return; - // Return early if we are already in the final state - if (!visible && getVisibility() != View.VISIBLE) return; - if (visible && getVisibility() == View.VISIBLE) return; // Cancel the previous animation if (mFooterAnimator != null) { @@ -93,25 +87,12 @@ public class TaskFooterView extends FrameLayout { } int finalHeight = visible ? mMaxFooterHeight : 0; if (duration > 0) { - // Make the view visible for the animation - if (visible && getVisibility() != View.VISIBLE) { - setVisibility(View.VISIBLE); - } mFooterAnimator = ObjectAnimator.ofInt(this, "footerHeight", finalHeight); mFooterAnimator.setDuration(duration); mFooterAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); - mFooterAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (!visible) { - setVisibility(View.INVISIBLE); - } - } - }); mFooterAnimator.start(); } else { setFooterHeight(finalHeight); - setVisibility(visible ? View.VISIBLE : View.INVISIBLE); } } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index f135e320b5c3..b501f7e70e6d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -83,7 +83,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int mFocusedTaskIndex = -1; OverScroller mScroller; ObjectAnimator mScrollAnimator; - boolean mEnableStackClipping = true; // Optimizations ReferenceCountedTrigger mHwLayersTrigger; @@ -93,8 +92,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal boolean mStartEnterAnimationRequestedAfterLayout; ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext; int[] mTmpVisibleRange = new int[2]; - Rect mTmpRect = new Rect(); - Rect mTmpRect2 = new Rect(); TaskViewTransform mTmpTransform = new TaskViewTransform(); HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<Task, TaskView>(); LayoutInflater mInflater; @@ -189,7 +186,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int stackScroll, int[] visibleRangeOut, boolean boundTranslationsToRect) { - // XXX: We should be intelligent about wheee to look for the visible stack range using the + // XXX: We should be intelligent about where to look for the visible stack range using the // current stack scroll. // XXX: We should log extra cases like the ones below where we don't expect to hit very often // XXX: Print out approximately how many indices we have to go through to find the first visible transform @@ -199,8 +196,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int frontMostVisibleIndex = -1; int backMostVisibleIndex = -1; - - // We can reuse the task transforms where possible to reduce object allocation if (taskTransformCount < taskCount) { // If there are less transforms than tasks, then add as many transforms as necessary @@ -290,6 +285,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (tv == null) { tv = mViewPool.pickUpViewFromPool(task, task); + if (mStackViewsAnimationDuration > 0) { // For items in the list, put them in start animating them from the // approriate ends of the list where they are expected to appear @@ -319,7 +315,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal /** Updates the clip for each of the task views. */ void clipTaskViews() { // Update the clip on each task child - if (Constants.DebugFlags.App.EnableTaskStackClipping && mEnableStackClipping) { + if (Constants.DebugFlags.App.EnableTaskStackClipping) { int childCount = getChildCount(); for (int i = 0; i < childCount - 1; i++) { TaskView tv = (TaskView) getChildAt(i); @@ -341,12 +337,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // stacked and we can make assumptions about the visibility of the this // task relative to the ones in front of it. if (nextTv != null) { - // We calculate the bottom clip independent of the footer (since we animate - // that) - int scaledMaxFooterHeight = (int) (tv.getMaxFooterHeight() * tv.getScaleX()); - tv.getHitRect(mTmpRect); - nextTv.getHitRect(mTmpRect2); - clipBottom = (mTmpRect.bottom - scaledMaxFooterHeight - mTmpRect2.top); + // We can reuse the current task transforms to find the task rects + TaskViewTransform transform = mCurrentTaskTransforms.get(mStack.indexOfTask(tv.getTask())); + TaskViewTransform nextTransform = mCurrentTaskTransforms.get(mStack.indexOfTask(nextTv.getTask())); + clipBottom = transform.rect.bottom - nextTransform.rect.top - 200; } } tv.getViewBounds().setClipBottom(clipBottom); @@ -359,18 +353,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } - /** Enables/Disables clipping of the tasks in the stack. */ - void setStackClippingEnabled(boolean stackClippingEnabled) { - if (!stackClippingEnabled) { - int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - TaskView tv = (TaskView) getChildAt(i); - tv.getViewBounds().setClipBottom(0); - } - } - mEnableStackClipping = stackClippingEnabled; - } - /** The stack insets to apply to the stack contents */ public void setStackInsetRect(Rect r) { mTaskStackBounds.set(r); @@ -634,18 +616,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal setStackScrollToInitialState(); requestSynchronizeStackViewsWithModel(); synchronizeStackViewsWithModel(); - - // Find the first task and mark it as full screen - if (mConfig.launchedFromAppWithScreenshot) { - int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - TaskView tv = (TaskView) getChildAt(i); - if (tv.getTask().isLaunchTarget) { - tv.setIsFullScreen(true); - break; - } - } - } } // Measure each of the TaskViews @@ -925,6 +895,15 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public void prepareViewToLeavePool(TaskView tv, Task task, boolean isNewView) { // Rebind the task and request that this task's data be filled into the TaskView tv.onTaskBound(task); + + // Mark the launch task as fullscreen + if (Constants.DebugFlags.App.EnableScreenshotAppTransition && mAwaitingFirstLayout) { + if (task.isLaunchTarget) { + tv.setIsFullScreen(true); + } + } + + // Load the task data RecentsTaskLoader.getInstance().loadTaskData(task); // Sanity check, the task view should always be clipping against the stack at this point, diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java index 7f94a0a29dac..0fd4e8642955 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java @@ -82,7 +82,7 @@ public class TaskStackViewLayoutAlgorithm { // Compute the min and max scroll values int numTasks = Math.max(1, tasks.size()); int taskHeight = mTaskRect.height(); - int stackHeight = mStackRect.height(); + int stackHeight = mStackRectSansPeek.height(); if (numTasks <= 1) { // If there is only one task, then center the task in the stack rect (sans peek) diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java index b83f9cc26546..b1c35f32196a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -263,7 +263,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { int velocity = (int) velocityTracker.getYVelocity(mActivePointerId); if (mIsScrolling && (Math.abs(velocity) > mMinimumVelocity)) { - // XXX: Make this animation a function of the velocity AND distance int overscrollRange = (int) (Math.min(1f, Math.abs((float) velocity / mMaximumVelocity)) * Constants.Values.TaskStackView.TaskStackOverscrollRange); @@ -277,7 +276,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { mSv.invalidate(mSv.mStackAlgorithm.mStackRect); } else if (mSv.isScrollOutOfBounds()) { // Animate the scroll back into bounds - // XXX: Make this animation a function of the velocity OR distance mSv.animateBoundScroll(); } @@ -303,7 +301,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { case MotionEvent.ACTION_CANCEL: { if (mSv.isScrollOutOfBounds()) { // Animate the scroll back into bounds - // XXX: Make this animation a function of the velocity OR distance mSv.animateBoundScroll(); } mActivePointerId = INACTIVE_POINTER_ID; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 259706bd51ec..1b5ad6ee5828 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -21,7 +21,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; -import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; @@ -60,7 +59,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, boolean mTaskDataLoaded; boolean mIsFocused; boolean mIsFullScreenView; - boolean mIsStub; boolean mClipViewInStack; AnimateableViewBounds mViewBounds; Paint mLayerPaint = new Paint(); @@ -123,7 +121,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mBarView = (TaskBarView) findViewById(R.id.task_view_bar); mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail); mFooterView = (TaskFooterView) findViewById(R.id.lock_to_app); - mFooterView.setCallbacks(this); + if (mConfig.lockToAppEnabled) { + mFooterView.setCallbacks(this); + } else { + mFooterView.setVisibility(View.GONE); + } } @Override @@ -147,6 +149,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY)); } setMeasuredDimension(width, height); + invalidateOutline(); } /** Synchronizes this view's properties with the task's transform */ @@ -201,9 +204,9 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, if (mConfig.launchedFromAppWithScreenshot) { if (isTaskViewLaunchTargetTask) { // Also hide the front most task bar view so we can animate it in - mBarView.prepareEnterRecentsAnimation(); + // mBarView.prepareEnterRecentsAnimation(); } else { - // Don't do anything for the side views + // Don't do anything for the side views when animating in } } else if (mConfig.launchedFromAppWithThumbnail) { @@ -232,17 +235,32 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, if (mConfig.launchedFromAppWithScreenshot) { if (mTask.isLaunchTarget) { - // XXX: We would have to animate the trasnlationY of the task view bar along with the clip and - // reset it at the bottom - - // XXX: This should actually be the inset on the current app... - mViewBounds.animateClipTop(taskRect.top, mConfig.taskViewEnterFromHomeDuration * 5); - mViewBounds.animateClipBottom(getMeasuredHeight() - taskRect.bottom, mConfig.taskViewEnterFromHomeDuration * 5); - - animate().scaleX(((float) taskRect.width() / getMeasuredWidth()) * transform.scale) - .scaleY(((float) taskRect.width() / getMeasuredWidth()) * transform.scale) - .translationY(taskRect.top + transform.translationY) - .setDuration(mConfig.taskViewEnterFromHomeDuration * 5) + int duration = mConfig.taskViewEnterFromHomeDuration * 5; + int windowInsetTop = mConfig.systemInsets.top; // XXX: Should be for the window + float taskScale = ((float) taskRect.width() / getMeasuredWidth()) * transform.scale; + float taskTranslationY = taskRect.top + transform.translationY - windowInsetTop; + + // Animate the top clip + mViewBounds.animateClipTop(windowInsetTop, duration, + new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + int y = (Integer) animation.getAnimatedValue(); + mBarView.setTranslationY(y); + } + }); + // Animate the bottom or right clip + int size = Math.round((taskRect.width() / taskScale)); + if (mConfig.hasHorizontalLayout()) { + mViewBounds.animateClipRight(getMeasuredWidth() - size, duration); + } else { + mViewBounds.animateClipBottom(getMeasuredHeight() - (windowInsetTop + size), duration); + } + animate() + .scaleX(taskScale) + .scaleY(taskScale) + .translationY(taskTranslationY) + .setDuration(duration) .withEndAction(new Runnable() { @Override public void run() { @@ -424,11 +442,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, return mIsFullScreenView; } - /** Sets the stubbed state of this task view. */ - void setStubState(boolean isStub) { - mIsStub = isStub; - } - /** * Returns whether this view should be clipped, or any views below should clip against this * view. @@ -447,7 +460,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, /** Gets the max footer height. */ public int getMaxFooterHeight() { - return mFooterView.mMaxFooterHeight; + if (mConfig.lockToAppEnabled) { + return mFooterView.mMaxFooterHeight; + } else { + return 0; + } } /** Animates the footer into and out of view. */ @@ -488,17 +505,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, setDim(getDimOverlayFromScale()); } - /**** View drawing ****/ - - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if (mIsStub && (child != mBarView)) { - // Skip the thumbnail view if we are in stub mode - return false; - } - return super.drawChild(canvas, child, drawingTime); - } - /**** View focus state ****/ /** diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java index 6d5bb9de1a1a..108c8df0d944 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java @@ -163,15 +163,17 @@ public class BrightnessController implements ToggleSlider.Listener { if (mListening) { return; } + mBrightnessObserver.startObserving(); mUserTracker.startTracking(); - // Update the slider and mode before attaching the listener so we don't receive the - // onChanged notifications for the initial values. + // Update the slider and mode before attaching the listener so we don't + // receive the onChanged notifications for the initial values. updateMode(); updateSlider(); mControl.setOnChangedListener(this); + mListening = true; } /** Unregister all call backs, both to and from the controller */ @@ -179,10 +181,11 @@ public class BrightnessController implements ToggleSlider.Listener { if (!mListening) { return; } + mBrightnessObserver.stopObserving(); - mChangeCallbacks.clear(); mUserTracker.stopTracking(); mControl.setOnChangedListener(null); + mListening = false; } public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value) { diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java index 65e1cc6ef3e2..ad98168e1593 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java +++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java @@ -16,6 +16,7 @@ package com.android.systemui.settings; +import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.res.Resources; @@ -30,76 +31,66 @@ import android.widget.ImageView; import com.android.systemui.R; /** A dialog that provides controls for adjusting the screen brightness. */ -public class BrightnessDialog extends Dialog implements +public class BrightnessDialog extends Activity implements BrightnessController.BrightnessStateChangeCallback { - - private static final String TAG = "BrightnessDialog"; - private static final boolean DEBUG = false; - - protected Handler mHandler = new Handler(); + private final Handler mHandler = new Handler(); private BrightnessController mBrightnessController; - private final int mBrightnessDialogLongTimeout; - private final int mBrightnessDialogShortTimeout; + private int mBrightnessDialogLongTimeout; + private int mBrightnessDialogShortTimeout; private final Runnable mDismissDialogRunnable = new Runnable() { public void run() { - if (BrightnessDialog.this.isShowing()) { - BrightnessDialog.this.dismiss(); - } + finish(); }; }; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - public BrightnessDialog(Context ctx) { - super(ctx); - Resources r = ctx.getResources(); - mBrightnessDialogLongTimeout = - r.getInteger(R.integer.quick_settings_brightness_dialog_long_timeout); - mBrightnessDialogShortTimeout = - r.getInteger(R.integer.quick_settings_brightness_dialog_short_timeout); - } + final Resources r = getResources(); + mBrightnessDialogLongTimeout = r.getInteger( + R.integer.quick_settings_brightness_dialog_long_timeout); + mBrightnessDialogShortTimeout = r.getInteger( + R.integer.quick_settings_brightness_dialog_short_timeout); + final Window window = getWindow(); + final WindowManager.LayoutParams lp = window.getAttributes(); - /** - * Create the brightness dialog and any resources that are used for the - * entire lifetime of the dialog. - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Window window = getWindow(); - window.setGravity(Gravity.TOP); - WindowManager.LayoutParams lp = window.getAttributes(); // Offset from the top - lp.y = getContext().getResources().getDimensionPixelOffset(R.dimen.volume_panel_top); + lp.y = getResources().getDimensionPixelOffset(R.dimen.volume_panel_top); lp.type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; - lp.privateFlags |= - WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; + lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; + window.setAttributes(lp); + window.setGravity(Gravity.TOP); window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); window.requestFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.quick_settings_brightness_dialog); - setCanceledOnTouchOutside(true); } - @Override protected void onStart() { super.onStart(); - mBrightnessController = new BrightnessController(getContext(), - (ImageView) findViewById(R.id.brightness_icon), - (ToggleSlider) findViewById(R.id.brightness_slider)); + + final ImageView icon = (ImageView) findViewById(R.id.brightness_icon); + final ToggleSlider slider = (ToggleSlider) findViewById(R.id.brightness_slider); + mBrightnessController = new BrightnessController(this, icon, slider); mBrightnessController.registerCallbacks(); - dismissBrightnessDialog(mBrightnessDialogLongTimeout); mBrightnessController.addStateChangedCallback(this); + + dismissBrightnessDialog(mBrightnessDialogLongTimeout); } @Override protected void onStop() { super.onStop(); + + mBrightnessController.removeStateChangedCallback(this); mBrightnessController.unregisterCallbacks(); + removeAllBrightnessDialogCallbacks(); } @@ -109,6 +100,7 @@ public class BrightnessDialog extends Dialog implements private void dismissBrightnessDialog(int timeout) { removeAllBrightnessDialogCallbacks(); + mHandler.postDelayed(mDismissDialogRunnable, timeout); } @@ -118,11 +110,12 @@ public class BrightnessDialog extends Dialog implements @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || - keyCode == KeyEvent.KEYCODE_VOLUME_UP || - keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) { - dismiss(); + if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN + || keyCode == KeyEvent.KEYCODE_VOLUME_UP + || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) { + finish(); } + return super.onKeyDown(keyCode, event); } } diff --git a/packages/SystemUI/src/com/android/systemui/settings/SettingsUI.java b/packages/SystemUI/src/com/android/systemui/settings/SettingsUI.java deleted file mode 100644 index 8bc72c93fa01..000000000000 --- a/packages/SystemUI/src/com/android/systemui/settings/SettingsUI.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.settings; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; -import android.os.UserHandle; -import android.util.Log; - -import com.android.systemui.SystemUI; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -public class SettingsUI extends SystemUI { - private static final String TAG = "SettingsUI"; - private static final boolean DEBUG = false; - - private final Handler mHandler = new Handler(); - private BrightnessDialog mBrightnessDialog; - - private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action.equals(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG)) { - if (DEBUG) Log.d(TAG, "showing brightness dialog"); - - if (mBrightnessDialog == null) { - mBrightnessDialog = new BrightnessDialog(mContext); - mBrightnessDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - mBrightnessDialog = null; - } - }); - } - - if (!mBrightnessDialog.isShowing()) { - mBrightnessDialog.show(); - } - - } else { - Log.w(TAG, "unknown intent: " + intent); - } - } - }; - - public void start() { - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG); - mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, mHandler); - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.print("mBrightnessDialog="); - pw.println(mBrightnessDialog == null ? "null" : mBrightnessDialog.toString()); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index c464f3168678..cf930bddead3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -44,12 +44,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener { private static final int TAG_KEY_ANIM = R.id.scrim; private static final int NUM_TEASES = 3; - private static final long TEASE_IN_ANIMATION_DURATION = 500; - private static final long TEASE_VISIBLE_DURATION = 3000; + private static final long TEASE_IN_ANIMATION_DURATION = 1000; + private static final long TEASE_VISIBLE_DURATION = 2000; private static final long TEASE_OUT_ANIMATION_DURATION = 1000; private static final long TEASE_INVISIBLE_DURATION = 1000; private static final long TEASE_DURATION = TEASE_IN_ANIMATION_DURATION + TEASE_VISIBLE_DURATION + TEASE_OUT_ANIMATION_DURATION + TEASE_INVISIBLE_DURATION; + private static final long PRE_TEASE_DELAY = 1000; private final View mScrimBehind; private final View mScrimInFront; @@ -128,8 +129,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener { public long tease() { if (!mDozing) return 0; mTeasesRemaining = NUM_TEASES; - mScrimInFront.post(mTeaseIn); - return NUM_TEASES * TEASE_DURATION; + mScrimInFront.postDelayed(mTeaseIn, PRE_TEASE_DELAY); + return PRE_TEASE_DELAY + NUM_TEASES * TEASE_DURATION; } private void cancelTeasing() { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 71f1d2118814..44a53448ccb7 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -2339,8 +2339,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.System.putIntForUser(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, brightness, UserHandle.USER_CURRENT_OR_SELF); - Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG); - mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF); + mContext.startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG), + UserHandle.CURRENT_OR_SELF); } return -1; } else if (keyCode == KeyEvent.KEYCODE_META_LEFT) { diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index bae2d223045b..3a4e2ee63a05 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -28,6 +28,7 @@ import com.android.server.location.GeofenceManager; import com.android.server.location.GeofenceProxy; import com.android.server.location.GpsLocationProvider; import com.android.server.location.GpsMeasurementsProvider; +import com.android.server.location.GpsNavigationMessageProvider; import com.android.server.location.LocationBlacklist; import com.android.server.location.LocationFudger; import com.android.server.location.LocationProviderInterface; @@ -60,6 +61,7 @@ import android.location.Criteria; import android.location.GeocoderParams; import android.location.Geofence; import android.location.IGpsMeasurementsListener; +import android.location.IGpsNavigationMessageListener; import android.location.IGpsStatusListener; import android.location.IGpsStatusProvider; import android.location.ILocationListener; @@ -159,6 +161,7 @@ public class LocationManagerService extends ILocationManager.Stub { private PassiveProvider mPassiveProvider; // track passive provider for special cases private LocationBlacklist mBlacklist; private GpsMeasurementsProvider mGpsMeasurementsProvider; + private GpsNavigationMessageProvider mGpsNavigationMessageProvider; // --- fields below are protected by mLock --- // Set of providers that are explicitly enabled @@ -409,6 +412,7 @@ public class LocationManagerService extends ILocationManager.Stub { mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider); } mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider(); + mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider(); /* Load package name(s) containing location provider support. @@ -1847,7 +1851,6 @@ public class LocationManagerService extends ILocationManager.Stub { if (!hasLocationAccess) { return false; } - return mGpsMeasurementsProvider.addListener(listener); } @@ -1857,6 +1860,35 @@ public class LocationManagerService extends ILocationManager.Stub { } @Override + public boolean addGpsNavigationMessageListener( + IGpsNavigationMessageListener listener, + String packageName) { + int allowedResolutionLevel = getCallerAllowedResolutionLevel(); + checkResolutionLevelIsSufficientForProviderUse( + allowedResolutionLevel, + LocationManager.GPS_PROVIDER); + + int uid = Binder.getCallingUid(); + long identity = Binder.clearCallingIdentity(); + boolean hasLocationAccess; + try { + hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel); + } finally { + Binder.restoreCallingIdentity(identity); + } + + if (!hasLocationAccess) { + return false; + } + return mGpsNavigationMessageProvider.addListener(listener); + } + + @Override + public boolean removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) { + return mGpsNavigationMessageProvider.removeListener(listener); + } + + @Override public boolean sendExtraCommand(String provider, String command, Bundle extras) { if (provider == null) { // throw NullPointerException to remain compatible with previous implementation diff --git a/services/core/java/com/android/server/job/JobMapReadFinishedListener.java b/services/core/java/com/android/server/job/JobMapReadFinishedListener.java deleted file mode 100644 index f3e77e6a36f6..000000000000 --- a/services/core/java/com/android/server/job/JobMapReadFinishedListener.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.server.job; - -import java.util.List; - -import com.android.server.job.controllers.JobStatus; - -/** - * Callback definition for I/O thread to let the JobManagerService know when - * I/O read has completed. Done this way so we don't stall the main thread on - * boot. - */ -public interface JobMapReadFinishedListener { - - /** - * Called by the {@link JobStore} at boot, when the disk read is finished. - */ - public void onJobMapReadFinished(List<JobStatus> jobs); -} diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 3b52bafc3ff7..587f596e420d 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -69,7 +69,7 @@ import com.android.server.job.controllers.TimeController; * @hide */ public class JobSchedulerService extends com.android.server.SystemService - implements StateChangedListener, JobCompletedListener, JobMapReadFinishedListener { + implements StateChangedListener, JobCompletedListener { // TODO: Switch this off for final version. static final boolean DEBUG = true; /** The number of concurrent jobs we run at one time. */ @@ -487,28 +487,6 @@ public class JobSchedulerService extends com.android.server.SystemService mHandler.obtainMessage(MSG_JOB_EXPIRED, jobStatus).sendToTarget(); } - /** - * Disk I/O is finished, take the list of jobs we read from disk and add them to our - * {@link JobStore}. - * This is run on the {@link com.android.server.IoThread} instance, which is a separate thread, - * and is called once at boot. - */ - @Override - public void onJobMapReadFinished(List<JobStatus> jobs) { - synchronized (mJobs) { - for (int i=0; i<jobs.size(); i++) { - JobStatus js = jobs.get(i); - if (mJobs.containsJobIdForUid(js.getJobId(), js.getUid())) { - // An app with BOOT_COMPLETED *might* have decided to reschedule their job, in - // the same amount of time it took us to read it from disk. If this is the case - // we leave it be. - continue; - } - startTrackingJob(js); - } - } - } - private class JobHandler extends Handler { public JobHandler(Looper looper) { diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java index 48312b04c9bd..46f557f5e1bb 100644 --- a/services/core/java/com/android/server/job/JobStore.java +++ b/services/core/java/com/android/server/job/JobStore.java @@ -88,19 +88,26 @@ public class JobStore { synchronized (sSingletonLock) { if (sSingleton == null) { sSingleton = new JobStore(jobManagerService.getContext(), - Environment.getDataDirectory(), jobManagerService); + Environment.getDataDirectory()); } return sSingleton; } } + /** + * @return A freshly initialized job store object, with no loaded jobs. + */ @VisibleForTesting - public static JobStore initAndGetForTesting(Context context, File dataDir, - JobMapReadFinishedListener callback) { - return new JobStore(context, dataDir, callback); + public static JobStore initAndGetForTesting(Context context, File dataDir) { + JobStore jobStoreUnderTest = new JobStore(context, dataDir); + jobStoreUnderTest.clear(); + return jobStoreUnderTest; } - private JobStore(Context context, File dataDir, JobMapReadFinishedListener callback) { + /** + * Construct the instance of the job store. This results in a blocking read from disk. + */ + private JobStore(Context context, File dataDir) { mContext = context; mDirtyOperations = 0; @@ -111,7 +118,7 @@ public class JobStore { mJobSet = new ArraySet<JobStatus>(); - readJobMapFromDiskAsync(callback); + readJobMapFromDisk(mJobSet); } /** @@ -249,12 +256,9 @@ public class JobStore { } } - private void readJobMapFromDiskAsync(JobMapReadFinishedListener callback) { - mIoHandler.post(new ReadJobMapFromDiskRunnable(callback)); - } - - public void readJobMapFromDisk(JobMapReadFinishedListener callback) { - new ReadJobMapFromDiskRunnable(callback).run(); + @VisibleForTesting + public void readJobMapFromDisk(ArraySet<JobStatus> jobSet) { + new ReadJobMapFromDiskRunnable(jobSet).run(); } /** @@ -398,13 +402,18 @@ public class JobStore { } /** - * Runnable that reads list of persisted job from xml. - * NOTE: This Runnable locks on JobStore.this + * Runnable that reads list of persisted job from xml. This is run once at start up, so doesn't + * need to go through {@link JobStore#add(com.android.server.job.controllers.JobStatus)}. */ private class ReadJobMapFromDiskRunnable implements Runnable { - private JobMapReadFinishedListener mCallback; - public ReadJobMapFromDiskRunnable(JobMapReadFinishedListener callback) { - mCallback = callback; + private final ArraySet<JobStatus> jobSet; + + /** + * @param jobSet Reference to the (empty) set of JobStatus objects that back the JobStore, + * so that after disk read we can populate it directly. + */ + ReadJobMapFromDiskRunnable(ArraySet<JobStatus> jobSet) { + this.jobSet = jobSet; } @Override @@ -414,11 +423,13 @@ public class JobStore { FileInputStream fis = mJobsFile.openRead(); synchronized (JobStore.this) { jobs = readJobMapImpl(fis); + if (jobs != null) { + for (int i=0; i<jobs.size(); i++) { + this.jobSet.add(jobs.get(i)); + } + } } fis.close(); - if (jobs != null) { - mCallback.onJobMapReadFinished(jobs); - } } catch (FileNotFoundException e) { if (JobSchedulerService.DEBUG) { Slog.d(TAG, "Could not find jobs file, probably there was nothing to load."); @@ -673,4 +684,4 @@ public class JobStore { return Pair.create(earliestRunTimeElapsed, latestRunTimeElapsed); } } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java index 09873c7383b9..058a23e36b14 100644 --- a/services/core/java/com/android/server/location/GpsLocationProvider.java +++ b/services/core/java/com/android/server/location/GpsLocationProvider.java @@ -38,6 +38,7 @@ import android.hardware.location.GeofenceHardwareImpl; import android.location.Criteria; import android.location.FusedBatchOptions; import android.location.GpsMeasurementsEvent; +import android.location.GpsNavigationMessageEvent; import android.location.IGpsGeofenceHardware; import android.location.IGpsStatusListener; import android.location.IGpsStatusProvider; @@ -324,6 +325,14 @@ public class GpsLocationProvider implements LocationProviderInterface { protected boolean isSupported() { return GpsLocationProvider.isSupported(); } + + @Override + protected boolean registerWithService() { + return true; + } + + @Override + protected void unregisterFromService() {} }; // Handler for processing events @@ -374,16 +383,34 @@ public class GpsLocationProvider implements LocationProviderInterface { } @Override - protected void onFirstListenerAdded() { - native_start_measurement_collection(); + protected boolean registerWithService() { + return native_start_measurement_collection(); } @Override - protected void onLastListenerRemoved() { + protected void unregisterFromService() { native_stop_measurement_collection(); } }; + private final GpsNavigationMessageProvider mGpsNavigationMessageProvider = + new GpsNavigationMessageProvider() { + @Override + protected boolean isSupported() { + return native_is_navigation_message_supported(); + } + + @Override + protected boolean registerWithService() { + return native_start_navigation_message_collection(); + } + + @Override + protected void unregisterFromService() { + native_stop_navigation_message_collection(); + } + }; + public IGpsStatusProvider getGpsStatusProvider() { return mGpsStatusProvider; } @@ -396,6 +423,10 @@ public class GpsLocationProvider implements LocationProviderInterface { return mGpsMeasurementsProvider; } + public GpsNavigationMessageProvider getGpsNavigationMessageProvider() { + return mGpsNavigationMessageProvider; + } + private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); @@ -1357,13 +1388,20 @@ public class GpsLocationProvider implements LocationProviderInterface { } /** - * called from native code - Gps Data callback + * called from native code - Gps measurements callback */ private void reportMeasurementData(GpsMeasurementsEvent event) { mGpsMeasurementsProvider.onMeasurementsAvailable(event); } /** + * called from native code - GPS navigation message callback + */ + private void reportNavigationMessage(GpsNavigationMessageEvent event) { + mGpsNavigationMessageProvider.onNavigationMessageAvailable(event); + } + + /** * called from native code to inform us what the GPS engine capabilities are */ private void setEngineCapabilities(int capabilities) { @@ -1954,6 +1992,11 @@ public class GpsLocationProvider implements LocationProviderInterface { // Gps Hal measurements support. private static native boolean native_is_measurement_supported(); - private static native boolean native_start_measurement_collection(); - private static native boolean native_stop_measurement_collection(); + private native boolean native_start_measurement_collection(); + private native boolean native_stop_measurement_collection(); + + // Gps Navigation message support. + private static native boolean native_is_navigation_message_supported(); + private native boolean native_start_navigation_message_collection(); + private native boolean native_stop_navigation_message_collection(); } diff --git a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java index 001f638ede50..1c48257b770d 100644 --- a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java +++ b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java @@ -29,6 +29,9 @@ import android.os.RemoteException; */ public abstract class GpsMeasurementsProvider extends RemoteListenerHelper<IGpsMeasurementsListener> { + public GpsMeasurementsProvider() { + super("GpsMeasurementsProvider"); + } public void onMeasurementsAvailable(final GpsMeasurementsEvent event) { ListenerOperation<IGpsMeasurementsListener> operation = diff --git a/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java b/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java new file mode 100644 index 000000000000..fca7378d3946 --- /dev/null +++ b/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.location; + +import android.location.GpsNavigationMessageEvent; +import android.location.IGpsNavigationMessageListener; +import android.os.RemoteException; + +/** + * An base implementation for GPS navigation messages provider. + * It abstracts out the responsibility of handling listeners, while still allowing technology + * specific implementations to be built. + * + * @hide + */ +public abstract class GpsNavigationMessageProvider + extends RemoteListenerHelper<IGpsNavigationMessageListener> { + public GpsNavigationMessageProvider() { + super("GpsNavigationMessageProvider"); + } + + public void onNavigationMessageAvailable(final GpsNavigationMessageEvent event) { + ListenerOperation<IGpsNavigationMessageListener> operation = + new ListenerOperation<IGpsNavigationMessageListener>() { + @Override + public void execute(IGpsNavigationMessageListener listener) + throws RemoteException { + listener.onGpsNavigationMessageReceived(event); + } + }; + + foreach(operation); + } +} diff --git a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java index b741e75c4452..27cf3d893bd8 100644 --- a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java +++ b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java @@ -23,6 +23,10 @@ import android.os.RemoteException; * Implementation of a handler for {@link IGpsStatusListener}. */ abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusListener> { + public GpsStatusListenerHelper() { + super("GpsStatusListenerHelper"); + } + public void onFirstFix(final int timeToFirstFix) { Operation operation = new Operation() { @Override diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java index 79335f73060c..451af18d1243 100644 --- a/services/core/java/com/android/server/location/RemoteListenerHelper.java +++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java @@ -32,16 +32,19 @@ import java.util.HashMap; * A helper class, that handles operations in remote listeners, and tracks for remote process death. */ abstract class RemoteListenerHelper<TListener extends IInterface> { - private static final String TAG = "RemoteListenerHelper"; - + private final String mTag; private final HashMap<IBinder, LinkedListener> mListenerMap = new HashMap<IBinder, LinkedListener>(); + protected RemoteListenerHelper(String name) { + Preconditions.checkNotNull(name); + mTag = name; + } + public boolean addListener(@NonNull TListener listener) { Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener."); - if (!isSupported()) { - Log.e(TAG, "Refused to add listener, the feature is not supported."); + Log.e(mTag, "Refused to add listener, the feature is not supported."); return false; } @@ -58,13 +61,17 @@ abstract class RemoteListenerHelper<TListener extends IInterface> { } catch (RemoteException e) { // if the remote process registering the listener is already death, just swallow the // exception and continue - Log.e(TAG, "Remote listener already died.", e); + Log.e(mTag, "Remote listener already died.", e); return false; } mListenerMap.put(binder, deathListener); if (mListenerMap.size() == 1) { - onFirstListenerAdded(); + if (!registerWithService()) { + Log.e(mTag, "RegisterWithService failed, listener will be removed."); + removeListener(listener); + return false; + } } } @@ -73,9 +80,8 @@ abstract class RemoteListenerHelper<TListener extends IInterface> { public boolean removeListener(@NonNull TListener listener) { Preconditions.checkNotNull(listener, "Attempted to remove a 'null' listener."); - if (!isSupported()) { - Log.e(TAG, "Refused to remove listener, the feature is not supported."); + Log.e(mTag, "Refused to remove listener, the feature is not supported."); return false; } @@ -84,26 +90,19 @@ abstract class RemoteListenerHelper<TListener extends IInterface> { synchronized (mListenerMap) { linkedListener = mListenerMap.remove(binder); if (mListenerMap.isEmpty() && linkedListener != null) { - onLastListenerRemoved(); + unregisterFromService(); } } if (linkedListener != null) { binder.unlinkToDeath(linkedListener, 0 /* flags */); } - return true; } protected abstract boolean isSupported(); - - protected void onFirstListenerAdded() { - // event triggered when the first listener has been added - } - - protected void onLastListenerRemoved() { - // event triggered when the last listener has bee removed - } + protected abstract boolean registerWithService(); + protected abstract void unregisterFromService(); protected interface ListenerOperation<TListener extends IInterface> { void execute(TListener listener) throws RemoteException; @@ -121,7 +120,7 @@ abstract class RemoteListenerHelper<TListener extends IInterface> { try { operation.execute(listener); } catch (RemoteException e) { - Log.e(TAG, "Error in monitored listener.", e); + Log.e(mTag, "Error in monitored listener.", e); removeListener(listener); } } @@ -141,7 +140,7 @@ abstract class RemoteListenerHelper<TListener extends IInterface> { @Override public void binderDied() { - Log.d(TAG, "Remote Listener died: " + mListener); + Log.d(mTag, "Remote Listener died: " + mListener); removeListener(mListener); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 69f2f32ac7c0..b96f67299085 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -138,7 +138,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Environment.UserEnvironment; -import android.os.FileObserver; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; @@ -235,7 +234,6 @@ public class PackageManagerService extends IPackageManager.Stub { private static final boolean DEBUG_PACKAGE_INFO = false; private static final boolean DEBUG_INTENT_MATCHING = false; private static final boolean DEBUG_PACKAGE_SCANNING = false; - private static final boolean DEBUG_APP_DIR_OBSERVER = false; private static final boolean DEBUG_VERIFY = false; private static final boolean DEBUG_DEXOPT = false; private static final boolean DEBUG_ABI_SELECTION = false; @@ -249,12 +247,6 @@ public class PackageManagerService extends IPackageManager.Stub { // Cap the size of permission trees that 3rd party apps can define private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768; // characters of text - private static final int REMOVE_EVENTS = - FileObserver.CLOSE_WRITE | FileObserver.DELETE | FileObserver.MOVED_FROM; - private static final int ADD_EVENTS = - FileObserver.CLOSE_WRITE /*| FileObserver.CREATE*/ | FileObserver.MOVED_TO; - - private static final int OBSERVER_EVENTS = REMOVE_EVENTS | ADD_EVENTS; // Suffix used during package installation when copying/moving // package apks to install directory. private static final String INSTALL_PACKAGE_SUFFIX = "-"; @@ -342,30 +334,6 @@ public class PackageManagerService extends IPackageManager.Stub { /** The location for ASEC container files on internal storage. */ final String mAsecInternalPath; - // This is the object monitoring the framework dir. - final FileObserver mFrameworkInstallObserver; - - // This is the object monitoring the system app dir. - final FileObserver mSystemInstallObserver; - - // This is the object monitoring the privileged system app dir. - final FileObserver mPrivilegedInstallObserver; - - // This is the object monitoring the vendor app dir. - final FileObserver mVendorInstallObserver; - - // This is the object monitoring the vendor overlay package dir. - final FileObserver mVendorOverlayInstallObserver; - - // This is the object monitoring the OEM app dir. - final FileObserver mOemInstallObserver; - - // This is the object monitoring mAppInstallDir. - final FileObserver mAppInstallObserver; - - // This is the object monitoring mDrmAppPrivateInstallDir. - final FileObserver mDrmAppInstallObserver; - // Used for privilege escalation. MUST NOT BE CALLED WITH mPackages // LOCK HELD. Can be called with mInstallLock held. final Installer mInstaller; @@ -1542,16 +1510,10 @@ public class PackageManagerService extends IPackageManager.Stub { // For security and version matching reason, only consider // overlay packages if they reside in VENDOR_OVERLAY_DIR. File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR); - mVendorOverlayInstallObserver = new AppDirObserver( - vendorOverlayDir.getPath(), OBSERVER_EVENTS, true, false); - mVendorOverlayInstallObserver.startWatching(); scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode | SCAN_TRUSTED_OVERLAY, 0); // Find base frameworks (resource packages without code). - mFrameworkInstallObserver = new AppDirObserver( - frameworkDir.getPath(), OBSERVER_EVENTS, true, false); - mFrameworkInstallObserver.startWatching(); scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, @@ -1559,18 +1521,12 @@ public class PackageManagerService extends IPackageManager.Stub { // Collected privileged system packages. File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app"); - mPrivilegedInstallObserver = new AppDirObserver( - privilegedAppDir.getPath(), OBSERVER_EVENTS, true, true); - mPrivilegedInstallObserver.startWatching(); scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanMode, 0); // Collect ordinary system packages. File systemAppDir = new File(Environment.getRootDirectory(), "app"); - mSystemInstallObserver = new AppDirObserver( - systemAppDir.getPath(), OBSERVER_EVENTS, true, false); - mSystemInstallObserver.startWatching(); scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); @@ -1581,17 +1537,11 @@ public class PackageManagerService extends IPackageManager.Stub { } catch (IOException e) { // failed to look up canonical path, continue with original one } - mVendorInstallObserver = new AppDirObserver( - vendorAppDir.getPath(), OBSERVER_EVENTS, true, false); - mVendorInstallObserver.startWatching(); scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); // Collect all OEM packages. File oemAppDir = new File(Environment.getOemDirectory(), "app"); - mOemInstallObserver = new AppDirObserver( - oemAppDir.getPath(), OBSERVER_EVENTS, true, false); - mOemInstallObserver.startWatching(); scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); @@ -1665,14 +1615,8 @@ public class PackageManagerService extends IPackageManager.Stub { if (!mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); - mAppInstallObserver = new AppDirObserver( - mAppInstallDir.getPath(), OBSERVER_EVENTS, false, false); - mAppInstallObserver.startWatching(); scanDirLI(mAppInstallDir, 0, scanMode, 0); - - mDrmAppInstallObserver = new AppDirObserver( - mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false, false); - mDrmAppInstallObserver.startWatching(); + scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode, 0); @@ -1703,9 +1647,6 @@ public class PackageManagerService extends IPackageManager.Stub { } reportSettingsProblem(Log.WARN, msg); } - } else { - mAppInstallObserver = null; - mDrmAppInstallObserver = null; } // Now that we know all of the shared libraries, update all clients to have @@ -7723,131 +7664,6 @@ public class PackageManagerService extends IPackageManager.Stub { } } } - - private final class AppDirObserver extends FileObserver { - public AppDirObserver(String path, int mask, boolean isrom, boolean isPrivileged) { - super(path, mask); - mRootDir = path; - mIsRom = isrom; - mIsPrivileged = isPrivileged; - } - - public void onEvent(int event, String path) { - String removedPackage = null; - int removedAppId = -1; - int[] removedUsers = null; - String addedPackage = null; - int addedAppId = -1; - int[] addedUsers = null; - - // TODO post a message to the handler to obtain serial ordering - synchronized (mInstallLock) { - String fullPathStr = null; - File fullPath = null; - if (path != null) { - fullPath = new File(mRootDir, path); - fullPathStr = fullPath.getPath(); - } - - if (DEBUG_APP_DIR_OBSERVER) - Log.v(TAG, "File " + fullPathStr + " changed: " + Integer.toHexString(event)); - - if (!isApkFile(fullPath)) { - if (DEBUG_APP_DIR_OBSERVER) - Log.v(TAG, "Ignoring change of non-package file: " + fullPathStr); - return; - } - - // Ignore packages that are being installed or - // have just been installed. - if (ignoreCodePath(fullPathStr)) { - return; - } - PackageParser.Package p = null; - PackageSetting ps = null; - // reader - synchronized (mPackages) { - p = mAppDirs.get(fullPathStr); - if (p != null) { - ps = mSettings.mPackages.get(p.applicationInfo.packageName); - if (ps != null) { - removedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); - } else { - removedUsers = sUserManager.getUserIds(); - } - } - addedUsers = sUserManager.getUserIds(); - } - if ((event&REMOVE_EVENTS) != 0) { - if (ps != null) { - if (DEBUG_REMOVE) Slog.d(TAG, "Package disappeared: " + ps); - removePackageLI(ps, true); - removedPackage = ps.name; - removedAppId = ps.appId; - } - } - - if ((event&ADD_EVENTS) != 0) { - if (p == null) { - if (DEBUG_INSTALL) Slog.d(TAG, "New file appeared: " + fullPath); - int flags = PackageParser.PARSE_CHATTY | PackageParser.PARSE_MUST_BE_APK; - if (mIsRom) { - flags |= PackageParser.PARSE_IS_SYSTEM - | PackageParser.PARSE_IS_SYSTEM_DIR; - if (mIsPrivileged) { - flags |= PackageParser.PARSE_IS_PRIVILEGED; - } - } - try { - p = scanPackageLI(fullPath, flags, - SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME, - System.currentTimeMillis(), UserHandle.ALL, null); - } catch (PackageManagerException e) { - Slog.w(TAG, "Failed to scan " + fullPath + ": " + e.getMessage()); - p = null; - } - if (p != null) { - /* - * TODO this seems dangerous as the package may have - * changed since we last acquired the mPackages - * lock. - */ - // writer - synchronized (mPackages) { - updatePermissionsLPw(p.packageName, p, - p.permissions.size() > 0 ? UPDATE_PERMISSIONS_ALL : 0); - } - addedPackage = p.applicationInfo.packageName; - addedAppId = UserHandle.getAppId(p.applicationInfo.uid); - } - } - } - - // reader - synchronized (mPackages) { - mSettings.writeLPr(); - } - } - - if (removedPackage != null) { - Bundle extras = new Bundle(1); - extras.putInt(Intent.EXTRA_UID, removedAppId); - extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false); - sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, - extras, null, null, removedUsers); - } - if (addedPackage != null) { - Bundle extras = new Bundle(1); - extras.putInt(Intent.EXTRA_UID, addedAppId); - sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, - extras, null, null, addedUsers); - } - } - - private final String mRootDir; - private final boolean mIsRom; - private final boolean mIsPrivileged; - } @Override public void installPackage(String originPath, IPackageInstallObserver2 observer, int flags, diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp index 8bb6e8a6cc9e..46327d7db897 100644 --- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp @@ -53,6 +53,7 @@ static jmethodID method_reportGeofenceRemoveStatus; static jmethodID method_reportGeofencePauseStatus; static jmethodID method_reportGeofenceResumeStatus; static jmethodID method_reportMeasurementData; +static jmethodID method_reportNavigationMessages; static const GpsInterface* sGpsInterface = NULL; static const GpsXtraInterface* sGpsXtraInterface = NULL; @@ -62,6 +63,7 @@ static const GpsDebugInterface* sGpsDebugInterface = NULL; static const AGpsRilInterface* sAGpsRilInterface = NULL; static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL; static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL; +static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL; // temporary storage for GPS callbacks static GpsSvStatus sGpsSvStatus; @@ -447,6 +449,10 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, clazz, "reportMeasurementData", "(Landroid/location/GpsMeasurementsEvent;)V"); + method_reportNavigationMessages = env->GetMethodID( + clazz, + "reportNavigationMessage", + "(Landroid/location/GpsNavigationMessageEvent;)V"); err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); if (err == 0) { @@ -472,6 +478,9 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, (const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE); sGpsMeasurementInterface = (const GpsMeasurementInterface*)sGpsInterface->get_extension(GPS_MEASUREMENT_INTERFACE); + sGpsNavigationMessageInterface = + (const GpsNavigationMessageInterface*)sGpsInterface->get_extension( + GPS_NAVIGATION_MESSAGE_INTERFACE); } } @@ -1212,7 +1221,6 @@ static void measurement_callback(GpsData* data) { checkAndClearExceptionFromCallback(env, __FUNCTION__); } else { ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%d", data->size); - return; } } @@ -1223,7 +1231,7 @@ GpsMeasurementCallbacks sGpsMeasurementCallbacks = { static jboolean android_location_GpsLocationProvider_is_measurement_supported( JNIEnv* env, - jobject obj) { + jclass clazz) { if (sGpsMeasurementInterface != NULL) { return JNI_TRUE; } @@ -1259,6 +1267,110 @@ static jboolean android_location_GpsLocationProvider_stop_measurement_collection return JNI_TRUE; } +static jobject translate_gps_navigation_message(JNIEnv* env, GpsNavigationMessage* message) { + size_t dataLength = message->data_length; + uint8_t* data = message->data; + if (dataLength == 0 || data == NULL) { + ALOGE("Invalid Navigation Message found: data=%p, length=%d", data, dataLength); + return NULL; + } + + jclass navigationMessageClass = env->FindClass("android/location/GpsNavigationMessage"); + jmethodID navigationMessageCtor = env->GetMethodID(navigationMessageClass, "<init>", "()V"); + jobject navigationMessageObject = env->NewObject(navigationMessageClass, navigationMessageCtor); + + jmethodID setTypeMethod = env->GetMethodID(navigationMessageClass, "setType", "(B)V"); + env->CallVoidMethod(navigationMessageObject, setTypeMethod, message->type); + + jmethodID setPrnMethod = env->GetMethodID(navigationMessageClass, "setPrn", "(B)V"); + env->CallVoidMethod(navigationMessageObject, setPrnMethod, message->prn); + + jmethodID setMessageIdMethod = env->GetMethodID(navigationMessageClass, "setMessageId", "(S)V"); + env->CallVoidMethod(navigationMessageObject, setMessageIdMethod, message->message_id); + + jmethodID setSubmessageIdMethod = + env->GetMethodID(navigationMessageClass, "setSubmessageId", "(S)V"); + env->CallVoidMethod(navigationMessageObject, setSubmessageIdMethod, message->submessage_id); + + jbyteArray dataArray = env->NewByteArray(dataLength); + env->SetByteArrayRegion(dataArray, 0, dataLength, (jbyte*) data); + jmethodID setDataMethod = env->GetMethodID(navigationMessageClass, "setData", "([B)V"); + env->CallVoidMethod(navigationMessageObject, setDataMethod, dataArray); + + return navigationMessageObject; +} + +static void navigation_message_callback(GpsNavigationMessage* message) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + if (message == NULL) { + ALOGE("Invalid Navigation Message provided to callback"); + return; + } + + if (message->size == sizeof(GpsNavigationMessage)) { + jobject navigationMessage = translate_gps_navigation_message(env, message); + + jclass navigationMessageEventClass = + env->FindClass("android/location/GpsNavigationMessageEvent"); + jmethodID navigationMessageEventCtor = env->GetMethodID( + navigationMessageEventClass, + "<init>", + "(Landroid/location/GpsNavigationMessage;)V"); + jobject navigationMessageEvent = env->NewObject( + navigationMessageEventClass, + navigationMessageEventCtor, + navigationMessage); + + env->CallVoidMethod(mCallbacksObj, method_reportNavigationMessages, navigationMessageEvent); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + } else { + ALOGE("Invalid GpsNavigationMessage size found: %d", message->size); + } +} + +GpsNavigationMessageCallbacks sGpsNavigationMessageCallbacks = { + sizeof(GpsNavigationMessageCallbacks), + navigation_message_callback, +}; + +static jboolean android_location_GpsLocationProvider_is_navigation_message_supported( + JNIEnv* env, + jclass clazz) { + if(sGpsNavigationMessageInterface != NULL) { + return JNI_TRUE; + } + return JNI_FALSE; +} + +static jboolean android_location_GpsLocationProvider_start_navigation_message_collection( + JNIEnv* env, + jobject obj) { + if (sGpsNavigationMessageInterface == NULL) { + ALOGE("Navigation Message interface is not available."); + return JNI_FALSE; + } + + int result = sGpsNavigationMessageInterface->init(&sGpsNavigationMessageCallbacks); + if (result != GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS) { + ALOGE("An error has been found in %s: %d", __FUNCTION__, result); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +static jboolean android_location_GpsLocationProvider_stop_navigation_message_collection( + JNIEnv* env, + jobject obj) { + if (sGpsNavigationMessageInterface == NULL) { + ALOGE("Navigation Message interface is not available."); + return JNI_FALSE; + } + + sGpsNavigationMessageInterface->close(); + return JNI_TRUE; +} + static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native}, @@ -1336,7 +1448,16 @@ static JNINativeMethod sMethods[] = { (void*) android_location_GpsLocationProvider_start_measurement_collection}, {"native_stop_measurement_collection", "()Z", - (void*) android_location_GpsLocationProvider_stop_measurement_collection} + (void*) android_location_GpsLocationProvider_stop_measurement_collection}, + {"native_is_navigation_message_supported", + "()Z", + (void*) android_location_GpsLocationProvider_is_navigation_message_supported}, + {"native_start_navigation_message_collection", + "()Z", + (void*) android_location_GpsLocationProvider_start_navigation_message_collection}, + {"native_stop_navigation_message_collection", + "()Z", + (void*) android_location_GpsLocationProvider_stop_navigation_message_collection}, }; int register_android_server_location_GpsLocationProvider(JNIEnv* env) diff --git a/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java index cb8da707b809..2b693a31408e 100644 --- a/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java @@ -1,4 +1,4 @@ -package com.android.server.task; +package com.android.server.job; import android.content.ComponentName; @@ -9,40 +9,32 @@ import android.os.PersistableBundle; import android.test.AndroidTestCase; import android.test.RenamingDelegatingContext; import android.util.Log; +import android.util.ArraySet; -import com.android.server.job.JobMapReadFinishedListener; -import com.android.server.job.JobStore; import com.android.server.job.controllers.JobStatus; -import java.util.List; +import java.util.Iterator; /** * Test reading and writing correctly from file. */ -public class TaskStoreTest extends AndroidTestCase { +public class JobStoreTest extends AndroidTestCase { private static final String TAG = "TaskStoreTest"; private static final String TEST_PREFIX = "_test_"; - // private static final int USER_NON_0 = 3; + private static final int SOME_UID = 34234; private ComponentName mComponent; - private static final long IO_WAIT = 600L; + private static final long IO_WAIT = 1000L; JobStore mTaskStoreUnderTest; Context mTestContext; - JobMapReadFinishedListener mTaskMapReadFinishedListenerStub = - new JobMapReadFinishedListener() { - @Override - public void onJobMapReadFinished(List<JobStatus> tasks) { - // do nothing. - } - }; @Override public void setUp() throws Exception { mTestContext = new RenamingDelegatingContext(getContext(), TEST_PREFIX); Log.d(TAG, "Saving tasks to '" + mTestContext.getFilesDir() + "'"); - mTaskStoreUnderTest = JobStore.initAndGetForTesting(mTestContext, - mTestContext.getFilesDir(), mTaskMapReadFinishedListenerStub); + mTaskStoreUnderTest = + JobStore.initAndGetForTesting(mTestContext, mTestContext.getFilesDir()); mComponent = new ComponentName(getContext().getPackageName(), StubClass.class.getName()); } @@ -69,19 +61,17 @@ public class TaskStoreTest extends AndroidTestCase { mTaskStoreUnderTest.add(ts); Thread.sleep(IO_WAIT); // Manually load tasks from xml file. - mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() { - @Override - public void onJobMapReadFinished(List<JobStatus> tasks) { - assertEquals("Didn't get expected number of persisted tasks.", 1, tasks.size()); - JobStatus loadedTaskStatus = tasks.get(0); - assertTasksEqual(task, loadedTaskStatus.getJob()); - assertEquals("Different uids.", SOME_UID, tasks.get(0).getUid()); - compareTimestampsSubjectToIoLatency("Early run-times not the same after read.", - ts.getEarliestRunTime(), loadedTaskStatus.getEarliestRunTime()); - compareTimestampsSubjectToIoLatency("Late run-times not the same after read.", - ts.getLatestRunTimeElapsed(), loadedTaskStatus.getLatestRunTimeElapsed()); - } - }); + final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>(); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet); + + assertEquals("Didn't get expected number of persisted tasks.", 1, jobStatusSet.size()); + final JobStatus loadedTaskStatus = jobStatusSet.iterator().next(); + assertTasksEqual(task, loadedTaskStatus.getJob()); + assertEquals("Different uids.", SOME_UID, loadedTaskStatus.getUid()); + compareTimestampsSubjectToIoLatency("Early run-times not the same after read.", + ts.getEarliestRunTime(), loadedTaskStatus.getEarliestRunTime()); + compareTimestampsSubjectToIoLatency("Late run-times not the same after read.", + ts.getLatestRunTimeElapsed(), loadedTaskStatus.getLatestRunTimeElapsed()); } @@ -104,26 +94,25 @@ public class TaskStoreTest extends AndroidTestCase { mTaskStoreUnderTest.add(taskStatus1); mTaskStoreUnderTest.add(taskStatus2); Thread.sleep(IO_WAIT); - mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() { - @Override - public void onJobMapReadFinished(List<JobStatus> tasks) { - assertEquals("Incorrect # of persisted tasks.", 2, tasks.size()); - JobStatus loaded1 = tasks.get(0); - JobStatus loaded2 = tasks.get(1); - assertTasksEqual(task1, loaded1.getJob()); - assertTasksEqual(task2, loaded2.getJob()); - - // Check that the loaded task has the correct runtimes. - compareTimestampsSubjectToIoLatency("Early run-times not the same after read.", - taskStatus1.getEarliestRunTime(), loaded1.getEarliestRunTime()); - compareTimestampsSubjectToIoLatency("Late run-times not the same after read.", - taskStatus1.getLatestRunTimeElapsed(), loaded1.getLatestRunTimeElapsed()); - compareTimestampsSubjectToIoLatency("Early run-times not the same after read.", - taskStatus2.getEarliestRunTime(), loaded2.getEarliestRunTime()); - compareTimestampsSubjectToIoLatency("Late run-times not the same after read.", - taskStatus2.getLatestRunTimeElapsed(), loaded2.getLatestRunTimeElapsed()); - } - }); + + final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>(); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet); + assertEquals("Incorrect # of persisted tasks.", 2, jobStatusSet.size()); + Iterator<JobStatus> it = jobStatusSet.iterator(); + JobStatus loaded1 = it.next(); + JobStatus loaded2 = it.next(); + assertTasksEqual(task1, loaded1.getJob()); + assertTasksEqual(task2, loaded2.getJob()); + + // Check that the loaded task has the correct runtimes. + compareTimestampsSubjectToIoLatency("Early run-times not the same after read.", + taskStatus1.getEarliestRunTime(), loaded1.getEarliestRunTime()); + compareTimestampsSubjectToIoLatency("Late run-times not the same after read.", + taskStatus1.getLatestRunTimeElapsed(), loaded1.getLatestRunTimeElapsed()); + compareTimestampsSubjectToIoLatency("Early run-times not the same after read.", + taskStatus2.getEarliestRunTime(), loaded2.getEarliestRunTime()); + compareTimestampsSubjectToIoLatency("Late run-times not the same after read.", + taskStatus2.getLatestRunTimeElapsed(), loaded2.getLatestRunTimeElapsed()); } @@ -144,15 +133,12 @@ public class TaskStoreTest extends AndroidTestCase { mTaskStoreUnderTest.add(taskStatus); Thread.sleep(IO_WAIT); - mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() { - @Override - public void onJobMapReadFinished(List<JobStatus> tasks) { - assertEquals("Incorrect # of persisted tasks.", 1, tasks.size()); - JobStatus loaded = tasks.get(0); - assertTasksEqual(task, loaded.getJob()); - } - }); + final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>(); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet); + assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); + JobStatus loaded = jobStatusSet.iterator().next(); + assertTasksEqual(task, loaded.getJob()); } /** @@ -201,4 +187,4 @@ public class TaskStoreTest extends AndroidTestCase { private static class StubClass {} -}
\ No newline at end of file +} diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 9cff7657289c..2555874ac9b0 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -20,6 +20,7 @@ import android.annotation.SystemApi; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; +import android.content.Intent; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; @@ -2980,6 +2981,19 @@ public class TelephonyManager { /** @hide */ @SystemApi + public List<String> getCarrierPackageNamesForBroadcastIntent(Intent intent) { + try { + return getITelephony().getCarrierPackageNamesForBroadcastIntent(intent); + } catch (RemoteException ex) { + Rlog.e(TAG, "getCarrierPackageNamesForBroadcastIntent RemoteException", ex); + } catch (NullPointerException ex) { + Rlog.e(TAG, "getCarrierPackageNamesForBroadcastIntent NPE", ex); + } + return null; + } + + /** @hide */ + @SystemApi public void dial(String number) { try { getITelephony().dial(number); diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 435c3341b5a9..ec7b8ae71227 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import android.content.Intent; import android.os.Bundle; import java.util.List; import android.telephony.NeighboringCellInfo; @@ -660,6 +661,17 @@ interface ITelephony { int checkCarrierPrivilegesForPackage(String pkgname); /** + * Returns the package name of the carrier apps that should handle the input intent. + * + * @param packageManager PackageManager for getting receivers. + * @param intent Intent that will be broadcast. + * @return list of carrier app package names that can handle the intent. + * Returns null if there is an error and an empty list if there + * are no matching packages. + */ + List<String> getCarrierPackageNamesForBroadcastIntent(in Intent intent); + + /** * Set whether Android should display a simplified Mobile Network Settings UI. * The setting won't be persisted during power cycle. * diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml index a16b74901355..ee62e5ee9faa 100644 --- a/tests/VectorDrawableTest/AndroidManifest.xml +++ b/tests/VectorDrawableTest/AndroidManifest.xml @@ -100,7 +100,7 @@ </activity> <activity android:name="VectorDrawableStaticPerf" - android:label="Performance of vector images" > + android:label="System icons" > <intent-filter> <action android:name="android.intent.action.MAIN" /> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml index 66a9452d5380..3b01e029e1c7 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml @@ -26,7 +26,7 @@ <group> <path android:name="box1" - android:pathData="m20,200l100,90l180,-180l-35,-35l-145,145l-60,-60l-40,40z" + android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z" android:fill="?android:attr/colorControlActivated" android:stroke="?android:attr/colorControlActivated" android:strokeLineCap="round" diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml index 2fdb6769693a..cd2fd479098d 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml @@ -35,16 +35,16 @@ M 0, 6.125 l 7.3, 0 l 0, 12.25 - l -7.3, 0 + l-7.3, 0 z" /> </group> <group> <path android:name="one" android:fill="#ff88ff" - android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125 - l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 - l -5.046875,0.0 0.0,-1.0Z" /> + android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 + l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 + l-5.046875,0.0 0.0-1.0Z" /> </group> <group android:pivotX="3.65" @@ -57,22 +57,22 @@ M 0, 0 l 7.3, 0 l 0, 6.125 - l -7.3, 0 + l-7.3, 0 z" /> </group> <group> <path android:name="two" android:fill="#ff88ff" - android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375 - q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625 - q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625 - q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875 - q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875 - q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875 - q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625 - q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375 - q -0.78125024,0.8125 -2.2187502,2.265625Z" /> + android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 + q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625 + q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625 + q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875 + q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875 + q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875 + q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625 + q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375 + q-0.78125024,0.8125-2.2187502,2.265625Z" /> </group> </vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml index 296e026116e7..d57ae8b756ef 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml @@ -28,41 +28,41 @@ android:name="clip1" android:pathData=" M 3.65, 6.125 - m -.001, 0 + m-.001, 0 a .001,.001 0 1,0 .002,0 - a .001,.001 0 1,0 -.002,0z" + a .001,.001 0 1,0-.002,0z" android:clipToPath="true" android:fill="#112233" /> <path android:name="one" - android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125 - l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 - l -5.046875,0.0 0.0,-1.0Z" + android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 + l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 + l-5.046875,0.0 0.0-1.0Z" android:fill="#ff88ff" /> <path android:name="clip2" android:pathData=" M 3.65, 6.125 - m -6, 0 + m-6, 0 a 6,6 0 1,0 12,0 - a 6,6 0 1,0 -12,0z" + a 6,6 0 1,0-12,0z" android:clipToPath="true" android:fill="#112233" /> <path android:name="two" - android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375 - q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625 - q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625 - q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875 - q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875 - q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875 - q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625 - q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375 - q -0.78125024,0.8125 -2.2187502,2.265625Z" + android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 + q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625 + q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625 + q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875 + q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875 + q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875 + q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625 + q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375 + q-0.78125024,0.8125-2.2187502,2.265625Z" android:fill="#ff88ff" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml index 1633326ae2b0..673c46524243 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml @@ -28,21 +28,21 @@ <path android:name="one" android:fill="#ffff00" - android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125 - l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 - l -5.046875,0.0 0.0,-1.0Z" /> + android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 + l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 + l-5.046875,0.0 0.0-1.0Z" /> <path android:name="two" android:fill="#ffff00" android:fillOpacity="0" - android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375 - q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625 - q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625 - q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875 - q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875 - q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875 - q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625 - q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375 - q -0.78125024,0.8125 -2.2187502,2.265625Z" /> + android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 + q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625 + q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625 + q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875 + q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875 + q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875 + q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625 + q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375 + q-0.78125024,0.8125-2.2187502,2.265625Z" /> </group> </vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml index 7c7e679a3d1e..ccb0df0c9aa8 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml @@ -23,9 +23,9 @@ <group> <path android:name="back" - android:pathData="M 20,55 l 35.3,-35.3 7.07,7.07 -35.3,35.3 z - M 27,50 l 97,0 0,10 -97,0 z - M 20,55 l 7.07,-7.07 35.3,35.3 -7.07,7.07 z" + android:pathData="M 20,55 l 35.3-35.3 7.07,7.07-35.3,35.3 z + M 27,50 l 97,0 0,10-97,0 z + M 20,55 l 7.07-7.07 35.3,35.3-7.07,7.07 z" android:fill="#ffffffff" /> </group> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml index c93c85fef3bd..77434fca58f0 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml @@ -30,7 +30,7 @@ <path android:name="house" android:fill="#ffffffff" - android:pathData="M 100,20 l 0,0 0,140 -80,0 z M 100,20 l 0,0 80,140 -80,0 z"/> + android:pathData="M 100,20 l 0,0 0,140-80,0 z M 100,20 l 0,0 80,140-80,0 z"/> </group> </vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml index 8484e9e2f107..df24713e3ba0 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml @@ -28,19 +28,19 @@ <path android:name="bar3" android:fill="#FFFFFFFF" - android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" /> + android:pathData="M49.001,60c-5.466,0-9.899,4.478-9.899,10s4.434,10,9.899,10c5.468,0,9.899-4.478,9.899-10S54.469,60,49.001,60z" /> <path android:name="bar2" android:fill="#FFFFFFFF" - android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" /> + android:pathData="M28.001,48.787l7,7.07c7.731-7.811,20.269-7.81,28.001,0l6.999-7.07C58.403,37.071,39.599,37.071,28.001,48.787z" /> <path android:name="bar1" android:fill="#FF555555" - android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" /> + android:pathData="M14.001,34.645 L21,41.716c15.464-15.621,40.536-15.621,56,0l7.001-7.071C64.672,15.119,33.33,15.119,14.001,34.645z" /> <path android:name="bar0" android:fill="#FF555555" - android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" /> + android:pathData="M0,20.502l6.999,7.071 c23.196-23.431,60.806-23.431,84.002,0L98,20.503C70.938-6.834,27.063-6.834,0,20.502z" /> </group> </vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml index c8840f56a6b9..5a66e2d4bc9f 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml @@ -32,11 +32,11 @@ android:fill="#ff000000" android:pathData="M2.100006104,-6 C0.1449127197,-6,1.600006104,-5.975006104,0,-5.975006104 - C-1.574996948,-5.975006104,0.00309753418,-6,-1.949996948,-6 + C-1.574996948,-5.975006104,0.00309753418,-6-1.949996948-6 C-4.492996216,-6,-5.949996948,-3.718399048,-5.949996948,-1.149993896 C-5.949996948,2.379302979,-5.699996948,5.100006104,0,5.100006104 C5.699996948,5.100006104,6,2.379302979,6,-1.149993896 - C6,-3.718399048,4.643005371,-6,2.100006104,-6" /> + C6,-3.718399048,4.643005371-6,2.100006104-6" /> </group> </vector>
\ No newline at end of file |