diff options
122 files changed, 1125 insertions, 263 deletions
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index 43a163d..6382cee 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -858,6 +858,9 @@ public class SearchManager */ public Intent getAssistIntent(Context context, int userHandle) { try { + if (mService == null) { + return null; + } ComponentName comp = mService.getAssistIntent(userHandle); if (comp == null) { return null; diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java index cb61a71..24fd2e4 100644 --- a/core/java/android/appwidget/AppWidgetHost.java +++ b/core/java/android/appwidget/AppWidgetHost.java @@ -224,6 +224,22 @@ public class AppWidgetHost { } } + /** + * Gets a list of all the appWidgetIds that are bound to the current host + * + * @hide + */ + public int[] getAppWidgetIds() { + try { + if (sService == null) { + bindService(); + } + return sService.getAppWidgetIdsForHost(mHostId); + } catch (RemoteException e) { + throw new RuntimeException("system server dead?", e); + } + } + private static void checkCallerIsSystem() { int uid = Process.myUid(); if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) { diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index 977b461..e4b4b97 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -58,6 +58,7 @@ import android.util.Pair; import android.util.Slog; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.google.android.collect.Lists; import com.google.android.collect.Maps; @@ -155,7 +156,7 @@ public class SyncManager { private SyncStorageEngine mSyncStorageEngine; - // @GuardedBy("mSyncQueue") + @GuardedBy("mSyncQueue") private final SyncQueue mSyncQueue; protected final ArrayList<ActiveSyncContext> mActiveSyncContexts = Lists.newArrayList(); diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java index 10e7bff..bdc5a3f 100644 --- a/core/java/android/content/SyncStorageEngine.java +++ b/core/java/android/content/SyncStorageEngine.java @@ -16,6 +16,7 @@ package android.content; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; @@ -74,7 +75,7 @@ public class SyncStorageEngine extends Handler { private static final long DEFAULT_POLL_FREQUENCY_SECONDS = 60 * 60 * 24; // One day - // @VisibleForTesting + @VisibleForTesting static final long MILLIS_IN_4WEEKS = 1000L * 60 * 60 * 24 * 7 * 4; /** Enum value for a sync start event. */ diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java index 6def4a1..a07a865 100644 --- a/core/java/android/content/pm/RegisteredServicesCache.java +++ b/core/java/android/content/pm/RegisteredServicesCache.java @@ -34,6 +34,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.Xml; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.FastXmlSerializer; import com.google.android.collect.Lists; import com.google.android.collect.Maps; @@ -77,15 +78,15 @@ public abstract class RegisteredServicesCache<V> { private final Object mServicesLock = new Object(); - // @GuardedBy("mServicesLock") + @GuardedBy("mServicesLock") private boolean mPersistentServicesFileDidNotExist; - // @GuardedBy("mServicesLock") + @GuardedBy("mServicesLock") private final SparseArray<UserServices<V>> mUserServices = new SparseArray<UserServices<V>>(); private static class UserServices<V> { - // @GuardedBy("mServicesLock") + @GuardedBy("mServicesLock") public final Map<V, Integer> persistentServices = Maps.newHashMap(); - // @GuardedBy("mServicesLock") + @GuardedBy("mServicesLock") public Map<V, ServiceInfo<V>> services = null; } diff --git a/core/java/android/hardware/display/WifiDisplay.java b/core/java/android/hardware/display/WifiDisplay.java index 0138b1c..2fd52b8 100644 --- a/core/java/android/hardware/display/WifiDisplay.java +++ b/core/java/android/hardware/display/WifiDisplay.java @@ -107,6 +107,15 @@ public final class WifiDisplay implements Parcelable { && Objects.equal(mDeviceAlias, other.mDeviceAlias); } + /** + * Returns true if the other display is not null and has the same address as this one. + * Can be used to perform identity comparisons on displays ignoring properties + * that might change during a connection such as the name or alias. + */ + public boolean hasSameAddress(WifiDisplay other) { + return other != null && mDeviceAddress.equals(other.mDeviceAddress); + } + @Override public int hashCode() { // The address on its own should be sufficiently unique for hashing purposes. diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index f07002e..6f1cc94 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -930,11 +930,13 @@ public class InputMethodService extends AbstractInputMethodService { */ public void onConfigureWindow(Window win, boolean isFullscreen, boolean isCandidatesOnly) { - if (isFullscreen) { - mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT); - } else { - mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT); + final int currentHeight = mWindow.getWindow().getAttributes().height; + final int newHeight = isFullscreen ? MATCH_PARENT : WRAP_CONTENT; + if (mIsInputViewShown && currentHeight != newHeight) { + Log.w(TAG, "Window size has been changed. This may cause jankiness of resizing window: " + + currentHeight + " -> " + newHeight); } + mWindow.getWindow().setLayout(MATCH_PARENT, newHeight); } /** @@ -997,10 +999,11 @@ public class InputMethodService extends AbstractInputMethodService { } void updateExtractFrameVisibility() { - int vis; + final int vis; if (isFullscreenMode()) { vis = mExtractViewHidden ? View.INVISIBLE : View.VISIBLE; - mExtractFrame.setVisibility(View.VISIBLE); + // "vis" should be applied for the extract frame as well in the fullscreen mode. + mExtractFrame.setVisibility(vis); } else { vis = View.VISIBLE; mExtractFrame.setVisibility(View.GONE); diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java index 874e80a..8dc900e 100644 --- a/core/java/android/net/DhcpStateMachine.java +++ b/core/java/android/net/DhcpStateMachine.java @@ -351,6 +351,8 @@ public class DhcpStateMachine extends StateMachine { DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal(); if (dhcpAction == DhcpAction.START) { + /* Stop any existing DHCP daemon before starting new */ + NetworkUtils.stopDhcp(mInterfaceName); if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName); success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal); mDhcpInfo = dhcpInfoInternal; diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 446bbf0..c757605 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -21,6 +21,7 @@ import android.os.Parcelable; import android.os.SystemClock; import android.util.SparseBooleanArray; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.Objects; @@ -190,14 +191,14 @@ public class NetworkStats implements Parcelable { return clone; } - // @VisibleForTesting + @VisibleForTesting public NetworkStats addIfaceValues( String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { return addValues( iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L); } - // @VisibleForTesting + @VisibleForTesting public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return addValues(new Entry( @@ -269,7 +270,7 @@ public class NetworkStats implements Parcelable { return size; } - // @VisibleForTesting + @VisibleForTesting public int internalSize() { return iface.length; } @@ -335,7 +336,7 @@ public class NetworkStats implements Parcelable { * Find first stats index that matches the requested parameters, starting * search around the hinted index as an optimization. */ - // @VisibleForTesting + @VisibleForTesting public int findIndexHinted(String iface, int uid, int set, int tag, int hintIndex) { for (int offset = 0; offset < size; offset++) { final int halfOffset = offset / 2; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index d8e53d5..d3839ad 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -33,6 +33,7 @@ import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Objects; /** @@ -63,7 +64,7 @@ public class NetworkTemplate implements Parcelable { private static boolean sForceAllNetworkTypes = false; - // @VisibleForTesting + @VisibleForTesting public static void forceAllNetworkTypes() { sForceAllNetworkTypes = true; } diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 88529f8..1bada67 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -22,6 +22,8 @@ import android.os.storage.StorageVolume; import android.text.TextUtils; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + import java.io.File; /** @@ -47,7 +49,7 @@ public class Environment { private static final Object sLock = new Object(); - // @GuardedBy("sLock") + @GuardedBy("sLock") private static volatile StorageVolume sPrimaryVolume; private static StorageVolume getPrimaryVolume() { diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index 3e90dfc..ec660ee 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -15,6 +15,9 @@ */ package android.os; + +import dalvik.system.CloseGuard; + import java.io.Closeable; import java.io.File; import java.io.FileDescriptor; @@ -31,12 +34,16 @@ import java.net.Socket; */ public class ParcelFileDescriptor implements Parcelable, Closeable { private final FileDescriptor mFileDescriptor; - private boolean mClosed; - //this field is to create wrapper for ParcelFileDescriptor using another - //PartialFileDescriptor but avoid invoking close twice - //consider ParcelFileDescriptor A(fileDescriptor fd), ParcelFileDescriptor B(A) - //in this particular case fd.close might be invoked twice. - private final ParcelFileDescriptor mParcelDescriptor; + + /** + * Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid + * double-closing {@link #mFileDescriptor}. + */ + private final ParcelFileDescriptor mWrapped; + + private volatile boolean mClosed; + + private final CloseGuard mGuard = CloseGuard.get(); /** * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied @@ -289,13 +296,15 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { if (mClosed) { throw new IllegalStateException("Already closed"); } - if (mParcelDescriptor != null) { - int fd = mParcelDescriptor.detachFd(); + if (mWrapped != null) { + int fd = mWrapped.detachFd(); mClosed = true; + mGuard.close(); return fd; } int fd = getFd(); mClosed = true; + mGuard.close(); Parcel.clearFileDescriptor(mFileDescriptor); return fd; } @@ -307,15 +316,16 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * @throws IOException * If an error occurs attempting to close this ParcelFileDescriptor. */ + @Override public void close() throws IOException { - synchronized (this) { - if (mClosed) return; - mClosed = true; - } - if (mParcelDescriptor != null) { + if (mClosed) return; + mClosed = true; + mGuard.close(); + + if (mWrapped != null) { // If this is a proxy to another file descriptor, just call through to its // close method. - mParcelDescriptor.close(); + mWrapped.close(); } else { Parcel.closeFileDescriptor(mFileDescriptor); } @@ -374,6 +384,9 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { @Override protected void finalize() throws Throwable { + if (mGuard != null) { + mGuard.warnIfOpen(); + } try { if (!mClosed) { close(); @@ -384,21 +397,22 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } public ParcelFileDescriptor(ParcelFileDescriptor descriptor) { - super(); - mParcelDescriptor = descriptor; - mFileDescriptor = mParcelDescriptor.mFileDescriptor; + mWrapped = descriptor; + mFileDescriptor = mWrapped.mFileDescriptor; + mGuard.open("close"); } - /*package */ParcelFileDescriptor(FileDescriptor descriptor) { - super(); + /** {@hide} */ + public ParcelFileDescriptor(FileDescriptor descriptor) { if (descriptor == null) { throw new NullPointerException("descriptor must not be null"); } + mWrapped = null; mFileDescriptor = descriptor; - mParcelDescriptor = null; + mGuard.open("close"); } - /* Parcelable interface */ + @Override public int describeContents() { return Parcelable.CONTENTS_FILE_DESCRIPTOR; } @@ -408,6 +422,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags, * the file descriptor will be closed after a copy is written to the Parcel. */ + @Override public void writeToParcel(Parcel out, int flags) { out.writeFileDescriptor(mFileDescriptor); if ((flags&PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) { @@ -421,12 +436,14 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR = new Parcelable.Creator<ParcelFileDescriptor>() { + @Override public ParcelFileDescriptor createFromParcel(Parcel in) { return in.readFileDescriptor(); } + + @Override public ParcelFileDescriptor[] newArray(int size) { return new ParcelFileDescriptor[size]; } }; - } diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index ed51818..0ca9183 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -44,6 +44,7 @@ public final class Trace { public static final long TRACE_TAG_AUDIO = 1L << 8; public static final long TRACE_TAG_VIDEO = 1L << 9; public static final long TRACE_TAG_CAMERA = 1L << 10; + private static final long TRACE_TAG_NOT_READY = 1L << 63; public static final int TRACE_FLAGS_START_BIT = 1; public static final String[] TRACE_TAGS = { @@ -53,11 +54,8 @@ public final class Trace { public static final String PROPERTY_TRACE_TAG_ENABLEFLAGS = "debug.atrace.tags.enableflags"; - // This works as a "not ready" flag because TRACE_TAG_ALWAYS is always set. - private static final long TRACE_FLAGS_NOT_READY = 0; - // Must be volatile to avoid word tearing. - private static volatile long sEnabledTags = TRACE_FLAGS_NOT_READY; + private static volatile long sEnabledTags = TRACE_TAG_NOT_READY; private static native long nativeGetEnabledTags(); private static native void nativeTraceCounter(long tag, String name, int value); @@ -99,7 +97,7 @@ public final class Trace { */ private static long cacheEnabledTags() { long tags = nativeGetEnabledTags(); - if (tags == TRACE_FLAGS_NOT_READY) { + if (tags == TRACE_TAG_NOT_READY) { Log.w(TAG, "Unexpected value from nativeGetEnabledTags: " + tags); // keep going } @@ -115,7 +113,7 @@ public final class Trace { */ public static boolean isTagEnabled(long traceTag) { long tags = sEnabledTags; - if (tags == TRACE_FLAGS_NOT_READY) { + if (tags == TRACE_TAG_NOT_READY) { tags = cacheEnabledTags(); } return (tags & traceTag) != 0; diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index 1060bd8..bcce61d 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -607,6 +607,30 @@ public class DateUtils } /** + * Return given duration in a human-friendly format. For example, "4 + * minutes" or "1 second". Returns only largest meaningful unit of time, + * from seconds up to hours. + * + * @hide + */ + public static CharSequence formatDuration(long millis) { + final Resources res = Resources.getSystem(); + if (millis >= HOUR_IN_MILLIS) { + final int hours = (int) ((millis + 1800000) / HOUR_IN_MILLIS); + return res.getQuantityString( + com.android.internal.R.plurals.duration_hours, hours, hours); + } else if (millis >= MINUTE_IN_MILLIS) { + final int minutes = (int) ((millis + 30000) / MINUTE_IN_MILLIS); + return res.getQuantityString( + com.android.internal.R.plurals.duration_minutes, minutes, minutes); + } else { + final int seconds = (int) ((millis + 500) / SECOND_IN_MILLIS); + return res.getQuantityString( + com.android.internal.R.plurals.duration_seconds, seconds, seconds); + } + } + + /** * Formats an elapsed time in the form "MM:SS" or "H:MM:SS" * for display on the call-in-progress screen. * @param elapsedSeconds the elapsed time in seconds. diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index ff44475..1747627 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -623,6 +623,7 @@ import java.util.concurrent.atomic.AtomicInteger; * @attr ref android.R.styleable#View_hapticFeedbackEnabled * @attr ref android.R.styleable#View_keepScreenOn * @attr ref android.R.styleable#View_layerType + * @attr ref android.R.styleable#View_layoutDirection * @attr ref android.R.styleable#View_longClickable * @attr ref android.R.styleable#View_minHeight * @attr ref android.R.styleable#View_minWidth @@ -660,6 +661,7 @@ import java.util.concurrent.atomic.AtomicInteger; * @attr ref android.R.styleable#View_soundEffectsEnabled * @attr ref android.R.styleable#View_tag * @attr ref android.R.styleable#View_textAlignment + * @attr ref android.R.styleable#View_textDirection * @attr ref android.R.styleable#View_transformPivotX * @attr ref android.R.styleable#View_transformPivotY * @attr ref android.R.styleable#View_translationX @@ -5854,6 +5856,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #LAYOUT_DIRECTION_RTL}, * {@link #LAYOUT_DIRECTION_INHERIT} or * {@link #LAYOUT_DIRECTION_LOCALE}. + * * @attr ref android.R.styleable#View_layoutDirection * * @hide @@ -5909,6 +5912,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. + * + * @attr ref android.R.styleable#View_layoutDirection */ @ViewDebug.ExportedProperty(category = "layout", mapping = { @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), @@ -16627,6 +16632,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #TEXT_DIRECTION_RTL}, * {@link #TEXT_DIRECTION_LOCALE} * + * @attr ref android.R.styleable#View_textDirection + * * @hide */ @ViewDebug.ExportedProperty(category = "text", mapping = { @@ -16656,6 +16663,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution * proceeds up the parent chain of the view to get the value. If there is no parent, then it will * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. + * + * @attr ref android.R.styleable#View_textDirection */ public void setTextDirection(int textDirection) { if (getRawTextDirection() != textDirection) { @@ -16684,6 +16693,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #TEXT_DIRECTION_LTR}, * {@link #TEXT_DIRECTION_RTL}, * {@link #TEXT_DIRECTION_LOCALE} + * + * @attr ref android.R.styleable#View_textDirection */ public int getTextDirection() { return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; @@ -16816,6 +16827,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #TEXT_ALIGNMENT_VIEW_START}, * {@link #TEXT_ALIGNMENT_VIEW_END} * + * @attr ref android.R.styleable#View_textAlignment + * * @hide */ @ViewDebug.ExportedProperty(category = "text", mapping = { @@ -16879,6 +16892,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #TEXT_ALIGNMENT_TEXT_END}, * {@link #TEXT_ALIGNMENT_VIEW_START}, * {@link #TEXT_ALIGNMENT_VIEW_END} + * + * @attr ref android.R.styleable#View_textAlignment */ @ViewDebug.ExportedProperty(category = "text", mapping = { @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index b1a44c5..521e686 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -291,6 +291,7 @@ public class Editor { mErrorWasChanged = true; if (mError == null) { + setErrorIcon(null); if (mErrorPopup != null) { if (mErrorPopup.isShowing()) { mErrorPopup.dismiss(); @@ -299,10 +300,11 @@ public class Editor { mErrorPopup = null; } - setErrorIcon(null); - } else if (mTextView.isFocused()) { - showError(); + } else { setErrorIcon(icon); + if (mTextView.isFocused()) { + showError(); + } } } @@ -321,8 +323,6 @@ public class Editor { if (mErrorPopup.isShowing()) { mErrorPopup.dismiss(); } - - setErrorIcon(null); } mShowErrorAfterAttach = false; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 5d90400..267b22a 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8229,9 +8229,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener TextDirectionHeuristic getTextDirectionHeuristic() { if (hasPasswordTransformationMethod()) { - // TODO: take care of the content direction to show the password text and dots justified - // to the left or to the right - return TextDirectionHeuristics.LOCALE; + // passwords fields should be LTR + return TextDirectionHeuristics.LTR; } // Always need to resolve layout direction first diff --git a/core/java/com/android/internal/annotations/GuardedBy.java b/core/java/com/android/internal/annotations/GuardedBy.java new file mode 100644 index 0000000..fc61945 --- /dev/null +++ b/core/java/com/android/internal/annotations/GuardedBy.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation type used to mark a method or field that can only be accessed when + * holding the referenced lock. + */ +@Target({ ElementType.FIELD, ElementType.METHOD }) +@Retention(RetentionPolicy.CLASS) +public @interface GuardedBy { + String value(); +} diff --git a/core/java/com/android/internal/annotations/Immutable.java b/core/java/com/android/internal/annotations/Immutable.java new file mode 100644 index 0000000..b424275 --- /dev/null +++ b/core/java/com/android/internal/annotations/Immutable.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation type used to mark a class which is immutable. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.CLASS) +public @interface Immutable { +} diff --git a/core/java/com/android/internal/annotations/VisibleForTesting.java b/core/java/com/android/internal/annotations/VisibleForTesting.java new file mode 100644 index 0000000..bc3121c --- /dev/null +++ b/core/java/com/android/internal/annotations/VisibleForTesting.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Denotes that the class, method or field has its visibility relaxed so + * that unit tests can access it. + * <p/> + * The <code>visibility</code> argument can be used to specific what the original + * visibility should have been if it had not been made public or package-private for testing. + * The default is to consider the element private. + */ +@Retention(RetentionPolicy.SOURCE) +public @interface VisibleForTesting { + /** + * Intended visibility if the element had not been made public or package-private for + * testing. + */ + enum Visibility { + /** The element should be considered protected. */ + PROTECTED, + /** The element should be considered package-private. */ + PACKAGE, + /** The element should be considered private. */ + PRIVATE + } + + /** + * Intended visibility if the element had not been made public or package-private for testing. + * If not specified, one should assume the element originally intended to be private. + */ + Visibility visibility() default Visibility.PRIVATE; +} diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl index cfb16fa..b63ad62 100644 --- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl +++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl @@ -38,6 +38,7 @@ interface IAppWidgetService { void deleteHost(int hostId); void deleteAllHosts(); RemoteViews getAppWidgetViews(int appWidgetId); + int[] getAppWidgetIdsForHost(int hostId); // // for AppWidgetManager diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 8b222f0..c517a68 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -25,6 +25,7 @@ import android.net.NetworkStats; import android.os.StrictMode; import android.os.SystemClock; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ProcFileReader; import java.io.File; @@ -53,7 +54,7 @@ public class NetworkStatsFactory { this(new File("/proc/")); } - // @VisibleForTesting + @VisibleForTesting public NetworkStatsFactory(File procRoot) { mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all"); mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp index e7c4c23..9537ac4 100644 --- a/core/jni/android_net_wifi_Wifi.cpp +++ b/core/jni/android_net_wifi_Wifi.cpp @@ -122,9 +122,9 @@ static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject, jboolean return (jboolean)(::wifi_start_supplicant(p2pSupported) == 0); } -static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject) +static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject, jboolean p2pSupported) { - return (jboolean)(::wifi_stop_supplicant() == 0); + return (jboolean)(::wifi_stop_supplicant(p2pSupported) == 0); } static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject, jstring jIface) @@ -204,7 +204,7 @@ static JNINativeMethod gWifiMethods[] = { { "isDriverLoaded", "()Z", (void *)android_net_wifi_isDriverLoaded }, { "unloadDriver", "()Z", (void *)android_net_wifi_unloadDriver }, { "startSupplicant", "(Z)Z", (void *)android_net_wifi_startSupplicant }, - { "killSupplicant", "()Z", (void *)android_net_wifi_killSupplicant }, + { "killSupplicant", "(Z)Z", (void *)android_net_wifi_killSupplicant }, { "connectToSupplicant", "(Ljava/lang/String;)Z", (void *)android_net_wifi_connectToSupplicant }, { "closeSupplicantConnection", "(Ljava/lang/String;)V", diff --git a/core/res/res/drawable-hdpi/ic_coins_l.png b/core/res/res/drawable-hdpi/ic_coins_l.png Binary files differnew file mode 100644 index 0000000..e1e3e2a --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_coins_l.png diff --git a/core/res/res/drawable-mdpi/ic_coins_l.png b/core/res/res/drawable-mdpi/ic_coins_l.png Binary files differnew file mode 100644 index 0000000..a6d7abb --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_coins_l.png diff --git a/core/res/res/drawable-xhdpi/ic_coins_l.png b/core/res/res/drawable-xhdpi/ic_coins_l.png Binary files differnew file mode 100644 index 0000000..84e7e72 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_coins_l.png diff --git a/core/res/res/layout/keyguard_pin_view.xml b/core/res/res/layout/keyguard_pin_view.xml index e494b69..6a3b9e6 100644 --- a/core/res/res/layout/keyguard_pin_view.xml +++ b/core/res/res/layout/keyguard_pin_view.xml @@ -39,6 +39,7 @@ android:layout_height="0dp" android:orientation="vertical" android:layout_weight="1" + android:layoutDirection="ltr" > <LinearLayout android:layout_width="match_parent" diff --git a/core/res/res/layout/keyguard_sim_pin_view.xml b/core/res/res/layout/keyguard_sim_pin_view.xml index 026b025..6e6fe08 100644 --- a/core/res/res/layout/keyguard_sim_pin_view.xml +++ b/core/res/res/layout/keyguard_sim_pin_view.xml @@ -44,6 +44,7 @@ android:layout_height="0dp" android:orientation="vertical" android:layout_weight="1" + android:layoutDirection="ltr" > <LinearLayout android:layout_width="match_parent" diff --git a/core/res/res/layout/keyguard_sim_puk_view.xml b/core/res/res/layout/keyguard_sim_puk_view.xml index 28a9f9a..0412fdc 100644 --- a/core/res/res/layout/keyguard_sim_puk_view.xml +++ b/core/res/res/layout/keyguard_sim_puk_view.xml @@ -45,6 +45,7 @@ android:layout_height="0dp" android:orientation="vertical" android:layout_weight="1" + android:layoutDirection="ltr" > <LinearLayout android:layout_width="match_parent" diff --git a/core/res/res/layout/sms_short_code_confirmation_dialog.xml b/core/res/res/layout/sms_short_code_confirmation_dialog.xml index ec39d97..d82f560 100644 --- a/core/res/res/layout/sms_short_code_confirmation_dialog.xml +++ b/core/res/res/layout/sms_short_code_confirmation_dialog.xml @@ -30,9 +30,9 @@ style="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingLeft="16dip" - android:paddingRight="16dip" - android:paddingTop="8dip" + android:paddingLeft="20dip" + android:paddingRight="20dip" + android:paddingTop="16dip" android:paddingBottom="16dip" /> <TableLayout android:id="@+id/sms_short_code_detail_layout" @@ -51,7 +51,7 @@ android:layout_height="wrap_content" android:paddingLeft="8dip" android:paddingRight="8dip" - android:src="@null" /> + android:src="@drawable/ic_coins_l" /> <TextView android:id="@+id/sms_short_code_detail_message" android:layout_width="match_parent" android:layout_height="wrap_content" /> @@ -60,14 +60,19 @@ <TableRow android:layout_width="wrap_content" android:layout_height="wrap_content" > - + <RelativeLayout android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingTop="12dip" + android:paddingLeft="8dip" > <CheckBox android:id="@+id/sms_short_code_remember_choice_checkbox" + android:paddingTop="11dip" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:paddingRight="8dip" /> + android:layout_height="wrap_content" /> + </RelativeLayout> <TextView android:id="@+id/sms_short_code_remember_choice_text" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:paddingTop="18dip" android:text="@string/sms_short_code_remember_choice" /> </TableRow> @@ -77,6 +82,7 @@ <Space android:layout_gravity="fill" /> <TextView android:id="@+id/sms_short_code_remember_undo_instruction" + android:paddingTop="10dip" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </TableRow> diff --git a/core/res/res/mipmap-xxhdpi/sym_def_app_icon.png b/core/res/res/mipmap-xxhdpi/sym_def_app_icon.png Binary files differnew file mode 100644 index 0000000..e3f3144 --- /dev/null +++ b/core/res/res/mipmap-xxhdpi/sym_def_app_icon.png diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 51d23e8..e71f3c5 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"weke"</string> <string name="year" msgid="4001118221013892076">"jaar"</string> <string name="years" msgid="6881577717993213522">"jaar"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Videoprobleem"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Hierdie video is nie geldig vir stroming na hierdie toestel nie."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Kan nie hierdie video speel nie."</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index f846ffd..11c11e7 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"ሳምንቶች"</string> <string name="year" msgid="4001118221013892076">"ዓመት"</string> <string name="years" msgid="6881577717993213522">"ዓመታት"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"የቪዲዮ ችግር"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"ይቅርታ፣ ይህ ቪዲዮ በዚህ መሣሪያ ለመልቀቅ ትክክል አይደለም።"</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"ይሄን ቪዲዮ ማጫወት አልተቻለም።"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index a7c0c50..e78d15b 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"أسابيع"</string> <string name="year" msgid="4001118221013892076">"سنة"</string> <string name="years" msgid="6881577717993213522">"أعوام"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"مشكلة في الفيديو"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"عذرًا، هذا الفيديو غير صالح للبث على هذا الجهاز."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"لا يمكنك تشغيل هذا الفيديو."</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 6ae68f9..34c98bb 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"тыд."</string> <string name="year" msgid="4001118221013892076">"год"</string> <string name="years" msgid="6881577717993213522">"г."</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Праблема з відэа"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Відэа не падыходзіць для патокавай перадачы на гэту прыладу."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Немагчыма прайграць гэта відэа."</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 838f0cf..1df2a78 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"седмици"</string> <string name="year" msgid="4001118221013892076">"година"</string> <string name="years" msgid="6881577717993213522">"години"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Проблем с видеоклипа"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Този видеоклип не е валиден за поточно предаване към това устройство."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Този видеоклип не може да се пусне."</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index fdc9506..20ae9dd 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"setmanes"</string> <string name="year" msgid="4001118221013892076">"any"</string> <string name="years" msgid="6881577717993213522">"anys"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Problema amb el vídeo"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Aquest vídeo no és vàlid per a la reproducció en aquest dispositiu."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"No es pot reproduir aquest vídeo."</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 374a6d5..125f7f2 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"týd."</string> <string name="year" msgid="4001118221013892076">"rokem"</string> <string name="years" msgid="6881577717993213522">"lety"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Potíže s videem"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Toto video nelze přenášet datovým proudem do tohoto zařízení."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Toto video nelze přehrát."</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index b0fcf8b..61b4e14 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"uger"</string> <string name="year" msgid="4001118221013892076">"år"</string> <string name="years" msgid="6881577717993213522">"år"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Videoproblem"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Denne video kan ikke streames på denne enhed."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Videoen kan ikke afspilles."</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index b4f87ef..cf8e9e1 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"Wochen"</string> <string name="year" msgid="4001118221013892076">"Jahr"</string> <string name="years" msgid="6881577717993213522">"Jahre"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Videoprobleme"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Dieses Video ist nicht für Streaming auf diesem Gerät gültig."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Video kann nicht wiedergegeben werden."</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 069c5d6..9b35015 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"εβδομάδες"</string> <string name="year" msgid="4001118221013892076">"έτος"</string> <string name="years" msgid="6881577717993213522">"έτη"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Πρόβλημα με το βίντεο"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Αυτό το βίντεο δεν είναι έγκυρο για ροή σε αυτή τη συσκευή."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Δεν μπορείτε να αναπαράγετε αυτό το βίντεο."</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 888e42e..5ceae63 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -993,6 +993,18 @@ <string name="weeks" msgid="6509623834583944518">"weeks"</string> <string name="year" msgid="4001118221013892076">"year"</string> <string name="years" msgid="6881577717993213522">"years"</string> + <plurals name="duration_seconds"> + <item quantity="one" msgid="6962015528372969481">"1 second"</item> + <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> seconds"</item> + </plurals> + <plurals name="duration_minutes"> + <item quantity="one" msgid="4915414002546085617">"1 minute"</item> + <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutes"</item> + </plurals> + <plurals name="duration_hours"> + <item quantity="one" msgid="8917467491248809972">"1 hour"</item> + <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> hours"</item> + </plurals> <string name="VideoView_error_title" msgid="3534509135438353077">"Video problem"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"This video isn\'t valid for streaming to this device."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Can\'t play this video."</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 47d436d..a25239b 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"semanas"</string> <string name="year" msgid="4001118221013892076">"año"</string> <string name="years" msgid="6881577717993213522">"años"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Problemas de video"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"No es posible transmitir este video al dispositivo."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"No se puede reproducir el video."</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index c129483..fb8548d 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"semanas"</string> <string name="year" msgid="4001118221013892076">"año"</string> <string name="years" msgid="6881577717993213522">"años"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Incidencias con el vídeo"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Este vídeo no se puede transmitir al dispositivo."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"No se puede reproducir el vídeo."</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 5fb21d4..0aa10f6 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"nädalat"</string> <string name="year" msgid="4001118221013892076">"aasta"</string> <string name="years" msgid="6881577717993213522">"aastat"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Probleem videoga"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"See video ei sobi voogesituseks selles seadmes."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Videot ei saa esitada."</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index d5e624d..95d3bfa 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"هفته"</string> <string name="year" msgid="4001118221013892076">"سال"</string> <string name="years" msgid="6881577717993213522">"سال"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"مشکل در ویدئو"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"متأسفیم، این ویدئو برای پخش جریانی با این دستگاه معتبر نیست."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"پخش این ویدئو ممکن نیست."</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 2b08bea..7a2eb8a 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"viikkoa"</string> <string name="year" msgid="4001118221013892076">"vuosi"</string> <string name="years" msgid="6881577717993213522">"vuotta"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Video-ongelma"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Tätä videota ei voi suoratoistaa tällä laitteella."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Videota ei voida toistaa."</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 479fe18..5bcfd7e 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"semaines"</string> <string name="year" msgid="4001118221013892076">"année"</string> <string name="years" msgid="6881577717993213522">"années"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Problème vidéo"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Impossible de lire cette vidéo en streaming sur cet appareil."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Impossible de lire la vidéo."</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 65aa563..ad4eec5 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"सप्ताह"</string> <string name="year" msgid="4001118221013892076">"वर्ष"</string> <string name="years" msgid="6881577717993213522">"वर्ष"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"वीडियो समस्याएं"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"यह वीडियो इस उपकरण पर स्ट्रीमिंग के लिए मान्य नहीं है."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"यह वीडियो नहीं चलाया जा सकता."</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index e279216..73e6d32 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"tjedna"</string> <string name="year" msgid="4001118221013892076">"godina"</string> <string name="years" msgid="6881577717993213522">"godina"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Problem s videozapisom"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ovaj videozapis nije valjan za streaming na ovaj uređaj."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Ovaj videozapis nije moguće reproducirati."</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 88f4046..8935319 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"hét"</string> <string name="year" msgid="4001118221013892076">"év"</string> <string name="years" msgid="6881577717993213522">"év"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Videoprobléma"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ezt a videót nem lehet megjeleníteni ezen az eszközön."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nem lehet lejátszani ezt a videót."</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index b5dfcd5..aafb275 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"minggu"</string> <string name="year" msgid="4001118221013892076">"tahun"</string> <string name="years" msgid="6881577717993213522">"tahun"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Masalah video"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Video ini tidak valid untuk pengaliran ke perangkat ini."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Tidak dapat memutar video ini."</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 0edb0c1..022b6d9 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"settimane"</string> <string name="year" msgid="4001118221013892076">"anno"</string> <string name="years" msgid="6881577717993213522">"anni"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Problemi video"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Questo video non è valido per lo streaming su questo dispositivo."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Impossibile riprodurre il video."</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index bb6a3ac..89ecf6a 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"שבועות"</string> <string name="year" msgid="4001118221013892076">"שנה"</string> <string name="years" msgid="6881577717993213522">"שנים"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"בעיה בווידאו"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"סרטון זה אינו חוקי להעברה כמדיה זורמת למכשיר זה."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"לא ניתן להפעיל סרטון זה."</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 8af0fed..02126f0 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"週間"</string> <string name="year" msgid="4001118221013892076">"年"</string> <string name="years" msgid="6881577717993213522">"年"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"動画の問題"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"この動画はこの端末にストリーミングできません。"</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"この動画を再生できません。"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 37c6b01..7dc7253 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"주"</string> <string name="year" msgid="4001118221013892076">"년"</string> <string name="years" msgid="6881577717993213522">"년"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"영상 문제"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"이 기기로 스트리밍하기에 적합하지 않은 동영상입니다."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"동영상을 재생할 수 없습니다."</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index f2ad504..2528e94 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"sav."</string> <string name="year" msgid="4001118221013892076">"metai"</string> <string name="years" msgid="6881577717993213522">"metai"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Vaizdo įrašo problema"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Šis vaizdo įrašas netinkamas srautiniu būdu perduoti į šį įrenginį."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Negalima paleisti šio vaizdo įrašo."</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index ee0b023..b602d16 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"nedēļas"</string> <string name="year" msgid="4001118221013892076">"gads"</string> <string name="years" msgid="6881577717993213522">"gadi"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Video problēma"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Šis video nav derīgs straumēšanai uz šo ierīci."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nevar atskaņot šo video."</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index e89f70f..75a03f0 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"minggu"</string> <string name="year" msgid="4001118221013892076">"tahun"</string> <string name="years" msgid="6881577717993213522">"tahun"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Masalah video"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Maaf, video ini tidak sah untuk penstriman ke peranti ini."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Tidak dapat mainkan video ini."</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 65014d3..d83eb26 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"uker"</string> <string name="year" msgid="4001118221013892076">"år"</string> <string name="years" msgid="6881577717993213522">"år"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Videoproblem"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Denne videoen er ikke gyldig for direkteavspilling på enheten."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Kan ikke spille av denne videoen."</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 21fe1cc..8fcaee2 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"weken"</string> <string name="year" msgid="4001118221013892076">"jaar"</string> <string name="years" msgid="6881577717993213522">"jaren"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Probleem met video"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Deze video kan niet worden gestreamd naar dit apparaat."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Deze video kan niet worden afgespeeld."</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 4282be6..350be2d 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"tygodni"</string> <string name="year" msgid="4001118221013892076">"rok"</string> <string name="years" msgid="6881577717993213522">"lat"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Problem z filmem"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ten film nie nadaje się do strumieniowego przesyłania do tego urządzenia."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nie można odtworzyć tego filmu."</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index fd7211e..0587d16 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"semanas"</string> <string name="year" msgid="4001118221013892076">"ano"</string> <string name="years" msgid="6881577717993213522">"anos"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Problema com o vídeo"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Este vídeo não é válido para transmissão em fluxo contínuo neste aparelho."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Não é possível reproduzir este vídeo."</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index ed656fe..a450f8e 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"semanas"</string> <string name="year" msgid="4001118221013892076">"ano"</string> <string name="years" msgid="6881577717993213522">"anos"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Problema com o vídeo"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Este vídeo não é válido para transmissão neste dispositivo."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Não é possível reproduzir este vídeo."</string> diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml index 0e7aaec..d3efd7e 100644 --- a/core/res/res/values-rm/strings.xml +++ b/core/res/res/values-rm/strings.xml @@ -1558,6 +1558,12 @@ <string name="weeks" msgid="6509623834583944518">"emnas"</string> <string name="year" msgid="4001118221013892076">"onn"</string> <string name="years" msgid="6881577717993213522">"onns"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <!-- no translation found for VideoView_error_title (3534509135438353077) --> <skip /> <!-- no translation found for VideoView_error_text_invalid_progressive_playback (3186670335938670444) --> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index f274acd..d0ef774 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"săptămâni"</string> <string name="year" msgid="4001118221013892076">"an"</string> <string name="years" msgid="6881577717993213522">"ani"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Problemă video"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Acest fişier video nu este valid pentru a fi transmis în flux către acest dispozitiv."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nu puteţi reda acest videoclip"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index d8713c2..6ba1fad 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"нед."</string> <string name="year" msgid="4001118221013892076">"г."</string> <string name="years" msgid="6881577717993213522">"г."</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Ошибка"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Это видео не предназначено для потокового воспроизведения на данном устройстве."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Не удалось воспроизвести видео."</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index c364380..12a3b8f 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"týždne"</string> <string name="year" msgid="4001118221013892076">"rok"</string> <string name="years" msgid="6881577717993213522">"roky"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Problém s videom"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Je nám ľúto, ale toto video sa nedá streamovať do tohto zariadenia."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Toto video nie je možné prehrať."</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 7f94c20..742a96a 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"tednov"</string> <string name="year" msgid="4001118221013892076">"leto"</string> <string name="years" msgid="6881577717993213522">"let"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Težava z videoposnetkom"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ta videoposnetek ni veljaven za pretakanje v to napravo."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Tega videoposnetka ni mogoče predvajati."</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 5a94aad..53604f1 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"недеље(а)"</string> <string name="year" msgid="4001118221013892076">"година"</string> <string name="years" msgid="6881577717993213522">"годинe(а)"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Проблем са видео снимком"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Овај видео не може да се стримује на овом уређају."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Не можете да пустите овај видео."</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 2737d62..48bd352 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"veckor"</string> <string name="year" msgid="4001118221013892076">"år"</string> <string name="years" msgid="6881577717993213522">"år"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Videoproblem"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Videon kan tyvärr inte spelas upp i den här enheten."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Det går inte att spela upp videon."</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index afdb39e..b662134 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"wiki"</string> <string name="year" msgid="4001118221013892076">"mwaka"</string> <string name="years" msgid="6881577717993213522">"miaka"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Shida ya video"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Video hii si halali kutiririshwa kwa kifaa hiki."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Haiwezi kucheza video hii."</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 0a86a86..d26b2d5 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"สัปดาห์"</string> <string name="year" msgid="4001118221013892076">"ปี"</string> <string name="years" msgid="6881577717993213522">" ปี"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"ปัญหาเกี่ยวกับวิดีโอ"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"วิดีโอนี้ไม่สามารถสตรีมไปยังอุปกรณ์นี้"</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"ไม่สามารถเล่นวิดีโอนี้"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 072f6df..485031d 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"mga linggo"</string> <string name="year" msgid="4001118221013892076">"taon"</string> <string name="years" msgid="6881577717993213522">"mga taon"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Problema sa video"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Hindi wasto ang video na ito para sa streaming sa device na ito."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Hindi ma-play ang video na ito."</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index dbb7b0d..afea527 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"hafta"</string> <string name="year" msgid="4001118221013892076">"yıl"</string> <string name="years" msgid="6881577717993213522">"yıl"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Video sorunu"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Bu video bu cihazda akış için uygun değil."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Bu video oynatılamıyor."</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 6512007..171d8ca 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"тижн."</string> <string name="year" msgid="4001118221013892076">"рік"</string> <string name="years" msgid="6881577717993213522">"р."</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Проблема з відео"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Відео не придатне для потокового передавання в цей пристрій."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Неможливо відтворити це відео."</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 7fb3412..e343ae7 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"tuần"</string> <string name="year" msgid="4001118221013892076">"năm"</string> <string name="years" msgid="6881577717993213522">"năm"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Sự cố video"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Video này không hợp lệ để phát trực tuyến đến thiết bị này."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Không thể phát video này."</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 251389b..dee48e7 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"周"</string> <string name="year" msgid="4001118221013892076">"年"</string> <string name="years" msgid="6881577717993213522">"年"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"视频问题"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"抱歉,该视频不适合在此设备上播放。"</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"无法播放此视频。"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 473b9d0..a1286f1 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"週"</string> <string name="year" msgid="4001118221013892076">"年"</string> <string name="years" msgid="6881577717993213522">"年"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"影片發生問題"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"這部影片的格式無效,因此無法在此裝置中串流播放。"</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"無法播放這部影片。"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index eb1cbfb..27660de 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -993,6 +993,12 @@ <string name="weeks" msgid="6509623834583944518">"amaviki"</string> <string name="year" msgid="4001118221013892076">"unyaka"</string> <string name="years" msgid="6881577717993213522">"iminyaka"</string> + <!-- no translation found for duration_seconds:one (6962015528372969481) --> + <!-- no translation found for duration_seconds:other (1886107766577166786) --> + <!-- no translation found for duration_minutes:one (4915414002546085617) --> + <!-- no translation found for duration_minutes:other (3165187169224908775) --> + <!-- no translation found for duration_hours:one (8917467491248809972) --> + <!-- no translation found for duration_hours:other (3863962854246773930) --> <string name="VideoView_error_title" msgid="3534509135438353077">"Inkinga yevidiyo"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Uxolo, le vidiyo ayilungele ukusakaza bukhomo kwale divaysi."</string> <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Iyehluleka ukudlala levidiyo."</string> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 447daab..48ee429 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2107,8 +2107,8 @@ <enum name="locale" value="3" /> </attr> - <!-- Direction of the text. A heuristic is used to determine the resolved text direction - of paragraphs. --> + <!-- Defines the direction of the text. A heuristic is used to determine the resolved text + direction of paragraphs. --> <attr name="textDirection" format="integer"> <!-- Default --> <enum name="inherit" value="0" /> @@ -2128,7 +2128,7 @@ <enum name="locale" value="5" /> </attr> - <!-- Alignment of the text. A heuristic is used to determine the resolved + <!-- Defines the alignment of the text. A heuristic is used to determine the resolved text alignment. --> <attr name="textAlignment" format="integer"> <!-- Default --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index f91df99..ea28a51 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1006,8 +1006,8 @@ --> <integer-array name="config_defaultNotificationVibePattern"> <item>0</item> - <item>250</item> - <item>250</item> + <item>150</item> + <item>200</item> <item>250</item> </integer-array> @@ -1017,8 +1017,8 @@ --> <integer-array name="config_notificationFallbackVibePattern"> <item>0</item> - <item>250</item> - <item>250</item> - <item>250</item> + <item>33</item> + <item>150</item> + <item>50</item> </integer-array> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 9932d1e..80c2a13 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2838,6 +2838,21 @@ <!-- Appened to express the value is this unit of time. --> <string name="years">years</string> + <!-- Phrase describing a time duration using seconds [CHAR LIMIT=16] --> + <plurals name="duration_seconds"> + <item quantity="one">1 second</item> + <item quantity="other"><xliff:g id="count">%d</xliff:g> seconds</item> + </plurals> + <!-- Phrase describing a time duration using minutes [CHAR LIMIT=16] --> + <plurals name="duration_minutes"> + <item quantity="one">1 minute</item> + <item quantity="other"><xliff:g id="count">%d</xliff:g> minutes</item> + </plurals> + <!-- Phrase describing a time duration using hours [CHAR LIMIT=16] --> + <plurals name="duration_hours"> + <item quantity="one">1 hour</item> + <item quantity="other"><xliff:g id="count">%d</xliff:g> hours</item> + </plurals> <!-- Title for error alert when a video cannot be played. it can be used by any app. --> <string name="VideoView_error_title">Video problem</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 6858732..1d29d8c 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -870,6 +870,9 @@ <java-symbol type="plurals" name="abbrev_num_hours_ago" /> <java-symbol type="plurals" name="abbrev_num_minutes_ago" /> <java-symbol type="plurals" name="abbrev_num_seconds_ago" /> + <java-symbol type="plurals" name="duration_hours" /> + <java-symbol type="plurals" name="duration_minutes" /> + <java-symbol type="plurals" name="duration_seconds" /> <java-symbol type="plurals" name="in_num_days" /> <java-symbol type="plurals" name="in_num_hours" /> <java-symbol type="plurals" name="in_num_minutes" /> diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java new file mode 100644 index 0000000..cf42bb1 --- /dev/null +++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.text.format; + +import android.test.suitebuilder.annotation.SmallTest; + +import junit.framework.TestCase; + +public class DateUtilsTest extends TestCase { + @SmallTest + public void testFormatDurationSeconds() throws Exception { + assertEquals("0 seconds", DateUtils.formatDuration(0)); + assertEquals("0 seconds", DateUtils.formatDuration(1)); + assertEquals("0 seconds", DateUtils.formatDuration(499)); + assertEquals("1 second", DateUtils.formatDuration(500)); + assertEquals("1 second", DateUtils.formatDuration(1000)); + assertEquals("2 seconds", DateUtils.formatDuration(1500)); + } + + @SmallTest + public void testFormatDurationMinutes() throws Exception { + assertEquals("59 seconds", DateUtils.formatDuration(59000)); + assertEquals("60 seconds", DateUtils.formatDuration(59500)); + assertEquals("1 minute", DateUtils.formatDuration(60000)); + assertEquals("2 minutes", DateUtils.formatDuration(120000)); + } + + @SmallTest + public void testFormatDurationHours() throws Exception { + assertEquals("59 minutes", DateUtils.formatDuration(3540000)); + assertEquals("1 hour", DateUtils.formatDuration(3600000)); + assertEquals("48 hours", DateUtils.formatDuration(172800000)); + } +} diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 13d1791..83ecdd9 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -134,6 +134,7 @@ <assign-permission name="android.permission.ACCESS_NETWORK_STATE" uid="shell" /> <assign-permission name="android.permission.ACCESS_WIFI_STATE" uid="shell" /> <assign-permission name="android.permission.BLUETOOTH" uid="shell" /> + <assign-permission name="android.permission.EXPAND_STATUS_BAR" uid="shell" /> <!-- System tool permissions granted to the shell. --> <assign-permission name="android.permission.GET_TASKS" uid="shell" /> <assign-permission name="android.permission.CHANGE_CONFIGURATION" uid="shell" /> diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 315196e..22f699f 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -436,6 +436,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished { private boolean mDockAudioMediaEnabled = true; + private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + /////////////////////////////////////////////////////////////////////////// // Construction /////////////////////////////////////////////////////////////////////////// @@ -3324,6 +3326,13 @@ public class AudioService extends IAudioService.Stub implements OnFinished { mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP); } + + synchronized (mSettingsLock) { + AudioSystem.setForceUse(AudioSystem.FOR_DOCK, + mDockAudioMediaEnabled ? + AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE); + } + // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); break; @@ -3751,13 +3760,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { config = AudioSystem.FORCE_BT_CAR_DOCK; break; case Intent.EXTRA_DOCK_STATE_LE_DESK: - synchronized (mSettingsLock) { - if (mDockAudioMediaEnabled) { - config = AudioSystem.FORCE_ANALOG_DOCK; - } else { - config = AudioSystem.FORCE_NONE; - } - } + config = AudioSystem.FORCE_ANALOG_DOCK; break; case Intent.EXTRA_DOCK_STATE_HE_DESK: config = AudioSystem.FORCE_DIGITAL_DOCK; @@ -3766,8 +3769,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished { default: config = AudioSystem.FORCE_NONE; } - - AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config); + // Low end docks have a menu to enable or disable audio + // (see mDockAudioMediaEnabled) + if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) || + ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) && + (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) { + AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config); + } + mDockState = dockState; } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED); diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 4414191..169502b 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -50,7 +50,7 @@ import java.util.Map; * <tr><th>Name</th><th>Value Type</th><th>Description</th></tr> * <tr><td>{@link #KEY_CHANNEL_COUNT}</td><td>Integer</td><td></td></tr> * <tr><td>{@link #KEY_SAMPLE_RATE}</td><td>Integer</td><td></td></tr> - * <tr><td>{@link #KEY_IS_ADTS}</td><td>Integer</td><td>optional, if content is AAC audio, setting this key to 1 indicates that each audio frame is prefixed by the ADTS header.</td></tr> + * <tr><td>{@link #KEY_IS_ADTS}</td><td>Integer</td><td>optional, if <em>decoding</em> AAC audio content, setting this key to 1 indicates that each audio frame is prefixed by the ADTS header.</td></tr> * <tr><td>{@link #KEY_AAC_PROFILE}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is AAC audio, specifies the desired profile.</td></tr> * <tr><td>{@link #KEY_CHANNEL_MASK}</td><td>Integer</td><td>A mask of audio channel assignments</td></tr> * <tr><td>{@link #KEY_FLAC_COMPRESSION_LEVEL}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is FLAC audio, specifies the desired compression level.</td></tr> @@ -140,6 +140,8 @@ public final class MediaFormat { * A key mapping to a value of 1 if the content is AAC audio and * audio frames are prefixed with an ADTS header. * The associated value is an integer (0 or 1). + * This key is only supported when _decoding_ content, it cannot + * be used to configure an encoder to emit ADTS output. */ public static final String KEY_IS_ADTS = "is-adts"; diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 2a5a16e..8701f36 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -862,7 +862,7 @@ public class MediaRouter { private static WifiDisplay findMatchingDisplay(WifiDisplay d, WifiDisplay[] displays) { for (int i = 0; i < displays.length; i++) { final WifiDisplay other = displays[i]; - if (d.getDeviceAddress().equals(other.getDeviceAddress())) { + if (d.hasSameAddress(other)) { return other; } } diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml index 2669c7e..b1104cc 100644 --- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml +++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml @@ -141,7 +141,7 @@ /> </LinearLayout> - <ImageView + <com.android.systemui.statusbar.policy.KeyButtonView android:layout_width="128dp" android:id="@+id/search_light" android:layout_height="match_parent" @@ -282,7 +282,7 @@ /> </LinearLayout> - <ImageView + <com.android.systemui.statusbar.policy.KeyButtonView android:layout_width="162dp" android:id="@+id/search_light" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml index 440a4e1..da52d89 100644 --- a/packages/SystemUI/res/layout/navigation_bar.xml +++ b/packages/SystemUI/res/layout/navigation_bar.xml @@ -145,7 +145,7 @@ /> </LinearLayout> - <ImageView + <com.android.systemui.statusbar.policy.KeyButtonView android:layout_width="80dp" android:id="@+id/search_light" android:layout_height="match_parent" @@ -289,7 +289,7 @@ /> </LinearLayout> - <ImageView + <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/search_light" android:layout_height="80dp" android:layout_width="match_parent" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java index cc9c601..f232856 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java @@ -415,7 +415,7 @@ class QuickSettings { }); parent.addView(wifiTile); - if (mModel.deviceSupportsTelephony()) { + if (mModel.deviceHasMobileData()) { // RSSI QuickSettingsTileView rssiTile = (QuickSettingsTileView) inflater.inflate(R.layout.quick_settings_tile, parent, false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java index 4513dcb..ec42883 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java @@ -29,6 +29,7 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.drawable.Drawable; import android.hardware.display.WifiDisplayStatus; +import android.net.ConnectivityManager; import android.os.Handler; import android.os.UserHandle; import android.provider.Settings; @@ -171,6 +172,8 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, private final BugreportObserver mBugreportObserver; private final BrightnessObserver mBrightnessObserver; + private final boolean mHasMobileData; + private QuickSettingsTileView mUserTile; private RefreshCallback mUserCallback; private UserState mUserState = new UserState(); @@ -249,6 +252,10 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, mBrightnessObserver = new BrightnessObserver(mHandler); mBrightnessObserver.startObserving(); + ConnectivityManager cm = (ConnectivityManager) + context.getSystemService(Context.CONNECTIVITY_SERVICE); + mHasMobileData = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); + IntentFilter alarmIntentFilter = new IntentFilter(); alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED); context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter); @@ -403,22 +410,22 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, mWifiCallback.refreshView(mWifiTile, mWifiState); } + boolean deviceHasMobileData() { + return mHasMobileData; + } + // RSSI void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) { mRSSITile = view; mRSSICallback = cb; mRSSICallback.refreshView(mRSSITile, mRSSIState); } - boolean deviceSupportsTelephony() { - PackageManager pm = mContext.getPackageManager(); - return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); - } // NetworkSignalChanged callback @Override public void onMobileDataSignalChanged( boolean enabled, int mobileSignalIconId, String signalContentDescription, int dataTypeIconId, String dataContentDescription, String enabledDesc) { - if (deviceSupportsTelephony()) { + if (deviceHasMobileData()) { // TODO: If view is in awaiting state, disable Resources r = mContext.getResources(); mRSSIState.signalIconId = enabled && (mobileSignalIconId > 0) diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java index de19bd5..0e25c84 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java @@ -26,7 +26,6 @@ import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; -import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -128,6 +127,8 @@ public class KeyguardHostView extends KeyguardViewBase { mLockPatternUtils = new LockPatternUtils(context); mAppWidgetHost = new AppWidgetHost( context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper()); + cleanupAppWidgetIds(); + mAppWidgetManager = AppWidgetManager.getInstance(mContext); mSecurityModel = new KeyguardSecurityModel(context); @@ -153,6 +154,33 @@ public class KeyguardHostView extends KeyguardViewBase { } } + private void cleanupAppWidgetIds() { + // Clean up appWidgetIds that are bound to lockscreen, but not actually used + // This is only to clean up after another bug: we used to not call + // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code + // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks + // that are triggered by deleteAppWidgetId, which is why we're doing this + int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets(); + int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds(); + for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) { + int appWidgetId = appWidgetIdsBoundToHost[i]; + if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) { + Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id " + + appWidgetId); + mAppWidgetHost.deleteAppWidgetId(appWidgetId); + } + } + } + + private static boolean contains(int[] array, int target) { + for (int value : array) { + if (value == target) { + return true; + } + } + return false; + } + private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks = new KeyguardUpdateMonitorCallback() { @Override @@ -331,10 +359,17 @@ public class KeyguardHostView extends KeyguardViewBase { }; @Override - public void onRemoveView(View v) { + public void onRemoveView(View v, boolean deletePermanently) { if (numWidgets() < MAX_WIDGETS) { setAddWidgetEnabled(true); } + if (deletePermanently) { + final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId(); + if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && + appWidgetId != LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) { + mAppWidgetHost.deleteAppWidgetId(appWidgetId); + } + } } }; diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java index 76ba811..4e8aba7 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java @@ -129,12 +129,19 @@ public class KeyguardViewManager { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - if (mKeyguardHost.getVisibility() == View.VISIBLE) { - // only propagate configuration messages if we're currently showing - maybeCreateKeyguardLocked(shouldEnableScreenRotation(), true, null); - } else { - if (DEBUG) Log.v(TAG, "onConfigurationChanged: view not visible"); - } + post(new Runnable() { + @Override + public void run() { + synchronized (KeyguardViewManager.this) { + if (mKeyguardHost.getVisibility() == View.VISIBLE) { + // only propagate configuration messages if we're currently showing + maybeCreateKeyguardLocked(shouldEnableScreenRotation(), true, null); + } else { + if (DEBUG) Log.v(TAG, "onConfigurationChanged: view not visible"); + } + } + } + }); } @Override diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java index df4c661..c227619 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java @@ -22,6 +22,7 @@ import android.app.Activity; import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.PendingIntent; +import android.app.SearchManager; import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -166,6 +167,9 @@ public class KeyguardViewMediator { /** UserManager for querying number of users */ private UserManager mUserManager; + /** SearchManager for determining whether or not search assistant is available */ + private SearchManager mSearchManager; + /** * Used to keep the device awake while to ensure the keyguard finishes opening before * we sleep. @@ -527,6 +531,7 @@ public class KeyguardViewMediator { * Let us know that the system is ready after startup. */ public void onSystemReady() { + mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); synchronized (this) { if (DEBUG) Log.d(TAG, "onSystemReady"); mSystemReady = true; @@ -1313,6 +1318,9 @@ public class KeyguardViewMediator { // showing secure lockscreen; disable ticker. flags |= StatusBarManager.DISABLE_NOTIFICATION_TICKER; } + if (!isAssistantAvailable()) { + flags |= StatusBarManager.DISABLE_SEARCH; + } } if (DEBUG) { @@ -1410,4 +1418,8 @@ public class KeyguardViewMediator { mKeyguardViewManager.showAssistant(); } + private boolean isAssistantAvailable() { + return mSearchManager != null + && mSearchManager.getAssistIntent(mContext, UserHandle.USER_CURRENT) != null; + } } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java index 25e2781..85b5472 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java @@ -237,7 +237,7 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit public void userActivity(); public void onUserActivityTimeoutChanged(); public void onAddView(View v); - public void onRemoveView(View v); + public void onRemoveView(View v, boolean deletePermanently); } public void addWidget(View widget) { @@ -245,10 +245,10 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit } - public void onRemoveView(View v) { + public void onRemoveView(View v, final boolean deletePermanently) { final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId(); if (mCallbacks != null) { - mCallbacks.onRemoveView(v); + mCallbacks.onRemoveView(v, deletePermanently); } mBackgroundWorkerHandler.post(new Runnable() { @Override diff --git a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java index 3900ab4..0b06306 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java @@ -1457,7 +1457,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } removeView(mDragView); - onRemoveView(mDragView); + onRemoveView(mDragView, false); addView(mDragView, pageUnderPointIndex); onAddView(mDragView, pageUnderPointIndex); mSidePageHoverIndex = -1; @@ -1587,7 +1587,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } //public abstract void onFlingToDelete(View v); - public abstract void onRemoveView(View v); + public abstract void onRemoveView(View v, boolean deletePermanently); public abstract void onAddView(View v, int index); private void resetTouchState() { @@ -2391,7 +2391,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc slideAnimations.start(); removeView(dragView); - onRemoveView(dragView); + onRemoveView(dragView, true); } }; } diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index 06d37dc..9590712 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -26,6 +26,8 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.os.Binder; import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; @@ -54,13 +56,19 @@ class AppWidgetService extends IAppWidgetService.Stub Locale mLocale; PackageManager mPackageManager; boolean mSafeMode; + private final Handler mSaveStateHandler; private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices; AppWidgetService(Context context) { mContext = context; + + HandlerThread handlerThread = new HandlerThread("AppWidgetService -- Save state"); + handlerThread.start(); + mSaveStateHandler = new Handler(handlerThread.getLooper()); + mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5); - AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0); + AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler); mAppWidgetServices.append(0, primary); } @@ -138,6 +146,11 @@ class AppWidgetService extends IAppWidgetService.Stub return getImplForUser(getCallingOrCurrentUserId()).allocateAppWidgetId( packageName, hostId); } + + @Override + public int[] getAppWidgetIdsForHost(int hostId) throws RemoteException { + return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIdsForHost(hostId); + } @Override public void deleteAppWidgetId(int appWidgetId) throws RemoteException { @@ -229,7 +242,7 @@ class AppWidgetService extends IAppWidgetService.Stub if (service == null) { Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding"); // TODO: Verify that it's a valid user - service = new AppWidgetServiceImpl(mContext, userId); + service = new AppWidgetServiceImpl(mContext, userId, mSaveStateHandler); service.systemReady(mSafeMode); // Assume that BOOT_COMPLETED was received, as this is a non-primary user. mAppWidgetServices.append(userId, service); diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java index daa82f2..fe92b26 100644 --- a/services/java/com/android/server/AppWidgetServiceImpl.java +++ b/services/java/com/android/server/AppWidgetServiceImpl.java @@ -41,7 +41,10 @@ import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.Environment; +import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; +import android.os.Looper; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; @@ -180,15 +183,18 @@ class AppWidgetServiceImpl { boolean mStateLoaded; int mMaxWidgetBitmapMemory; + private final Handler mSaveStateHandler; + // These are for debugging only -- widgets are going missing in some rare instances ArrayList<Provider> mDeletedProviders = new ArrayList<Provider>(); ArrayList<Host> mDeletedHosts = new ArrayList<Host>(); - AppWidgetServiceImpl(Context context, int userId) { + AppWidgetServiceImpl(Context context, int userId, Handler saveStateHandler) { mContext = context; mPm = AppGlobals.getPackageManager(); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); mUserId = userId; + mSaveStateHandler = saveStateHandler; computeMaximumWidgetBitmapMemory(); } @@ -236,7 +242,7 @@ class AppWidgetServiceImpl { updateProvidersForPackageLocked(cn.getPackageName(), removedProviders); } } - saveStateLocked(); + saveStateAsync(); } } } @@ -286,7 +292,7 @@ class AppWidgetServiceImpl { providersModified |= addProvidersForPackageLocked(pkgName); } } - saveStateLocked(); + saveStateAsync(); } } else { Bundle extras = intent.getExtras(); @@ -297,7 +303,7 @@ class AppWidgetServiceImpl { ensureStateLoadedLocked(); for (String pkgName : pkgList) { providersModified |= removeProvidersForPackageLocked(pkgName); - saveStateLocked(); + saveStateAsync(); } } } @@ -410,7 +416,7 @@ class AppWidgetServiceImpl { private void ensureStateLoadedLocked() { if (!mStateLoaded) { - loadAppWidgetList(); + loadAppWidgetListLocked(); loadStateLocked(); mStateLoaded = true; } @@ -431,7 +437,7 @@ class AppWidgetServiceImpl { host.instances.add(id); mAppWidgetIds.add(id); - saveStateLocked(); + saveStateAsync(); if (DBG) log("Allocating AppWidgetId for " + packageName + " host=" + hostId + " id=" + appWidgetId); return appWidgetId; @@ -444,7 +450,7 @@ class AppWidgetServiceImpl { AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); if (id != null) { deleteAppWidgetLocked(id); - saveStateLocked(); + saveStateAsync(); } } } @@ -456,7 +462,7 @@ class AppWidgetServiceImpl { Host host = lookupHostLocked(callingUid, hostId); if (host != null) { deleteHostLocked(host); - saveStateLocked(); + saveStateAsync(); } } } @@ -475,7 +481,7 @@ class AppWidgetServiceImpl { } } if (changed) { - saveStateLocked(); + saveStateAsync(); } } } @@ -591,7 +597,7 @@ class AppWidgetServiceImpl { // schedule the future updates registerForBroadcastsLocked(p, getAppWidgetIds(p)); - saveStateLocked(); + saveStateAsync(); } } finally { Binder.restoreCallingIdentity(ident); @@ -655,8 +661,8 @@ class AppWidgetServiceImpl { } else { mPackagesWithBindWidgetPermission.remove(packageName); } + saveStateAsync(); } - saveStateLocked(); } // Binds to a specific RemoteViewsService @@ -849,13 +855,17 @@ class AppWidgetServiceImpl { } public List<AppWidgetProviderInfo> getInstalledProviders() { + return getInstalledProviders(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN); + } + + private List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) { synchronized (mAppWidgetIds) { ensureStateLoadedLocked(); final int N = mInstalledProviders.size(); ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N); for (int i = 0; i < N; i++) { Provider p = mInstalledProviders.get(i); - if (!p.zombie) { + if (!p.zombie && (p.info.widgetCategory & categoryFilter) != 0) { result.add(cloneIfLocalBinder(p.info)); } } @@ -893,6 +903,20 @@ class AppWidgetServiceImpl { } } + private void saveStateAsync() { + mSaveStateHandler.post(mSaveStateRunnable); + } + + private final Runnable mSaveStateRunnable = new Runnable() { + @Override + public void run() { + synchronized (mAppWidgetIds) { + ensureStateLoadedLocked(); + saveStateLocked(); + } + } + }; + public void updateAppWidgetOptions(int appWidgetId, Bundle options) { synchronized (mAppWidgetIds) { options = cloneIfLocalBinder(options); @@ -913,7 +937,7 @@ class AppWidgetServiceImpl { intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, id.options); mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId)); - saveStateLocked(); + saveStateAsync(); } } @@ -1214,7 +1238,7 @@ class AppWidgetServiceImpl { } } - void loadAppWidgetList() { + void loadAppWidgetListLocked() { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); try { List<ResolveInfo> broadcastReceivers = mPm.queryIntentReceivers(intent, @@ -1334,6 +1358,28 @@ class AppWidgetServiceImpl { } } + static int[] getAppWidgetIds(Host h) { + int instancesSize = h.instances.size(); + int appWidgetIds[] = new int[instancesSize]; + for (int i = 0; i < instancesSize; i++) { + appWidgetIds[i] = h.instances.get(i).appWidgetId; + } + return appWidgetIds; + } + + public int[] getAppWidgetIdsForHost(int hostId) { + synchronized (mAppWidgetIds) { + ensureStateLoadedLocked(); + int callingUid = Binder.getCallingUid(); + Host host = lookupHostLocked(callingUid, hostId); + if (host != null) { + return getAppWidgetIds(host); + } else { + return new int[0]; + } + } + } + private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) { Provider p = null; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index ad1dfb2..a7c4d73 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2686,18 +2686,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { state + "/" + info.getDetailedState()); } - // Connectivity state changed: - // [31-14] Reserved for future use - // [13-10] Network subtype (for mobile network, as defined - // by TelephonyManager) - // [9-4] Detailed state ordinal (as defined by - // NetworkInfo.DetailedState) - // [3-0] Network type (as defined by ConnectivityManager) - int eventLogParam = (info.getType() & 0xf) | - ((info.getDetailedState().ordinal() & 0x3f) << 4) | - (info.getSubtype() << 10); - EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED, - eventLogParam); + EventLogTags.writeConnectivityStateChanged( + info.getType(), info.getSubtype(), info.getDetailedState().ordinal()); if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) { diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags index 0fe66fc..8bc2da2 100644 --- a/services/java/com/android/server/EventLogTags.logtags +++ b/services/java/com/android/server/EventLogTags.logtags @@ -135,12 +135,8 @@ option java_package com.android.server # --------------------------- # ConnectivityService.java # --------------------------- -# Connectivity state changed: -# [31-14] Reserved for future use -# [13-10] Network subtype (for mobile network, as defined by TelephonyManager) -# [ 9- 4] Detailed state ordinal (as defined by NetworkInfo.DetailedState) -# [ 3- 0] Network type (as defined by ConnectivityManager) -50020 connectivity_state_changed (custom|1|5) +# Connectivity state changed +50020 connectivity_state_changed (type|1),(subtype|1),(state|1) # --------------------------- diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index c9ff595..da6f1fa 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -2486,10 +2486,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub map.put(id, p); // Valid system default IMEs and IMEs that have English subtypes are enabled - // by default, unless there's a hard keyboard and the system IME was explicitly - // disabled - if ((isValidSystemDefaultIme(p, mContext) || isSystemImeThatHasEnglishSubtype(p)) - && (!haveHardKeyboard || disabledSysImes.indexOf(id) < 0)) { + // by default + if ((isValidSystemDefaultIme(p, mContext) || isSystemImeThatHasEnglishSubtype(p))) { setInputMethodEnabledLocked(id, true); } diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 89fa6d0..7a55497c 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -506,7 +506,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } } else { Intent statusChanged = new Intent(); - statusChanged.putExtras(extras); + statusChanged.putExtras(new Bundle(extras)); statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); try { synchronized (this) { @@ -541,7 +541,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } } else { Intent locationChanged = new Intent(); - locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); + locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location)); try { synchronized (this) { // synchronize to ensure incrementPendingBroadcastsLocked() diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index c512bc1..ad28a36 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -57,6 +57,8 @@ import android.util.AttributeSet; import android.util.Slog; import android.util.Xml; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IMediaContainerService; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; @@ -181,13 +183,13 @@ class MountService extends IMountService.Stub /** When defined, base template for user-specific {@link StorageVolume}. */ private StorageVolume mEmulatedTemplate; - // @GuardedBy("mVolumesLock") + @GuardedBy("mVolumesLock") private final ArrayList<StorageVolume> mVolumes = Lists.newArrayList(); /** Map from path to {@link StorageVolume} */ - // @GuardedBy("mVolumesLock") + @GuardedBy("mVolumesLock") private final HashMap<String, StorageVolume> mVolumesByPath = Maps.newHashMap(); /** Map from path to state */ - // @GuardedBy("mVolumesLock") + @GuardedBy("mVolumesLock") private final HashMap<String, String> mVolumeStates = Maps.newHashMap(); private volatile boolean mSystemReady = false; @@ -198,8 +200,8 @@ class MountService extends IMountService.Stub // Used as a lock for methods that register/unregister listeners. final private ArrayList<MountServiceBinderListener> mListeners = new ArrayList<MountServiceBinderListener>(); - private CountDownLatch mConnectedSignal = new CountDownLatch(1); - private CountDownLatch mAsecsScanned = new CountDownLatch(1); + private final CountDownLatch mConnectedSignal = new CountDownLatch(1); + private final CountDownLatch mAsecsScanned = new CountDownLatch(1); private boolean mSendUmsConnectedOnBoot = false; /** @@ -495,10 +497,6 @@ class MountService extends IMountService.Stub } private void waitForLatch(CountDownLatch latch) { - if (latch == null) { - return; - } - for (;;) { try { if (latch.await(5000, TimeUnit.MILLISECONDS)) { @@ -738,14 +736,12 @@ class MountService extends IMountService.Stub * the hounds! */ mConnectedSignal.countDown(); - mConnectedSignal = null; // Let package manager load internal ASECs. mPms.scanAvailableAsecs(); // Notify people waiting for ASECs to be scanned that it's done. mAsecsScanned.countDown(); - mAsecsScanned = null; } }.start(); } @@ -2571,7 +2567,7 @@ class MountService extends IMountService.Stub } } - // @VisibleForTesting + @VisibleForTesting public static String buildObbPath(final String canonicalPath, int userId, boolean forVold) { // TODO: allow caller to provide Environment for full testing diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 92af9a9..5e94a9f 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -25,6 +25,7 @@ import android.os.SystemClock; import android.util.LocalLog; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; import com.google.android.collect.Lists; import java.nio.charset.Charsets; @@ -400,7 +401,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo * Append the given argument to {@link StringBuilder}, escaping as needed, * and surrounding with quotes when it contains spaces. */ - // @VisibleForTesting + @VisibleForTesting static void appendEscaped(StringBuilder builder, String arg) { final boolean hasSpaces = arg.indexOf(' ') >= 0; if (hasSpaces) { diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 70d37bf..fa84f48 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -1077,16 +1077,27 @@ public class NotificationManagerService extends INotificationManager.Stub final AudioManager audioManager = (AudioManager) mContext .getSystemService(Context.AUDIO_SERVICE); + // sound final boolean useDefaultSound = (notification.defaults & Notification.DEFAULT_SOUND) != 0; - if (useDefaultSound || notification.sound != null) { - Uri uri; - if (useDefaultSound) { - uri = Settings.System.DEFAULT_NOTIFICATION_URI; - } else { - uri = notification.sound; - } + + Uri soundUri = null; + boolean hasValidSound = false; + + if (useDefaultSound) { + soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; + + // check to see if the default notification sound is silent + ContentResolver resolver = mContext.getContentResolver(); + hasValidSound = Settings.System.getString(resolver, + Settings.System.NOTIFICATION_SOUND) != null; + } else if (notification.sound != null) { + soundUri = notification.sound; + hasValidSound = (soundUri != null); + } + + if (hasValidSound) { boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0; int audioStreamType; if (notification.audioStreamType >= 0) { @@ -1103,7 +1114,7 @@ public class NotificationManagerService extends INotificationManager.Stub try { final IRingtonePlayer player = mAudioService.getRingtonePlayer(); if (player != null) { - player.playAsync(uri, user, looping, audioStreamType); + player.playAsync(soundUri, user, looping, audioStreamType); } } catch (RemoteException e) { } finally { @@ -1120,7 +1131,7 @@ public class NotificationManagerService extends INotificationManager.Stub // and no other vibration is specified, we apply the default vibration anyway final boolean convertSoundToVibration = !hasCustomVibrate - && (useDefaultSound || notification.sound != null) + && hasValidSound && (audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE); // The DEFAULT_VIBRATE flag trumps any custom vibration. diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index 35999ea..5c24e67 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -1090,11 +1090,8 @@ public class ActiveServices { boolean created = false; try { - mAm.mStringBuilder.setLength(0); - r.intent.getIntent().toShortString(mAm.mStringBuilder, true, false, true, false); - EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE, - r.userId, System.identityHashCode(r), r.shortName, - mAm.mStringBuilder.toString(), r.app.pid); + EventLogTags.writeAmCreateService( + r.userId, System.identityHashCode(r), r.shortName, r.app.pid); synchronized (r.stats.getBatteryStats()) { r.stats.startLaunchedLocked(); } @@ -1242,9 +1239,8 @@ public class ActiveServices { } if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down " + r + " " + r.intent); - EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE, - r.userId, System.identityHashCode(r), r.shortName, - (r.app != null) ? r.app.pid : -1); + EventLogTags.writeAmDestroyService( + r.userId, System.identityHashCode(r), (r.app != null) ? r.app.pid : -1); mServiceMap.removeServiceByName(r.name, r.userId); mServiceMap.removeServiceByIntent(r.intent, r.userId); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index d2cd646..db64a9a 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -14229,6 +14229,7 @@ public final class ActivityManagerService extends ActivityManagerNative startHomeActivityLocked(userId); } + EventLogTags.writeAmSwitchUser(userId); getUserManagerLocked().userForeground(userId); sendUserSwitchBroadcastsLocked(oldUserId, userId); if (needStart) { diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/java/com/android/server/am/EventLogTags.logtags index 6ee7507..f784861 100644 --- a/services/java/com/android/server/am/EventLogTags.logtags +++ b/services/java/com/android/server/am/EventLogTags.logtags @@ -63,9 +63,9 @@ option java_package com.android.server.am 30024 am_broadcast_discard_filter (User|1|5),(Broadcast|1|5),(Action|3),(Receiver Number|1|1),(BroadcastFilter|1|5) 30025 am_broadcast_discard_app (User|1|5),(Broadcast|1|5),(Action|3),(Receiver Number|1|1),(App|3) # A service is being created -30030 am_create_service (User|1|5),(Service Record|1|5),(Name|3),(Intent|3),(PID|1|5) +30030 am_create_service (User|1|5),(Service Record|1|5),(Name|3),(PID|1|5) # A service is being destroyed -30031 am_destroy_service (User|1|5),(Service Record|1|5),(Name|3),(PID|1|5) +30031 am_destroy_service (User|1|5),(Service Record|1|5),(PID|1|5) # A process has crashed too many times, it is being cleared 30032 am_process_crashed_too_much (User|1|5),(Name|3),(PID|1|5) # An unknown process is trying to attach to the activity manager @@ -83,3 +83,6 @@ option java_package com.android.server.am 30039 am_crash (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Exception|3),(Message|3),(File|3),(Line|1|5) # Log.wtf() called 30040 am_wtf (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Tag|3),(Message|3) + +# User switched +30041 am_switch_user (id|1|5) diff --git a/services/java/com/android/server/display/PersistentDataStore.java b/services/java/com/android/server/display/PersistentDataStore.java index 3a6e1a6..105c253 100644 --- a/services/java/com/android/server/display/PersistentDataStore.java +++ b/services/java/com/android/server/display/PersistentDataStore.java @@ -81,6 +81,15 @@ final class PersistentDataStore { } } + public WifiDisplay getRememberedWifiDisplay(String deviceAddress) { + loadIfNeeded(); + int index = findRememberedWifiDisplay(deviceAddress); + if (index >= 0) { + return mRememberedWifiDisplays.get(index); + } + return null; + } + public WifiDisplay[] getRememberedWifiDisplays() { loadIfNeeded(); return mRememberedWifiDisplays.toArray(new WifiDisplay[mRememberedWifiDisplays.size()]); @@ -137,22 +146,6 @@ final class PersistentDataStore { return true; } - public boolean renameWifiDisplay(String deviceAddress, String alias) { - int index = findRememberedWifiDisplay(deviceAddress); - if (index >= 0) { - WifiDisplay display = mRememberedWifiDisplays.get(index); - if (Objects.equal(display.getDeviceAlias(), alias)) { - return false; // already has this alias - } - WifiDisplay renamedDisplay = new WifiDisplay(deviceAddress, - display.getDeviceName(), alias); - mRememberedWifiDisplays.set(index, renamedDisplay); - setDirty(); - return true; - } - return false; - } - public boolean forgetWifiDisplay(String deviceAddress) { int index = findRememberedWifiDisplay(deviceAddress); if (index >= 0) { diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java index 45fff30..c8a44d2 100644 --- a/services/java/com/android/server/display/WifiDisplayAdapter.java +++ b/services/java/com/android/server/display/WifiDisplayAdapter.java @@ -45,6 +45,8 @@ import android.view.Surface; import java.io.PrintWriter; import java.util.Arrays; +import libcore.util.Objects; + /** * Connects to Wifi displays that implement the Miracast protocol. * <p> @@ -224,16 +226,18 @@ final class WifiDisplayAdapter extends DisplayAdapter { } } - if (mPersistentDataStore.renameWifiDisplay(address, alias)) { - mPersistentDataStore.saveIfNeeded(); - updateRememberedDisplaysLocked(); - scheduleStatusChangedBroadcastLocked(); + WifiDisplay display = mPersistentDataStore.getRememberedWifiDisplay(address); + if (display != null && !Objects.equal(display.getDeviceAlias(), alias)) { + display = new WifiDisplay(address, display.getDeviceName(), alias); + if (mPersistentDataStore.rememberWifiDisplay(display)) { + mPersistentDataStore.saveIfNeeded(); + updateRememberedDisplaysLocked(); + scheduleStatusChangedBroadcastLocked(); + } } - if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address) - && mDisplayDevice != null) { - mDisplayDevice.setNameLocked(mActiveDisplay.getFriendlyDisplayName()); - sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED); + if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) { + renameDisplayDeviceLocked(mActiveDisplay.getFriendlyDisplayName()); } } @@ -272,9 +276,42 @@ final class WifiDisplayAdapter extends DisplayAdapter { mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays); } - private void handleConnectLocked(WifiDisplay display, + private void fixRememberedDisplayNamesFromAvailableDisplaysLocked() { + // It may happen that a display name has changed since it was remembered. + // Consult the list of available displays and update the name if needed. + // We don't do anything special for the active display here. The display + // controller will send a separate event when it needs to be updates. + boolean changed = false; + for (int i = 0; i < mRememberedDisplays.length; i++) { + WifiDisplay rememberedDisplay = mRememberedDisplays[i]; + WifiDisplay availableDisplay = findAvailableDisplayLocked( + rememberedDisplay.getDeviceAddress()); + if (availableDisplay != null && !rememberedDisplay.equals(availableDisplay)) { + if (DEBUG) { + Slog.d(TAG, "fixRememberedDisplayNamesFromAvailableDisplaysLocked: " + + "updating remembered display to " + availableDisplay); + } + mRememberedDisplays[i] = availableDisplay; + changed |= mPersistentDataStore.rememberWifiDisplay(availableDisplay); + } + } + if (changed) { + mPersistentDataStore.saveIfNeeded(); + } + } + + private WifiDisplay findAvailableDisplayLocked(String address) { + for (WifiDisplay display : mAvailableDisplays) { + if (display.getDeviceAddress().equals(address)) { + return display; + } + } + return null; + } + + private void addDisplayDeviceLocked(WifiDisplay display, Surface surface, int width, int height, int flags) { - handleDisconnectLocked(); + removeDisplayDeviceLocked(); if (mPersistentDataStore.rememberWifiDisplay(display)) { mPersistentDataStore.saveIfNeeded(); @@ -303,7 +340,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { scheduleUpdateNotificationLocked(); } - private void handleDisconnectLocked() { + private void removeDisplayDeviceLocked() { if (mDisplayDevice != null) { mDisplayDevice.clearSurfaceLocked(); sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED); @@ -313,6 +350,13 @@ final class WifiDisplayAdapter extends DisplayAdapter { } } + private void renameDisplayDeviceLocked(String name) { + if (mDisplayDevice != null && !mDisplayDevice.getNameLocked().equals(name)) { + mDisplayDevice.setNameLocked(name); + sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED); + } + } + private void scheduleStatusChangedBroadcastLocked() { mCurrentStatus = null; if (!mPendingStatusChangeBroadcast) { @@ -446,6 +490,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { || !Arrays.equals(mAvailableDisplays, availableDisplays)) { mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING; mAvailableDisplays = availableDisplays; + fixRememberedDisplayNamesFromAvailableDisplaysLocked(); scheduleStatusChangedBroadcastLocked(); } } @@ -483,7 +528,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { int width, int height, int flags) { synchronized (getSyncRoot()) { display = mPersistentDataStore.applyWifiDisplayAlias(display); - handleConnectLocked(display, surface, width, height, flags); + addDisplayDeviceLocked(display, surface, width, height, flags); if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED || mActiveDisplay == null @@ -496,10 +541,24 @@ final class WifiDisplayAdapter extends DisplayAdapter { } @Override + public void onDisplayChanged(WifiDisplay display) { + synchronized (getSyncRoot()) { + display = mPersistentDataStore.applyWifiDisplayAlias(display); + if (mActiveDisplay != null + && mActiveDisplay.hasSameAddress(display) + && !mActiveDisplay.equals(display)) { + mActiveDisplay = display; + renameDisplayDeviceLocked(display.getFriendlyDisplayName()); + scheduleStatusChangedBroadcastLocked(); + } + } + } + + @Override public void onDisplayDisconnected() { // Stop listening. synchronized (getSyncRoot()) { - handleDisconnectLocked(); + removeDisplayDeviceLocked(); if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED || mActiveDisplay != null) { diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java index 39d042f..886e049 100644 --- a/services/java/com/android/server/display/WifiDisplayController.java +++ b/services/java/com/android/server/display/WifiDisplayController.java @@ -120,6 +120,12 @@ final class WifiDisplayController implements DumpUtils.Dump { // or are not trying to connect. private WifiP2pDevice mConnectingDevice; + // The device from which we are currently disconnecting. + private WifiP2pDevice mDisconnectingDevice; + + // The device to which we were previously trying to connect and are now canceling. + private WifiP2pDevice mCancelingDevice; + // The device to which we are currently connected, which means we have an active P2P group. private WifiP2pDevice mConnectedDevice; @@ -186,6 +192,7 @@ final class WifiDisplayController implements DumpUtils.Dump { updateWfdEnableState(); } + @Override public void dump(PrintWriter pw) { pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting); pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled); @@ -196,6 +203,8 @@ final class WifiDisplayController implements DumpUtils.Dump { pw.println("mDiscoverPeersRetriesLeft=" + mDiscoverPeersRetriesLeft); pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice)); pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice)); + pw.println("mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice)); + pw.println("mCancelingDisplay=" + describeWifiP2pDevice(mCancelingDevice)); pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice)); pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft); pw.println("mRemoteDisplay=" + mRemoteDisplay); @@ -384,7 +393,9 @@ final class WifiDisplayController implements DumpUtils.Dump { final int count = mAvailableWifiDisplayPeers.size(); final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count); for (int i = 0; i < count; i++) { - displays[i] = createWifiDisplay(mAvailableWifiDisplayPeers.get(i)); + WifiP2pDevice device = mAvailableWifiDisplayPeers.get(i); + displays[i] = createWifiDisplay(device); + updateDesiredDevice(device); } mHandler.post(new Runnable() { @@ -395,6 +406,23 @@ final class WifiDisplayController implements DumpUtils.Dump { }); } + private void updateDesiredDevice(WifiP2pDevice device) { + // Handle the case where the device to which we are connecting or connected + // may have been renamed or reported different properties in the latest scan. + final String address = device.deviceAddress; + if (mDesiredDevice != null && mDesiredDevice.deviceAddress.equals(address)) { + if (DEBUG) { + Slog.d(TAG, "updateDesiredDevice: new information " + + describeWifiP2pDevice(device)); + } + mDesiredDevice.update(device); + if (mAdvertisedDisplay != null + && mAdvertisedDisplay.getDeviceAddress().equals(address)) { + readvertiseDisplay(createWifiDisplay(mDesiredDevice)); + } + } + } + private void connect(final WifiP2pDevice device) { if (mDesiredDevice != null && !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) { @@ -459,12 +487,17 @@ final class WifiDisplayController implements DumpUtils.Dump { } // Step 2. Before we try to connect to a new device, disconnect from the old one. + if (mDisconnectingDevice != null) { + return; // wait for asynchronous callback + } if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) { Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName); + mDisconnectingDevice = mConnectedDevice; + mConnectedDevice = null; unadvertiseDisplay(); - final WifiP2pDevice oldDevice = mConnectedDevice; + final WifiP2pDevice oldDevice = mDisconnectingDevice; mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() { @Override public void onSuccess() { @@ -480,8 +513,8 @@ final class WifiDisplayController implements DumpUtils.Dump { } private void next() { - if (mConnectedDevice == oldDevice) { - mConnectedDevice = null; + if (mDisconnectingDevice == oldDevice) { + mDisconnectingDevice = null; updateConnection(); } } @@ -491,13 +524,18 @@ final class WifiDisplayController implements DumpUtils.Dump { // Step 3. Before we try to connect to a new device, stop trying to connect // to the old one. + if (mCancelingDevice != null) { + return; // wait for asynchronous callback + } if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) { Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName); + mCancelingDevice = mConnectingDevice; + mConnectingDevice = null; unadvertiseDisplay(); mHandler.removeCallbacks(mConnectionTimeout); - final WifiP2pDevice oldDevice = mConnectingDevice; + final WifiP2pDevice oldDevice = mCancelingDevice; mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() { @Override public void onSuccess() { @@ -513,8 +551,8 @@ final class WifiDisplayController implements DumpUtils.Dump { } private void next() { - if (mConnectingDevice == oldDevice) { - mConnectingDevice = null; + if (mCancelingDevice == oldDevice) { + mCancelingDevice = null; updateConnection(); } } @@ -763,13 +801,17 @@ final class WifiDisplayController implements DumpUtils.Dump { public void run() { if (oldSurface != null && surface != oldSurface) { mListener.onDisplayDisconnected(); - } else if (oldDisplay != null && !Objects.equal(display, oldDisplay)) { + } else if (oldDisplay != null && !oldDisplay.hasSameAddress(display)) { mListener.onDisplayConnectionFailed(); } if (display != null) { - if (!Objects.equal(display, oldDisplay)) { + if (!display.hasSameAddress(oldDisplay)) { mListener.onDisplayConnecting(display); + } else if (!display.equals(oldDisplay)) { + // The address is the same but some other property such as the + // name must have changed. + mListener.onDisplayChanged(display); } if (surface != null && surface != oldSurface) { mListener.onDisplayConnected(display, surface, width, height, flags); @@ -784,6 +826,12 @@ final class WifiDisplayController implements DumpUtils.Dump { advertiseDisplay(null, null, 0, 0, 0); } + private void readvertiseDisplay(WifiDisplay display) { + advertiseDisplay(display, mAdvertisedDisplaySurface, + mAdvertisedDisplayWidth, mAdvertisedDisplayHeight, + mAdvertisedDisplayFlags); + } + private static Inet4Address getInterfaceAddress(WifiP2pGroup info) { NetworkInterface iface; try { @@ -885,6 +933,7 @@ final class WifiDisplayController implements DumpUtils.Dump { void onDisplayConnecting(WifiDisplay display); void onDisplayConnectionFailed(); + void onDisplayChanged(WifiDisplay display); void onDisplayConnected(WifiDisplay display, Surface surface, int width, int height, int flags); void onDisplayDisconnected(); diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index 43ddf8d..b839331 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -131,6 +131,7 @@ import android.util.TrustedTime; import android.util.Xml; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Objects; @@ -184,9 +185,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int VERSION_SWITCH_UID = 10; private static final int VERSION_LATEST = VERSION_SWITCH_UID; - // @VisibleForTesting + @VisibleForTesting public static final int TYPE_WARNING = 0x1; + @VisibleForTesting public static final int TYPE_LIMIT = 0x2; + @VisibleForTesting public static final int TYPE_LIMIT_SNOOZED = 0x3; private static final String TAG_POLICY_LIST = "policy-list"; @@ -214,10 +217,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final String TAG_ALLOW_BACKGROUND = TAG + ":allowBackground"; - // @VisibleForTesting - public static final String ACTION_ALLOW_BACKGROUND = + private static final String ACTION_ALLOW_BACKGROUND = "com.android.server.net.action.ALLOW_BACKGROUND"; - public static final String ACTION_SNOOZE_WARNING = + private static final String ACTION_SNOOZE_WARNING = "com.android.server.net.action.SNOOZE_WARNING"; private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS; @@ -2063,7 +2065,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return intent; } - // @VisibleForTesting + @VisibleForTesting public void addIdleHandler(IdleHandler handler) { mHandler.getLooper().getQueue().addIdleHandler(handler); } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 0efdead..7101520 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -115,6 +115,7 @@ import android.util.Slog; import android.util.SparseIntArray; import android.util.TrustedTime; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; @@ -165,7 +166,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private IConnectivityManager mConnManager; - // @VisibleForTesting + @VisibleForTesting public static final String ACTION_NETWORK_STATS_POLL = "com.android.server.action.NETWORK_STATS_POLL"; public static final String ACTION_NETWORK_STATS_UPDATED = diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java index e05442b..dbfe34d 100644 --- a/services/java/com/android/server/pm/UserManagerService.java +++ b/services/java/com/android/server/pm/UserManagerService.java @@ -16,8 +16,7 @@ package com.android.server.pm; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.FastXmlSerializer; +import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import android.app.Activity; import android.app.ActivityManager; @@ -26,7 +25,6 @@ import android.app.IStopUserCallback; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.graphics.Bitmap; @@ -34,6 +32,7 @@ import android.graphics.BitmapFactory; import android.os.Binder; import android.os.Environment; import android.os.FileUtils; +import android.os.Handler; import android.os.IUserManager; import android.os.Process; import android.os.RemoteException; @@ -42,9 +41,17 @@ import android.os.UserManager; import android.util.AtomicFile; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.util.TimeUtils; import android.util.Xml; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.FastXmlSerializer; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + import java.io.BufferedOutputStream; import java.io.File; import java.io.FileDescriptor; @@ -54,13 +61,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - public class UserManagerService extends IUserManager.Stub { private static final String LOG_TAG = "UserManagerService"; @@ -86,7 +88,7 @@ public class UserManagerService extends IUserManager.Stub { private static final int MIN_USER_ID = 10; - private static final int USER_VERSION = 1; + private static final int USER_VERSION = 2; private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms @@ -95,19 +97,24 @@ public class UserManagerService extends IUserManager.Stub { private final Object mInstallLock; private final Object mPackagesLock; + private final Handler mHandler; + private final File mUsersDir; private final File mUserListFile; private final File mBaseUserPath; - private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>(); - private HashSet<Integer> mRemovingUserIds = new HashSet<Integer>(); + private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>(); + + /** + * Set of user IDs being actively removed. Removed IDs linger in this set + * for several seconds to work around a VFS caching issue. + */ + // @GuardedBy("mPackagesLock") + private final SparseBooleanArray mRemovingUserIds = new SparseBooleanArray(); private int[] mUserIds; private boolean mGuestEnabled; private int mNextSerialNumber; - // This resets on a reboot. Otherwise it keeps incrementing so that user ids are - // not reused in quick succession - private int mNextUserId = MIN_USER_ID; private int mUserVersion = 0; private static UserManagerService sInstance; @@ -147,6 +154,7 @@ public class UserManagerService extends IUserManager.Stub { mPm = pm; mInstallLock = installLock; mPackagesLock = packagesLock; + mHandler = new Handler(); synchronized (mInstallLock) { synchronized (mPackagesLock) { mUsersDir = new File(dataDir, USER_INFO_DIR); @@ -190,7 +198,7 @@ public class UserManagerService extends IUserManager.Stub { if (ui.partial) { continue; } - if (!excludeDying || !mRemovingUserIds.contains(ui.id)) { + if (!excludeDying || !mRemovingUserIds.get(ui.id)) { users.add(ui); } } @@ -212,7 +220,7 @@ public class UserManagerService extends IUserManager.Stub { private UserInfo getUserInfoLocked(int userId) { UserInfo ui = mUsers.get(userId); // If it is partial and not in the process of being removed, return as unknown user. - if (ui != null && ui.partial && !mRemovingUserIds.contains(userId)) { + if (ui != null && ui.partial && !mRemovingUserIds.get(userId)) { Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId); return null; } @@ -476,8 +484,7 @@ public class UserManagerService extends IUserManager.Stub { } /** - * This fixes an incorrect initialization of user name for the owner. - * TODO: Remove in the next release. + * Upgrade steps between versions, either for fixing bugs or changing the data format. */ private void upgradeIfNecessary() { int userVersion = mUserVersion; @@ -491,6 +498,16 @@ public class UserManagerService extends IUserManager.Stub { userVersion = 1; } + if (userVersion < 2) { + // Owner should be marked as initialized + UserInfo user = mUsers.get(UserHandle.USER_OWNER); + if ((user.flags & UserInfo.FLAG_INITIALIZED) == 0) { + user.flags |= UserInfo.FLAG_INITIALIZED; + writeUserLocked(user); + } + userVersion = 2; + } + if (userVersion < USER_VERSION) { Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to " + USER_VERSION); @@ -502,7 +519,7 @@ public class UserManagerService extends IUserManager.Stub { private void fallbackToSingleUserLocked() { // Create the primary user - UserInfo primary = new UserInfo(0, + UserInfo primary = new UserInfo(0, mContext.getResources().getString(com.android.internal.R.string.owner_name), null, UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED); mUsers.put(0, primary); @@ -749,7 +766,7 @@ public class UserManagerService extends IUserManager.Stub { if (userHandle == 0 || user == null) { return false; } - mRemovingUserIds.add(userHandle); + mRemovingUserIds.put(userHandle, true); // Set this to a partially created user, so that the user will be purged // on next startup, in case the runtime stops now before stopping and // removing the user completely. @@ -813,13 +830,25 @@ public class UserManagerService extends IUserManager.Stub { } } - private void removeUserStateLocked(int userHandle) { + private void removeUserStateLocked(final int userHandle) { // Cleanup package manager settings mPm.cleanUpUserLILPw(userHandle); // Remove this user from the list mUsers.remove(userHandle); - mRemovingUserIds.remove(userHandle); + + // Have user ID linger for several seconds to let external storage VFS + // cache entries expire. This must be greater than the 'entry_valid' + // timeout used by the FUSE daemon. + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + synchronized (mPackagesLock) { + mRemovingUserIds.delete(userHandle); + } + } + }, MINUTE_IN_MILLIS); + // Remove user file AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml")); userFile.delete(); @@ -906,14 +935,13 @@ public class UserManagerService extends IUserManager.Stub { */ private int getNextAvailableIdLocked() { synchronized (mPackagesLock) { - int i = mNextUserId; + int i = MIN_USER_ID; while (i < Integer.MAX_VALUE) { - if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) { + if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) { break; } i++; } - mNextUserId = i + 1; return i; } } @@ -938,7 +966,7 @@ public class UserManagerService extends IUserManager.Stub { UserInfo user = mUsers.valueAt(i); if (user == null) continue; pw.print(" "); pw.print(user); pw.print(" serialNo="); pw.print(user.serialNumber); - if (mRemovingUserIds.contains(mUsers.keyAt(i))) pw.print(" <removing> "); + if (mRemovingUserIds.get(mUsers.keyAt(i))) pw.print(" <removing> "); if (user.partial) pw.print(" <partial>"); pw.println(); pw.print(" Created: "); diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java index f34a52d..c7c2c62 100644 --- a/services/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/java/com/android/server/usb/UsbDeviceManager.java @@ -47,6 +47,8 @@ import android.provider.Settings; import android.util.Pair; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; + import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; @@ -105,7 +107,7 @@ public class UsbDeviceManager { private final Context mContext; private final ContentResolver mContentResolver; - // @GuardedBy("mLock") + @GuardedBy("mLock") private UsbSettingsManager mCurrentSettings; private NotificationManager mNotificationManager; private final boolean mHasUsbAccessory; diff --git a/services/java/com/android/server/usb/UsbHostManager.java b/services/java/com/android/server/usb/UsbHostManager.java index 175ae6f..10272f2 100644 --- a/services/java/com/android/server/usb/UsbHostManager.java +++ b/services/java/com/android/server/usb/UsbHostManager.java @@ -26,6 +26,8 @@ import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashMap; @@ -46,7 +48,7 @@ public class UsbHostManager { private final Context mContext; private final Object mLock = new Object(); - // @GuardedBy("mLock") + @GuardedBy("mLock") private UsbSettingsManager mCurrentSettings; public UsbHostManager(Context context) { diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java index 629f5fa..3918d15 100644 --- a/services/java/com/android/server/usb/UsbService.java +++ b/services/java/com/android/server/usb/UsbService.java @@ -30,6 +30,7 @@ import android.os.ParcelFileDescriptor; import android.os.UserHandle; import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import java.io.File; @@ -52,7 +53,7 @@ public class UsbService extends IUsbManager.Stub { private final Object mLock = new Object(); /** Map from {@link UserHandle} to {@link UsbSettingsManager} */ - // @GuardedBy("mLock") + @GuardedBy("mLock") private final SparseArray<UsbSettingsManager> mSettingsByUser = new SparseArray<UsbSettingsManager>(); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index b871cdc..0e29882 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -508,6 +508,10 @@ public class WifiManager { private Messenger mWifiServiceMessenger; private final CountDownLatch mConnected = new CountDownLatch(1); + private static Object sThreadRefLock = new Object(); + private static int sThreadRefCount; + private static HandlerThread sHandlerThread; + /** * Create a new WifiManager instance. * Applications will almost always want to use @@ -1365,9 +1369,14 @@ public class WifiManager { return; } - HandlerThread t = new HandlerThread("WifiManager"); - t.start(); - mHandler = new ServiceHandler(t.getLooper()); + synchronized (sThreadRefLock) { + if (++sThreadRefCount == 1) { + sHandlerThread = new HandlerThread("WifiManager"); + sHandlerThread.start(); + } + } + + mHandler = new ServiceHandler(sHandlerThread.getLooper()); mAsyncChannel.connect(mContext, mHandler, mWifiServiceMessenger); try { mConnected.await(); @@ -1983,8 +1992,10 @@ public class WifiManager { protected void finalize() throws Throwable { try { - if (mHandler != null && mHandler.getLooper() != null) { - mHandler.getLooper().quit(); + synchronized (sThreadRefLock) { + if (--sThreadRefCount == 0 && sHandlerThread != null) { + sHandlerThread.getLooper().quit(); + } } } finally { super.finalize(); diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java index 4c5fc5d..5e25623 100644 --- a/wifi/java/android/net/wifi/WifiNative.java +++ b/wifi/java/android/net/wifi/WifiNative.java @@ -61,7 +61,7 @@ public class WifiNative { /* Sends a kill signal to supplicant. To be used when we have lost connection or when the supplicant is hung */ - public native static boolean killSupplicant(); + public native static boolean killSupplicant(boolean p2pSupported); private native boolean connectToSupplicant(String iface); diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 040ff24..dafa8e8 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -1944,6 +1944,7 @@ public class WifiStateMachine extends StateMachine { case CMD_STOP_DRIVER: case CMD_DELAYED_STOP_DRIVER: case CMD_DRIVER_START_TIMED_OUT: + case CMD_CAPTIVE_CHECK_COMPLETE: case CMD_START_AP: case CMD_START_AP_SUCCESS: case CMD_START_AP_FAILURE: @@ -2189,6 +2190,13 @@ public class WifiStateMachine extends StateMachine { loge("Unable to change interface settings: " + ie); } + /* Stop a running supplicant after a runtime restart + * Avoids issues with drivers that do not handle interface down + * on a running supplicant properly. + */ + if (DBG) log("Kill any running supplicant"); + mWifiNative.killSupplicant(mP2pSupported); + if(mWifiNative.startSupplicant(mP2pSupported)) { if (DBG) log("Supplicant start successful"); mWifiMonitor.startMonitoring(); @@ -2384,7 +2392,7 @@ public class WifiStateMachine extends StateMachine { case WifiMonitor.SUP_DISCONNECTION_EVENT: if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { loge("Failed to setup control channel, restart supplicant"); - mWifiNative.killSupplicant(); + mWifiNative.killSupplicant(mP2pSupported); transitionTo(mDriverLoadedState); sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); } else { @@ -2451,7 +2459,7 @@ public class WifiStateMachine extends StateMachine { break; case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ loge("Connection lost, restart supplicant"); - mWifiNative.killSupplicant(); + mWifiNative.killSupplicant(mP2pSupported); mWifiNative.closeSupplicantConnection(); mNetworkInfo.setIsAvailable(false); handleNetworkDisconnect(); @@ -2605,14 +2613,14 @@ public class WifiStateMachine extends StateMachine { /* Socket connection can be lost when we do a graceful shutdown * or when the driver is hung. Ensure supplicant is stopped here. */ - mWifiNative.killSupplicant(); + mWifiNative.killSupplicant(mP2pSupported); mWifiNative.closeSupplicantConnection(); transitionTo(mDriverLoadedState); break; case CMD_STOP_SUPPLICANT_FAILED: if (message.arg1 == mSupplicantStopFailureToken) { loge("Timed out on a supplicant stop, kill and proceed"); - mWifiNative.killSupplicant(); + mWifiNative.killSupplicant(mP2pSupported); mWifiNative.closeSupplicantConnection(); transitionTo(mDriverLoadedState); } |