diff options
98 files changed, 1128 insertions, 298 deletions
diff --git a/api/current.txt b/api/current.txt index afcca22..fbb8333 100644 --- a/api/current.txt +++ b/api/current.txt @@ -10743,6 +10743,7 @@ package android.media { method public void setRecordPositionUpdateListener(android.media.AudioRecord.OnRecordPositionUpdateListener); method public void setRecordPositionUpdateListener(android.media.AudioRecord.OnRecordPositionUpdateListener, android.os.Handler); method public void startRecording() throws java.lang.IllegalStateException; + method public void startRecording(android.media.MediaSyncEvent) throws java.lang.IllegalStateException; method public void stop() throws java.lang.IllegalStateException; field public static final int ERROR = -1; // 0xffffffff field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe @@ -10972,8 +10973,8 @@ package android.media { method public java.nio.ByteBuffer[] getInputBuffers(); method public java.nio.ByteBuffer[] getOutputBuffers(); method public final java.util.Map<java.lang.String, java.lang.Object> getOutputFormat(); - method public final void queueInputBuffer(int, int, int, long, int); - method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int); + method public final void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException; + method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException; method public final void release(); method public final void releaseOutputBuffer(int, boolean); method public final void start(); @@ -10998,6 +10999,11 @@ package android.media { field public int size; } + public static final class MediaCodec.CryptoException extends java.lang.RuntimeException { + ctor public MediaCodec.CryptoException(int, java.lang.String); + method public int getErrorCode(); + } + public static final class MediaCodec.CryptoInfo { ctor public MediaCodec.CryptoInfo(); method public void set(int, int[], int[], byte[], byte[], int); @@ -11288,6 +11294,15 @@ package android.media { method public abstract void onScanCompleted(java.lang.String, android.net.Uri); } + public class MediaSyncEvent { + method public static android.media.MediaSyncEvent createEvent(int) throws java.lang.IllegalArgumentException; + method public int getAudioSessionId(); + method public int getType(); + method public android.media.MediaSyncEvent setAudioSessionId(int) throws java.lang.IllegalArgumentException; + field public static final int SYNC_EVENT_NONE = 0; // 0x0 + field public static final int SYNC_EVENT_PRESENTATION_COMPLETE = 1; // 0x1 + } + public class RemoteControlClient { ctor public RemoteControlClient(android.app.PendingIntent); ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper); @@ -11405,6 +11420,7 @@ package android.media { public class ToneGenerator { ctor public ToneGenerator(int, int); + method public final int getAudioSessionId(); method public void release(); method public boolean startTone(int); method public boolean startTone(int, int); @@ -11756,11 +11772,13 @@ package android.media.audiofx { method public int getFft(byte[]) throws java.lang.IllegalStateException; method public static int getMaxCaptureRate(); method public int getSamplingRate() throws java.lang.IllegalStateException; + method public int getScalingMode() throws java.lang.IllegalStateException; method public int getWaveForm(byte[]) throws java.lang.IllegalStateException; method public void release(); method public int setCaptureSize(int) throws java.lang.IllegalStateException; method public int setDataCaptureListener(android.media.audiofx.Visualizer.OnDataCaptureListener, int, boolean, boolean); method public int setEnabled(boolean) throws java.lang.IllegalStateException; + method public int setScalingMode(int) throws java.lang.IllegalStateException; field public static final int ALREADY_EXISTS = -2; // 0xfffffffe field public static final int ERROR = -1; // 0xffffffff field public static final int ERROR_BAD_VALUE = -4; // 0xfffffffc @@ -11768,6 +11786,8 @@ package android.media.audiofx { field public static final int ERROR_INVALID_OPERATION = -5; // 0xfffffffb field public static final int ERROR_NO_INIT = -3; // 0xfffffffd field public static final int ERROR_NO_MEMORY = -6; // 0xfffffffa + field public static final int SCALING_MODE_AS_PLAYED = 1; // 0x1 + field public static final int SCALING_MODE_NORMALIZED = 0; // 0x0 field public static final int STATE_ENABLED = 2; // 0x2 field public static final int STATE_INITIALIZED = 1; // 0x1 field public static final int STATE_UNINITIALIZED = 0; // 0x0 @@ -12485,10 +12505,14 @@ package android.net.nsd { method public void resolveService(android.net.nsd.NsdManager.Channel, java.lang.String, java.lang.String, android.net.nsd.NsdManager.DnsSdResolveListener); method public void stopServiceDiscovery(android.net.nsd.NsdManager.Channel, android.net.nsd.NsdManager.ActionListener); method public void unregisterService(android.net.nsd.NsdManager.Channel, int, android.net.nsd.NsdManager.ActionListener); + field public static final java.lang.String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED"; field public static final int ALREADY_ACTIVE = 3; // 0x3 field public static final int BUSY = 2; // 0x2 field public static final int ERROR = 0; // 0x0 + field public static final java.lang.String EXTRA_NSD_STATE = "nsd_state"; field public static final int MAX_REGS_REACHED = 4; // 0x4 + field public static final int NSD_STATE_DISABLED = 1; // 0x1 + field public static final int NSD_STATE_ENABLED = 2; // 0x2 field public static final int UNSUPPORTED = 1; // 0x1 } diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java index 800d0d2..dfd1820 100644 --- a/core/java/android/content/ClipboardManager.java +++ b/core/java/android/content/ClipboardManager.java @@ -77,7 +77,20 @@ public class ClipboardManager extends android.text.ClipboardManager { } }; + /** + * Defines a listener callback that is invoked when the primary clip on the clipboard changes. + * Objects that want to register a listener call + * {@link android.content.ClipboardManager#addPrimaryClipChangedListener(OnPrimaryClipChangedListener) + * addPrimaryClipChangedListener()} with an + * object that implements OnPrimaryClipChangedListener. + * + */ public interface OnPrimaryClipChangedListener { + + /** + * Callback that is invoked by {@link android.content.ClipboardManager} when the primary + * clip changes. + */ void onPrimaryClipChanged(); } diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java index 04f6377..acdc488 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -390,6 +390,8 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen // Called by SQLiteConnectionPool only. void reconfigure(SQLiteDatabaseConfiguration configuration) { + mOnlyAllowReadOnlyOperations = false; + // Register custom functions. final int functionCount = configuration.customFunctions.size(); for (int i = 0; i < functionCount; i++) { diff --git a/core/java/android/net/DhcpInfoInternal.java b/core/java/android/net/DhcpInfoInternal.java index fa77bc5..7ab8047 100644 --- a/core/java/android/net/DhcpInfoInternal.java +++ b/core/java/android/net/DhcpInfoInternal.java @@ -19,9 +19,8 @@ package android.net; import android.text.TextUtils; import android.util.Log; -import java.net.InetAddress; import java.net.Inet4Address; -import java.net.UnknownHostException; +import java.net.InetAddress; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -42,6 +41,11 @@ public class DhcpInfoInternal { public String serverAddress; public int leaseDuration; + /** + * Vendor specific information (from RFC 2132). + */ + public String vendorInfo; + private Collection<RouteInfo> mRoutes; public DhcpInfoInternal() { diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl index 077a675..3361a7b 100644 --- a/core/java/android/net/nsd/INsdManager.aidl +++ b/core/java/android/net/nsd/INsdManager.aidl @@ -26,4 +26,5 @@ import android.os.Messenger; interface INsdManager { Messenger getMessenger(); + void setEnabled(boolean enable); } diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index dac8d20..77e97e1 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -16,6 +16,8 @@ package android.net.nsd; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.os.Binder; import android.os.IBinder; @@ -133,6 +135,40 @@ public class NsdManager { private static final String TAG = "NsdManager"; INsdManager mService; + /** + * Broadcast intent action to indicate whether network service discovery is + * enabled or disabled. An extra {@link #EXTRA_NSD_STATE} provides the state + * information as int. + * + * @see #EXTRA_NSD_STATE + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_NSD_STATE_CHANGED = + "android.net.nsd.STATE_CHANGED"; + + /** + * The lookup key for an int that indicates whether network service discovery is enabled + * or disabled. Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}. + * + * @see #NSD_STATE_DISABLED + * @see #NSD_STATE_ENABLED + */ + public static final String EXTRA_NSD_STATE = "nsd_state"; + + /** + * Network service discovery is disabled + * + * @see #ACTION_NSD_STATE_CHANGED + */ + public static final int NSD_STATE_DISABLED = 1; + + /** + * Network service discovery is enabled + * + * @see #ACTION_NSD_STATE_CHANGED + */ + public static final int NSD_STATE_ENABLED = 2; + private static final int BASE = Protocol.BASE_NSD_MANAGER; /** @hide */ @@ -188,6 +224,12 @@ public class NsdManager { /** @hide */ public static final int STOP_RESOLVE_SUCCEEDED = BASE + 23; + /** @hide */ + public static final int ENABLE = BASE + 24; + /** @hide */ + public static final int DISABLE = BASE + 25; + + /** * Create a new Nsd instance. Applications use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve @@ -312,8 +354,8 @@ public class NsdManager { private DnsSdResolveListener mDnsSdResolveListener; private ActionListener mDnsSdStopResolveListener; - AsyncChannel mAsyncChannel; - ServiceHandler mHandler; + private AsyncChannel mAsyncChannel; + private ServiceHandler mHandler; class ServiceHandler extends Handler { ServiceHandler(Looper looper) { super(looper); @@ -594,6 +636,13 @@ public class NsdManager { c.mAsyncChannel.sendMessage(STOP_RESOLVE); } + /** Internal use only @hide */ + public void setEnabled(boolean enabled) { + try { + mService.setEnabled(enabled); + } catch (RemoteException e) { } + } + /** * Get a reference to NetworkService handler. This is used to establish * an AsyncChannel communication with the service diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 6dfbb2f..3a5fdd1 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3277,6 +3277,12 @@ public final class Settings { "wifi_mobile_data_transition_wakelock_timeout_ms"; /** + * Whether network service discovery is enabled. + * @hide + */ + public static final String NSD_ON = "nsd_on"; + + /** * Whether background data usage is allowed by the user. See * ConnectivityManager for more info. */ diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index bd054bc..537c474 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -2472,6 +2472,12 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal int mSystemUiVisibility; /** + * Reference count for transient state. + * @see #setHasTransientState(boolean) + */ + int mTransientStateCount = 0; + + /** * Count of how many windows this view has been attached to. */ int mWindowAttachCount; @@ -5400,21 +5406,32 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal /** * Set whether this view is currently tracking transient state that the - * framework should attempt to preserve when possible. + * framework should attempt to preserve when possible. This flag is reference counted, + * so every call to setHasTransientState(true) should be paired with a later call + * to setHasTransientState(false). * * @param hasTransientState true if this view has transient state */ public void setHasTransientState(boolean hasTransientState) { - if (hasTransientState() == hasTransientState) return; - - mPrivateFlags2 = (mPrivateFlags2 & ~HAS_TRANSIENT_STATE) | - (hasTransientState ? HAS_TRANSIENT_STATE : 0); - if (mParent != null) { - try { - mParent.childHasTransientStateChanged(this, hasTransientState); - } catch (AbstractMethodError e) { - Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + - " does not fully implement ViewParent", e); + mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : + mTransientStateCount - 1; + if (mTransientStateCount < 0) { + mTransientStateCount = 0; + Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + + "unmatched pair of setHasTransientState calls"); + } + if ((hasTransientState && mTransientStateCount == 1) || + (hasTransientState && mTransientStateCount == 0)) { + // update flag if we've just incremented up from 0 or decremented down to 0 + mPrivateFlags2 = (mPrivateFlags2 & ~HAS_TRANSIENT_STATE) | + (hasTransientState ? HAS_TRANSIENT_STATE : 0); + if (mParent != null) { + try { + mParent.childHasTransientStateChanged(this, hasTransientState); + } catch (AbstractMethodError e) { + Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + + " does not fully implement ViewParent", e); + } } } } @@ -12297,7 +12314,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal final int flags = parent.mGroupFlags; final boolean initialized = a.isInitialized(); if (!initialized) { - a.initialize(mRight - mLeft, mBottom - mTop, getWidth(), getHeight()); + a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); onAnimationStart(); } diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java index 3626aba..e573056 100644 --- a/core/java/android/view/ViewPropertyAnimator.java +++ b/core/java/android/view/ViewPropertyAnimator.java @@ -714,6 +714,7 @@ public class ViewPropertyAnimator { * value accordingly. */ private void startAnimation() { + mView.setHasTransientState(true); ValueAnimator animator = ValueAnimator.ofFloat(1.0f); ArrayList<NameValuesHolder> nameValueList = (ArrayList<NameValuesHolder>) mPendingAnimations.clone(); @@ -960,6 +961,7 @@ public class ViewPropertyAnimator { @Override public void onAnimationEnd(Animator animation) { + mView.setHasTransientState(false); if (mListener != null) { mListener.onAnimationEnd(animation); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 3d40b2f..247f673 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1199,13 +1199,13 @@ public final class ViewRootImpl implements ViewParent, } } + // Execute enqueued actions on every traversal in case a detached view enqueued an action + getRunQueue().executeActions(attachInfo.mHandler); + boolean insetsChanged = false; boolean layoutRequested = mLayoutRequested && !mStopped; if (layoutRequested) { - // Execute enqueued actions on every layout in case a view that was detached - // enqueued an action after being detached - getRunQueue().executeActions(attachInfo.mHandler); final Resources res = mView.getContext().getResources(); diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index 9c5e852..c8cfb0a 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -1485,8 +1485,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc switch (eventType) { case WebViewInputDispatcher.EVENT_TYPE_LONG_PRESS: HitTestResult hitTest = getHitTestResult(); - if (hitTest != null - && hitTest.getType() != HitTestResult.UNKNOWN_TYPE) { + if (hitTest != null) { performLongClick(); } break; diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index aea23c0..f86262e 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -46,6 +46,8 @@ import junit.framework.Assert; import java.util.ArrayList; import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; import java.util.Map; import java.util.Set; @@ -1182,7 +1184,7 @@ public final class WebViewCore { private Handler mHandler; // Message queue for containing messages before the WebCore thread is // ready. - private ArrayList<Message> mMessages = new ArrayList<Message>(); + private LinkedList<Message> mMessages = new LinkedList<Message>(); // Flag for blocking messages. This is used during DESTROY to avoid // posting more messages to the EventHub or to WebView's event handler. private boolean mBlockMessages; @@ -1822,10 +1824,13 @@ public final class WebViewCore { mDrawIsScheduled = false; } if (mMessages != null) { - Throwable throwable = new Throwable( - "EventHub.removeMessages(int what = " + what + ") is not supported " + - "before the WebViewCore is set up."); - Log.w(LOGTAG, Log.getStackTraceString(throwable)); + Iterator<Message> iter = mMessages.iterator(); + while (iter.hasNext()) { + Message m = iter.next(); + if (m.what == what) { + iter.remove(); + } + } } else { mHandler.removeMessages(what); } diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index ca5648a..ae68794 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -123,7 +123,7 @@ public abstract class AbsSeekBar extends ProgressBar { invalidate(); if (needUpdate) { updateThumbPos(getWidth(), getHeight()); - if (thumb.isStateful()) { + if (thumb != null && thumb.isStateful()) { // Note that if the states are different this won't work. // For now, let's consider that an app bug. int[] state = getDrawableState(); diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index 0786909..471f259 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -29,6 +29,8 @@ import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; +import android.text.method.AllCapsTransformationMethod; +import android.text.method.TransformationMethod2; import android.util.AttributeSet; import android.view.Gravity; import android.view.MotionEvent; @@ -91,6 +93,7 @@ public class Switch extends CompoundButton { private ColorStateList mTextColors; private Layout mOnLayout; private Layout mOffLayout; + private TransformationMethod2 mSwitchTransformationMethod; @SuppressWarnings("hiding") private final Rect mTempRect = new Rect(); @@ -207,6 +210,15 @@ public class Switch extends CompoundButton { setSwitchTypefaceByIndex(typefaceIndex, styleIndex); + boolean allCaps = appearance.getBoolean(com.android.internal.R.styleable. + TextAppearance_textAllCaps, false); + if (allCaps) { + mSwitchTransformationMethod = new AllCapsTransformationMethod(getContext()); + mSwitchTransformationMethod.setLengthChangesAllowed(true); + } else { + mSwitchTransformationMethod = null; + } + appearance.recycle(); } @@ -526,8 +538,12 @@ public class Switch extends CompoundButton { } private Layout makeLayout(CharSequence text) { - return new StaticLayout(text, mTextPaint, - (int) Math.ceil(Layout.getDesiredWidth(text, mTextPaint)), + final CharSequence transformed = (mSwitchTransformationMethod != null) + ? mSwitchTransformationMethod.getTransformation(text, this) + : text; + + return new StaticLayout(transformed, mTextPaint, + (int) Math.ceil(Layout.getDesiredWidth(transformed, mTextPaint)), Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true); } diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java index 1ba6d43..d0071e3 100644 --- a/core/java/com/android/internal/app/ActionBarImpl.java +++ b/core/java/com/android/internal/app/ActionBarImpl.java @@ -16,6 +16,7 @@ package com.android.internal.app; +import com.android.internal.view.ActionBarPolicy; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuPopupHelper; import com.android.internal.view.menu.SubMenuBuilder; @@ -183,18 +184,13 @@ public class ActionBarImpl extends ActionBar { mContextDisplayMode = mActionView.isSplitActionBar() ? CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL; - // Older apps get the home button interaction enabled by default. - // Newer apps need to enable it explicitly. - setHomeButtonEnabled(mContext.getApplicationInfo().targetSdkVersion < - Build.VERSION_CODES.ICE_CREAM_SANDWICH); - - setHasEmbeddedTabs(mContext.getResources().getBoolean( - com.android.internal.R.bool.action_bar_embed_tabs)); + ActionBarPolicy abp = ActionBarPolicy.get(mContext); + setHomeButtonEnabled(abp.enableHomeButtonByDefault()); + setHasEmbeddedTabs(abp.hasEmbeddedTabs()); } public void onConfigurationChanged(Configuration newConfig) { - setHasEmbeddedTabs(mContext.getResources().getBoolean( - com.android.internal.R.bool.action_bar_embed_tabs)); + setHasEmbeddedTabs(ActionBarPolicy.get(mContext).hasEmbeddedTabs()); } private void setHasEmbeddedTabs(boolean hasEmbeddedTabs) { diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java index 0c5d5ef..d1c2d2e 100644 --- a/core/java/com/android/internal/util/AsyncChannel.java +++ b/core/java/com/android/internal/util/AsyncChannel.java @@ -150,7 +150,7 @@ public class AsyncChannel { */ public static final int CMD_CHANNEL_DISCONNECTED = BASE + 4; - private static final int CMD_TO_STRING_COUNT = CMD_CHANNEL_DISCONNECTED + 1; + private static final int CMD_TO_STRING_COUNT = CMD_CHANNEL_DISCONNECTED - BASE + 1; private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT]; static { sCmdToString[CMD_CHANNEL_HALF_CONNECTED - BASE] = "CMD_CHANNEL_HALF_CONNECTED"; diff --git a/core/java/com/android/internal/view/ActionBarPolicy.java b/core/java/com/android/internal/view/ActionBarPolicy.java new file mode 100644 index 0000000..0c6b780 --- /dev/null +++ b/core/java/com/android/internal/view/ActionBarPolicy.java @@ -0,0 +1,90 @@ +/* + * 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.view; + +import com.android.internal.R; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.os.Build; +import android.view.ViewConfiguration; + +/** + * Allows components to query for various configuration policy decisions + * about how the action bar should lay out and behave on the current device. + */ +public class ActionBarPolicy { + private Context mContext; + + public static ActionBarPolicy get(Context context) { + return new ActionBarPolicy(context); + } + + private ActionBarPolicy(Context context) { + mContext = context; + } + + public int getMaxActionButtons() { + return mContext.getResources().getInteger(R.integer.max_action_buttons); + } + + public boolean showsOverflowMenuButton() { + return !ViewConfiguration.get(mContext).hasPermanentMenuKey(); + } + + public int getEmbeddedMenuWidthLimit() { + return mContext.getResources().getDisplayMetrics().widthPixels / 2; + } + + public boolean hasEmbeddedTabs() { + final int targetSdk = mContext.getApplicationInfo().targetSdkVersion; + if (targetSdk >= Build.VERSION_CODES.JELLY_BEAN) { + return mContext.getResources().getBoolean(R.bool.action_bar_embed_tabs); + } + + // The embedded tabs policy changed in Jellybean; give older apps the old policy + // so they get what they expect. + return mContext.getResources().getBoolean(R.bool.action_bar_embed_tabs_pre_jb); + } + + public int getTabContainerHeight() { + TypedArray a = mContext.obtainStyledAttributes(null, R.styleable.ActionBar, + com.android.internal.R.attr.actionBarStyle, 0); + int height = a.getLayoutDimension(R.styleable.ActionBar_height, 0); + Resources r = mContext.getResources(); + if (!hasEmbeddedTabs()) { + // Stacked tabs; limit the height + height = Math.min(height, + r.getDimensionPixelSize(R.dimen.action_bar_stacked_max_height)); + } + a.recycle(); + return height; + } + + public boolean enableHomeButtonByDefault() { + // Older apps get the home button interaction enabled by default. + // Newer apps need to enable it explicitly. + return mContext.getApplicationInfo().targetSdkVersion < + Build.VERSION_CODES.ICE_CREAM_SANDWICH; + } + + public int getStackedTabMaxWidth() { + return mContext.getResources().getDimensionPixelSize( + R.dimen.action_bar_stacked_tab_max_width); + } +} diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java index dca45a9..73324c0 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java @@ -16,6 +16,7 @@ package com.android.internal.view.menu; +import com.android.internal.view.ActionBarPolicy; import com.android.internal.view.menu.ActionMenuView.ActionMenuChildView; import android.content.Context; @@ -29,7 +30,6 @@ import android.view.MenuItem; import android.view.SoundEffectConstants; import android.view.View; import android.view.View.MeasureSpec; -import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.ImageButton; @@ -79,17 +79,18 @@ public class ActionMenuPresenter extends BaseMenuPresenter final Resources res = context.getResources(); + final ActionBarPolicy abp = ActionBarPolicy.get(context); if (!mReserveOverflowSet) { - mReserveOverflow = !ViewConfiguration.get(context).hasPermanentMenuKey(); + mReserveOverflow = abp.showsOverflowMenuButton(); } if (!mWidthLimitSet) { - mWidthLimit = res.getDisplayMetrics().widthPixels / 2; + mWidthLimit = abp.getEmbeddedMenuWidthLimit(); } // Measure for initial configuration if (!mMaxItemsSet) { - mMaxItems = res.getInteger(com.android.internal.R.integer.max_action_buttons); + mMaxItems = abp.getMaxActionButtons(); } int width = mWidthLimit; diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java index 06f5158..25a9c54 100644 --- a/core/java/com/android/internal/widget/AbsActionBarView.java +++ b/core/java/com/android/internal/widget/AbsActionBarView.java @@ -161,10 +161,12 @@ public abstract class AbsActionBarView extends ViewGroup { @Override public void setVisibility(int visibility) { - if (mVisibilityAnim != null) { - mVisibilityAnim.end(); + if (visibility != getVisibility()) { + if (mVisibilityAnim != null) { + mVisibilityAnim.end(); + } + super.setVisibility(visibility); } - super.setVisibility(visibility); } public boolean showOverflowMenu() { diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java index 1767d68..83ac896 100644 --- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java +++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java @@ -15,7 +15,7 @@ */ package com.android.internal.widget; -import com.android.internal.R; +import com.android.internal.view.ActionBarPolicy; import android.animation.Animator; import android.animation.ObjectAnimator; @@ -23,7 +23,6 @@ import android.animation.TimeInterpolator; import android.app.ActionBar; import android.content.Context; import android.content.res.Configuration; -import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.text.TextUtils.TruncateAt; import android.view.Gravity; @@ -55,6 +54,7 @@ public class ScrollingTabContainerView extends HorizontalScrollView private boolean mAllowCollapse; int mMaxTabWidth; + int mStackedTabMaxWidth; private int mContentHeight; private int mSelectedTabIndex; @@ -69,10 +69,9 @@ public class ScrollingTabContainerView extends HorizontalScrollView super(context); setHorizontalScrollBarEnabled(false); - TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.ActionBar, - com.android.internal.R.attr.actionBarStyle, 0); - setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0)); - a.recycle(); + ActionBarPolicy abp = ActionBarPolicy.get(context); + setContentHeight(abp.getTabContainerHeight()); + mStackedTabMaxWidth = abp.getStackedTabMaxWidth(); mTabLayout = createTabLayout(); addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, @@ -93,6 +92,7 @@ public class ScrollingTabContainerView extends HorizontalScrollView } else { mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2; } + mMaxTabWidth = Math.min(mMaxTabWidth, mStackedTabMaxWidth); } else { mMaxTabWidth = -1; } @@ -187,6 +187,7 @@ public class ScrollingTabContainerView extends HorizontalScrollView final LinearLayout tabLayout = new LinearLayout(getContext(), null, com.android.internal.R.attr.actionBarTabBarStyle); tabLayout.setMeasureWithLargestChildEnabled(true); + tabLayout.setGravity(Gravity.CENTER); tabLayout.setLayoutParams(new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT)); return tabLayout; @@ -205,12 +206,11 @@ public class ScrollingTabContainerView extends HorizontalScrollView protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); + ActionBarPolicy abp = ActionBarPolicy.get(getContext()); // Action bar can change size on configuration changes. // Reread the desired height from the theme-specified style. - TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.ActionBar, - com.android.internal.R.attr.actionBarStyle, 0); - setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0)); - a.recycle(); + setContentHeight(abp.getTabContainerHeight()); + mStackedTabMaxWidth = abp.getStackedTabMaxWidth(); } public void animateToVisibility(int visibility) { diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 724d9fb..1f2b1ae 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -31,20 +31,22 @@ int ifc_reset_connections(const char *ifname, int reset_mask); int dhcp_do_request(const char *ifname, const char *ipaddr, const char *gateway, - uint32_t *prefixLength, + uint32_t *prefixLength, const char *dns1, const char *dns2, const char *server, - uint32_t *lease); + uint32_t *lease, + const char *vendorInfo); int dhcp_do_request_renew(const char *ifname, const char *ipaddr, const char *gateway, - uint32_t *prefixLength, + uint32_t *prefixLength, const char *dns1, const char *dns2, const char *server, - uint32_t *lease); + uint32_t *lease, + const char *vendorInfo); int dhcp_stop(const char *ifname); int dhcp_release_lease(const char *ifname); @@ -68,6 +70,7 @@ static struct fieldIds { jfieldID dns2; jfieldID serverAddress; jfieldID leaseDuration; + jfieldID vendorInfo; } dhcpInfoInternalFieldIds; static jint android_net_utils_enableInterface(JNIEnv* env, jobject clazz, jstring ifname) @@ -116,16 +119,17 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr char dns2[PROPERTY_VALUE_MAX]; char server[PROPERTY_VALUE_MAX]; uint32_t lease; + char vendorInfo[PROPERTY_VALUE_MAX]; const char *nameStr = env->GetStringUTFChars(ifname, NULL); if (nameStr == NULL) return (jboolean)false; if (renew) { result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength, - dns1, dns2, server, &lease); + dns1, dns2, server, &lease, vendorInfo); } else { result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength, - dns1, dns2, server, &lease); + dns1, dns2, server, &lease, vendorInfo); } env->ReleaseStringUTFChars(ifname, nameStr); @@ -161,6 +165,7 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr env->SetObjectField(info, dhcpInfoInternalFieldIds.serverAddress, env->NewStringUTF(server)); env->SetIntField(info, dhcpInfoInternalFieldIds.leaseDuration, lease); + env->SetObjectField(info, dhcpInfoInternalFieldIds.vendorInfo, env->NewStringUTF(vendorInfo)); } return (jboolean)(result == 0); } @@ -230,6 +235,7 @@ int register_android_net_NetworkUtils(JNIEnv* env) dhcpInfoInternalFieldIds.dns2 = env->GetFieldID(dhcpInfoInternalClass, "dns2", "Ljava/lang/String;"); dhcpInfoInternalFieldIds.serverAddress = env->GetFieldID(dhcpInfoInternalClass, "serverAddress", "Ljava/lang/String;"); dhcpInfoInternalFieldIds.leaseDuration = env->GetFieldID(dhcpInfoInternalClass, "leaseDuration", "I"); + dhcpInfoInternalFieldIds.vendorInfo = env->GetFieldID(dhcpInfoInternalClass, "vendorInfo", "Ljava/lang/String;"); return AndroidRuntime::registerNativeMethods(env, NETUTILS_PKG_NAME, gNetworkUtilMethods, NELEM(gNetworkUtilMethods)); diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index b2714dd..15f56f3 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -70,7 +70,7 @@ <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"የደዋይ ID ወደ አልተከለከለም ነባሪዎች።ቀጥሎ ጥሪ፡ ተከልክሏል"</string> <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"የደዋይ ID ነባሪዎች ወደአልተከለከለም። ቀጥሎ ጥሪ፡አልተከለከለም"</string> <string name="serviceNotProvisioned" msgid="8614830180508686666">"አገልግሎት አልቀረበም።"</string> - <string name="CLIRPermanent" msgid="3377371145926835671">"የደዋይ መታወቂያ ቅንጅቶች መለወጥ አትችልም፡፡"</string> + <string name="CLIRPermanent" msgid="3377371145926835671">"የደዋይ መታወቂያ ቅንብሮች መለወጥ አትችልም፡፡"</string> <string name="RestrictedChangedTitle" msgid="5592189398956187498">"ክልክል ድረስተለውጧል"</string> <string name="RestrictedOnData" msgid="8653794784690065540">"የውሂብ አገልግሎት የታገደ ነው።"</string> <string name="RestrictedOnEmergency" msgid="6581163779072833665">"የአደጋ ጊዜአገልግሎት የታገደ ነው።"</string> @@ -375,7 +375,7 @@ <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"የንዑስ ክፈፍ ቋት አንብብ"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"የክፈፍ ቋት ይዘት ለማንበብ ለመተግበሪያው ይፈቅዳሉ።"</string> <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"የድምፅ ቅንብሮችን ለውጥ"</string> - <string name="permdesc_modifyAudioSettings" msgid="7343951185408396919">"የዓለም አቀፍ ኦዲዮ ቅንጅቶች እንደ ድምፅ እና ፈለግ ለመቀየር ለመተግበሪያው ይፈቅዳሉ ።"</string> + <string name="permdesc_modifyAudioSettings" msgid="7343951185408396919">"የዓለም አቀፍ ኦዲዮ ቅንብሮች እንደ ድምፅ እና ፈለግ ለመቀየር ለመተግበሪያው ይፈቅዳሉ ።"</string> <string name="permlab_recordAudio" msgid="3876049771427466323">"ኦዲዮ ቅዳ"</string> <string name="permdesc_recordAudio" msgid="2387462233976248635">"መተግበሪያ የድምፅ መዝገብ ዱካን ለመድረስ ይፈቅዳል።"</string> <string name="permlab_camera" msgid="3616391919559751192">"ፎቶዎች እና ቪዲዮዎች አንሳ"</string> @@ -445,7 +445,7 @@ <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"የልጣፍአዘጋጅ መጠን ፍንጮች"</string> <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"የስርዓቱን ልጥፍ መጠንለማዘጋጀት ለመተግበሪያው ይፈቅዳሉ፡፡"</string> <string name="permlab_masterClear" msgid="2315750423139697397">"ስርዓትን ወደ ፋብሪካ ነባሪዎች ዳግም አስጀምር"</string> - <string name="permdesc_masterClear" msgid="3665380492633910226">"ወደ ፋብሪካው ቅንጅቶች ሙሉ በሙሉ ስርዓቱን ዳግም ለማስጀመር ለመተግበሪያው ይፈቅዳሉ ፤ ሁሉንም ውሂብ፣ አወቃቀር፣ እና የተጫኑ መተግበሪያዎችን በማጥፈት፡፡"</string> + <string name="permdesc_masterClear" msgid="3665380492633910226">"ወደ ፋብሪካው ቅንብሮች ሙሉ በሙሉ ስርዓቱን ዳግም ለማስጀመር ለመተግበሪያው ይፈቅዳሉ ፤ ሁሉንም ውሂብ፣ አወቃቀር፣ እና የተጫኑ መተግበሪያዎችን በማጥፈት፡፡"</string> <string name="permlab_setTime" msgid="2021614829591775646">"ሰዓት ሙላ"</string> <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"መተግበሪያውን የጡባዊ ተኮን ሰዓት ለመለወጥ ይፈቅዳሉ።"</string> <string name="permdesc_setTime" product="default" msgid="1855702730738020">"መተግበሪያውን የስልኩን ሰዓት ለመለወጥ ይፈቅዳሉ።"</string> @@ -474,7 +474,7 @@ <string name="permlab_changeTetherState" msgid="5952584964373017960">"የተያያዘ ግንኙነት ለውጥ"</string> <string name="permdesc_changeTetherState" msgid="1524441344412319780">"መተግበሪያ የእውታረ መረቡን ግንኙነት ትይይዝ ሁኔታ ለመለወጥ ይፈቅዳል።"</string> <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"የዳራ ውሂብ አጠቃቀም ቅንብር ለውጥ"</string> - <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"የዳራ ውሂብ አጠቃቀም ቅንጅቶች ለመለወጥ ለመተግበሪያው ይፈቅዳሉ፡፡"</string> + <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"የዳራ ውሂብ አጠቃቀም ቅንብሮች ለመለወጥ ለመተግበሪያው ይፈቅዳሉ፡፡"</string> <string name="permlab_accessWifiState" msgid="8100926650211034400">"የWi-Fi ሁኔታ እይ"</string> <string name="permdesc_accessWifiState" msgid="7770452658226256831">"ስለWi-Fi ሁኔታ መረጃን ለማየት ለመተግበሪያው ይፈቅዳሉ፡፡"</string> <string name="permlab_changeWifiState" msgid="7280632711057112137">"የWi-Fi ሁኔታን ለውጥ"</string> @@ -924,7 +924,7 @@ <string name="capital_off" msgid="6815870386972805832">"ውጪ"</string> <string name="whichApplication" msgid="4533185947064773386">"... በመጠቀም ድርጊቱን አጠናቅ"</string> <string name="alwaysUse" msgid="4583018368000610438">"ለዕርምጃ ነባሪ ተጠቀም።"</string> - <string name="clearDefaultHintMsg" msgid="3252584689512077257">"ነባሪ አጽዳ በስርዓት ቅንጅቶች ውስጥ > Apps &gt፤ወርዷል፡፡"</string> + <string name="clearDefaultHintMsg" msgid="3252584689512077257">"ነባሪ አጽዳ በስርዓት ቅንብሮች ውስጥ > Apps &gt፤ወርዷል፡፡"</string> <string name="chooseActivity" msgid="7486876147751803333">"ድርጊት ምረጥ"</string> <string name="chooseUsbActivity" msgid="6894748416073583509">"ለUSB መሳሪያ መተግበሪያ ምረጥ"</string> <string name="noApplications" msgid="2991814273936504689">"ምንም ትግበራዎች ይህን ድርጊት ማከናወን አይችሉም።"</string> @@ -945,7 +945,7 @@ <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> በዋናነት የተነሳው።"</string> <string name="screen_compat_mode_scale" msgid="3202955667675944499">"የልኬት ለውጥ"</string> <string name="screen_compat_mode_show" msgid="4013878876486655892">"ሁልጊዜ አሳይ"</string> - <string name="screen_compat_mode_hint" msgid="1064524084543304459">"በስርዓት ቅንጅቶች ውስጥ ይሄንን ዳግም አንቃ> Apps &gt፤ወርዷል፡፡"</string> + <string name="screen_compat_mode_hint" msgid="1064524084543304459">"በስርዓት ቅንብሮች ውስጥ ይሄንን ዳግም አንቃ> Apps &gt፤ወርዷል፡፡"</string> <string name="smv_application" msgid="3307209192155442829">"መተግበሪያው <xliff:g id="APPLICATION">%1$s</xliff:g>( ሂደት<xliff:g id="PROCESS">%2$s</xliff:g>) በራስ ተነሳሺ StrictMode ደንብን ይተላለፋል።"</string> <string name="smv_process" msgid="5120397012047462446">"ሂደቱ <xliff:g id="PROCESS">%1$s</xliff:g> በራስ ተነሳሺ StrictMode ፖሊሲን ይተላለፋል።"</string> <string name="android_upgrading_title" msgid="1584192285441405746">"Android እያሻሻለ ነው..."</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index e57c157..bdd802d 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1012,9 +1012,9 @@ <string name="sms_control_yes" msgid="3663725993855816807">"Engedélyezés"</string> <string name="sms_control_no" msgid="625438561395534982">"Elutasítás"</string> <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"SMS küldése a rövid kódra?"</string> - <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Elküldi a prémium SMS-t?"</string> - <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"A(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> szöveges üzenetet szeretne küldeni a(z) <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> címre, ami egy SMS rövid kódja.<p>Az egyes rövid kódokra küldött üzenetek miatt mobilszámláján prémiumszolgáltatások lesznek kiszámlázva.</b><p>Engedélyezi, hogy az alkalmazás elküldje az üzenetet?"</string> - <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"A(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> szöveges üzenetet szeretne küldeni a(z) <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> címre, ami egy prémium SMS rövid kódja.<p>Az ide küldött üzenet miatt mobilszámláján prémiumszolgáltatások lesznek kiszámlázva.</b><p>Engedélyezi, hogy az alkalmazás elküldje az üzenetet?"</string> + <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Elküldi az emelt díjas SMS-t?"</string> + <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"A(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> szöveges üzenetet szeretne küldeni a(z) <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> címre, ami egy SMS rövid kódja.<p>Az egyes rövid kódokra küldött üzenetek miatt mobilszámláján emelt díjas szolgáltatások lesznek kiszámlázva.</b><p>Engedélyezi, hogy az alkalmazás elküldje az üzenetet?"</string> + <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"A(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> szöveges üzenetet szeretne küldeni a(z) <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> címre, ami egy emelt díjas SMS rövid kódja.<p>Az ide küldött üzenet miatt mobilszámláján emelt díjas szolgáltatások lesznek kiszámlázva.</b><p>Engedélyezi, hogy az alkalmazás elküldje az üzenetet?"</string> <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Üzenet küldése"</string> <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Nincs küldés"</string> <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Rosszindulatú alk. bejelentése"</string> diff --git a/core/res/res/values-port/bools.xml b/core/res/res/values-port/bools.xml new file mode 100644 index 0000000..fc62b69 --- /dev/null +++ b/core/res/res/values-port/bools.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <bool name="action_bar_embed_tabs">false</bool> +</resources> diff --git a/core/res/res/values-sw600dp/bools.xml b/core/res/res/values-sw600dp/bools.xml index 2097049..e74379c 100644 --- a/core/res/res/values-sw600dp/bools.xml +++ b/core/res/res/values-sw600dp/bools.xml @@ -17,6 +17,5 @@ <resources> <bool name="preferences_prefer_dual_pane">true</bool> <bool name="show_ongoing_ime_switcher">false</bool> - <bool name="action_bar_expanded_action_views_exclusive">false</bool> <bool name="target_honeycomb_needs_options_menu">false</bool> </resources> diff --git a/core/res/res/values-w480dp/bools.xml b/core/res/res/values-w480dp/bools.xml index 57a2939..3a463a6 100644 --- a/core/res/res/values-w480dp/bools.xml +++ b/core/res/res/values-w480dp/bools.xml @@ -17,6 +17,6 @@ */ --> <resources> - <bool name="action_bar_embed_tabs">true</bool> + <bool name="action_bar_embed_tabs_pre_jb">true</bool> <bool name="split_action_bar_is_narrow">false</bool> </resources> diff --git a/core/res/res/values-w720dp/bools.xml b/core/res/res/values-w720dp/bools.xml new file mode 100644 index 0000000..352c319 --- /dev/null +++ b/core/res/res/values-w720dp/bools.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <bool name="action_bar_expanded_action_views_exclusive">false</bool> +</resources> diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml index 87a98e2..f9762b1 100644 --- a/core/res/res/values/bools.xml +++ b/core/res/res/values/bools.xml @@ -15,7 +15,8 @@ --> <resources> - <bool name="action_bar_embed_tabs">false</bool> + <bool name="action_bar_embed_tabs">true</bool> + <bool name="action_bar_embed_tabs_pre_jb">false</bool> <bool name="split_action_bar_is_narrow">true</bool> <bool name="preferences_prefer_dual_pane">false</bool> <bool name="show_ongoing_ime_switcher">true</bool> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 0442be8..ef80160 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -213,4 +213,13 @@ <!-- Minimum width for an action button in the menu area of an action bar --> <dimen name="action_button_min_width">56dip</dimen> + + <!-- Maximum height for a stacked tab bar as part of an action bar --> + <dimen name="action_bar_stacked_max_height">48dp</dimen> + + <!-- Maximum width for a stacked action bar tab. This prevents + action bar tabs from becoming too wide on a wide screen when only + a few are present. --> + <dimen name="action_bar_stacked_tab_max_width">180dp</dimen> + </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index b564b97..03ba08c 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -234,6 +234,7 @@ <java-symbol type="attr" name="accessibilityFocusedDrawable"/> <java-symbol type="bool" name="action_bar_embed_tabs" /> + <java-symbol type="bool" name="action_bar_embed_tabs_pre_jb" /> <java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" /> <java-symbol type="bool" name="config_allowActionMenuItemTextWithIcon" /> <java-symbol type="bool" name="config_bluetooth_adapter_quick_switch" /> @@ -292,6 +293,8 @@ <java-symbol type="dimen" name="textview_error_popup_default_width" /> <java-symbol type="dimen" name="toast_y_offset" /> <java-symbol type="dimen" name="volume_panel_top" /> + <java-symbol type="dimen" name="action_bar_stacked_max_height" /> + <java-symbol type="dimen" name="action_bar_stacked_tab_max_width" /> <java-symbol type="string" name="addToDictionary" /> <java-symbol type="string" name="action_bar_home_description" /> diff --git a/docs/html/images/LivePocketGemsTitleCard.png b/docs/html/images/LivePocketGemsTitleCard.png Binary files differnew file mode 100644 index 0000000..0d70a56 --- /dev/null +++ b/docs/html/images/LivePocketGemsTitleCard.png diff --git a/docs/html/live/index.jd b/docs/html/live/index.jd new file mode 100644 index 0000000..70559e7 --- /dev/null +++ b/docs/html/live/index.jd @@ -0,0 +1,64 @@ +page.title=Live +@jd:body + +<div id="mainBodyFixed" style="padding-left:2em;"> + +<h1>Android Developers Live</h1> + +<p>Meet the developers behind successful apps and games on Android. Check back for upcoming +livecasts on YouTube and videos of past sessions or follow us on +<a href="https://plus.google.com/108967384991768947849/posts">+Android Developers</a> for updates.</p> + + <div id="interviewBlock" style="border-top:1px solid #ddd;margin-top:2em;padding-top:1em;clear:both;"> + + <div id="mainBodyLeft" class="videoPlayer"> + + <h3>Developer Interview: Pocket Gems</h3> + + <p>19 April 2012<br />2PM PST</p> + <p><span itemprop="description">Pocket Gems, a top game developer on Android, joins + <a href="https://plus.google.com/108967384991768947849/posts">+Android Developers</a> + to give a short talk on "Defragging Your Android Development." The talk highlights some + of the techniques they've used to ensure quality while distributing their apps to hundreds + of devices worldwide. </p> + + <p>After the talk, they'll take a few questions from developers in the hangout or from + developers joining on air via the moderator queue. </p> + + <div id="objectWrapper"> + <img width="560" height="315" src="{@docRoot}images/LivePocketGemsTitleCard.png" frameborder="0" allowfullscreen></iframe> + </div> + + </div><!-- end mainBodyLeft --> + + <div id="mainBodyRight" class="videoPlayer"> + + <div style="padding-left:1.5em;font-size:12px;"> + <div style="padding-bottom:1em;"><img itemprop="image" src="http://pocketgems.com/images/pocket-gems-logo-blue.png"></div> + + <h3 style="color:#000;font-size:12px;">About Pocket Gems</h3> + <p> + Web: <a style="text-decoration:none" href="http://www.pocketgems.com">www.pocketgems.com</a><br /> + Google+: <a style="text-decoration:none" href="https://plus.google.com/b/102436156807338888308/">+Pocket Gems</a><br /> + Twitter: <a style="text-decoration:none" href="https://twitter.com/#!/PocketGems">@PocketGems</a><br /> + </p> + + <h3 style="color:#000;font-size:12px;">Published on Google Play</h3> + <p style="line-height:1.5em;"> + <a style="text-decoration:none" href="https://play.google.com/store/apps/developer?id=Pocket+Gems">Apps by Pocket Gems</a> + </p> + + <h3 style="color:#000;font-size:12px;">Join</h3> + <p style="line-height:1.5em;"> + <a style="text-decoration:none" href="http://www.youtube.com/user/androiddevelopers">Watch live on YouTube</a><br /> + <a style="text-decoration:none" href="http://www.google.com/moderator/#15/e=1fd27e&t=1fd27e.40">Submit a question</a><br /> + <a style="text-decoration:none" href="https://www.google.com/calendar/ical/g2ilcr0iki4olp10aluid7gl70%40group.calendar.google.com/public/basic.ics">Add to calendar</a> (iCal) + </p> + + </li></ul> + +</div> + </div><!-- end mainBodyRight --> +</div><!-- interviewBlock --> + + </div><!-- end mainBodyFixed --> diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 34bf368..81e8028 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -530,7 +530,6 @@ public class AudioRecord * @throws IllegalStateException * @param syncEvent event that triggers the capture. * @see MediaSyncEvent - * @hide */ public void startRecording(MediaSyncEvent syncEvent) throws IllegalStateException { diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 2efacd8..258760f 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -280,6 +280,19 @@ final public class MediaCodec { */ public native final void flush(); + public final static class CryptoException extends RuntimeException { + public CryptoException(int errorCode, String detailMessage) { + super(detailMessage); + mErrorCode = errorCode; + } + + public int getErrorCode() { + return mErrorCode; + } + + private int mErrorCode; + } + /** After filling a range of the input buffer at the specified index * submit it to the component. * @@ -304,10 +317,13 @@ final public class MediaCodec { * @param presentationTimeUs The time at which this buffer should be rendered. * @param flags A bitmask of flags {@link #FLAG_SYNCFRAME}, * {@link #FLAG_CODECCONFIG} or {@link #FLAG_EOS}. + * @throws CryptoException if a crypto object has been specified in + * {@link #configure} */ public native final void queueInputBuffer( int index, - int offset, int size, long presentationTimeUs, int flags); + int offset, int size, long presentationTimeUs, int flags) + throws CryptoException; /** Metadata describing the structure of a (at least partially) encrypted * input sample. @@ -361,7 +377,7 @@ final public class MediaCodec { int offset, CryptoInfo info, long presentationTimeUs, - int flags); + int flags) throws CryptoException; /** Returns the index of an input buffer to be filled with valid data * or -1 if no such buffer is currently available. diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 545752c..fae7d0b 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1577,26 +1577,39 @@ public class MediaPlayer /** * Returns an array of track information. + * If it is called in an invalid state, IllegalStateException will be thrown. * - * @return Array of track info. null if an error occured. + * @return Array of track info. The total number of tracks is the array length. + * Must be called again if an external source has been added after any of the + * addExternalSource methods are called. * {@hide} */ - // FIXME: It returns timed text tracks' information for now. Other types of tracks will be - // supported in future. public TrackInfo[] getTrackInfo() { Parcel request = Parcel.obtain(); Parcel reply = Parcel.obtain(); request.writeInterfaceToken(IMEDIA_PLAYER); request.writeInt(INVOKE_ID_GET_TRACK_INFO); - invoke(request, reply); + int status = invoke(request, reply); + if (status != 0) { + throw new IllegalStateException(); + } TrackInfo trackInfo[] = reply.createTypedArray(TrackInfo.CREATOR); return trackInfo; } + /* Do not change these values without updating their counterparts + * in include/media/stagefright/MediaDefs.h and media/libstagefright/MediaDefs.cpp! + */ + /** + * MIME type for SubRip (SRT) container. Used in addExternalSource APIs. + * {@hide} + */ + public static final String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; + /* * A helper function to check if the mime type is supported by media framework. */ - private boolean availableMimeTypeForExternalSource(String mimeType) { + private static boolean availableMimeTypeForExternalSource(String mimeType) { if (mimeType == MEDIA_MIMETYPE_TEXT_SUBRIP) { return true; } @@ -1614,10 +1627,11 @@ public class MediaPlayer * additional tracks become available after this method call. * * @param path The file path of external source file. + * @param mimeType The mime type of the file. Must be one of the mime types listed above. + * @throws IOException if the file cannot be accessed or is corrupted. + * @throws IllegalArgumentException if the mimeType is not supported. * {@hide} */ - // FIXME: define error codes and throws exceptions according to the error codes. - // (IllegalStateException, IOException). public void addExternalSource(String path, String mimeType) throws IOException, IllegalArgumentException { if (!availableMimeTypeForExternalSource(mimeType)) { @@ -1647,10 +1661,11 @@ public class MediaPlayer * * @param context the Context to use when resolving the Uri * @param uri the Content URI of the data you want to play + * @param mimeType The mime type of the file. Must be one of the mime types listed above. + * @throws IOException if the file cannot be accessed or is corrupted. + * @throws IllegalArgumentException if the mimeType is not supported. * {@hide} */ - // FIXME: define error codes and throws exceptions according to the error codes. - // (IllegalStateException, IOException). public void addExternalSource(Context context, Uri uri, String mimeType) throws IOException, IllegalArgumentException { String scheme = uri.getScheme(); @@ -1677,15 +1692,6 @@ public class MediaPlayer } } - /* Do not change these values without updating their counterparts - * in include/media/stagefright/MediaDefs.h and media/libstagefright/MediaDefs.cpp! - */ - /** - * MIME type for SubRip (SRT) container. Used in {@link #addExternalSource()} APIs. - * {@hide} - */ - public static final String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; - /** * Adds an external source file (FileDescriptor). * It is the caller's responsibility to close the file descriptor. @@ -1697,14 +1703,10 @@ public class MediaPlayer * additional tracks become available after this method call. * * @param fd the FileDescriptor for the file you want to play - * @param mimeType A MIME type for the content. It can be null. - * <ul> - * <li>{@link #MEDIA_MIMETYPE_TEXT_SUBRIP} - * </ul> + * @param mimeType The mime type of the file. Must be one of the mime types listed above. + * @throws IllegalArgumentException if the mimeType is not supported. * {@hide} */ - // FIXME: define error codes and throws exceptions according to the error codes. - // (IllegalStateException, IOException). public void addExternalSource(FileDescriptor fd, String mimeType) throws IllegalArgumentException { // intentionally less than LONG_MAX @@ -1724,11 +1726,10 @@ public class MediaPlayer * @param fd the FileDescriptor for the file you want to play * @param offset the offset into the file where the data to be played starts, in bytes * @param length the length in bytes of the data to be played - * @param mimeType A MIME type for the content. It can be null. + * @param mimeType The mime type of the file. Must be one of the mime types listed above. + * @throws IllegalArgumentException if the mimeType is not supported. * {@hide} */ - // FIXME: define error codes and throws exceptions according to the error codes. - // (IllegalStateException, IOException). public void addExternalSource(FileDescriptor fd, long offset, long length, String mimeType) throws IllegalArgumentException { if (!availableMimeTypeForExternalSource(mimeType)) { @@ -1749,8 +1750,8 @@ public class MediaPlayer /** * Selects a track. * <p> - * If a MediaPlayer is in invalid state, it throws exception. - * If a MediaPlayer is in Started state, the selected track will be presented immediately. + * If a MediaPlayer is in invalid state, it throws an IllegalStateException exception. + * If a MediaPlayer is in <em>Started</em> state, the selected track is presented immediately. * If a MediaPlayer is not in Started state, it just marks the track to be played. * </p> * <p> @@ -1758,38 +1759,58 @@ public class MediaPlayer * Audio, Timed Text), the most recent one will be chosen. * </p> * <p> - * The first audio and video tracks will be selected by default, even though this function is not - * called. However, no timed text track will be selected until this function is called. + * The first audio and video tracks are selected by default if available, even though + * this method is not called. However, no timed text track will be selected until + * this function is called. + * </p> + * <p> + * Currently, only timed text tracks or audio tracks can be selected via this method. + * In addition, the support for selecting an audio track at runtime is pretty limited + * in that an audio track can only be selected in the <em>Prepared</em> state. * </p> + * @param index the index of the track to be selected. The valid range of the index + * is 0..total number of track - 1. The total number of tracks as well as the type of + * each individual track can be found by calling {@link #getTrackInfo()} method. + * @see android.media.MediaPlayer.getTrackInfo * {@hide} */ - // FIXME: define error codes and throws exceptions according to the error codes. - // (IllegalStateException, IOException, IllegalArgumentException). public void selectTrack(int index) { - Parcel request = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - request.writeInterfaceToken(IMEDIA_PLAYER); - request.writeInt(INVOKE_ID_SELECT_TRACK); - request.writeInt(index); - invoke(request, reply); + selectOrUnselectTrack(index, true /* select */); } /** * Unselect a track. - * If the track identified by index has not been selected before, it throws an exception. + * <p> + * Currently, the track must be a timed text track and no audio or video tracks can be + * unselected. If the timed text track identified by index has not been + * selected before, it throws an exception. + * </p> + * @param index the index of the track to be unselected. The valid range of the index + * is 0..total number of tracks - 1. The total number of tracks as well as the type of + * each individual track can be found by calling {@link #getTrackInfo()} method. + * + * @see android.media.MediaPlayer.getTrackInfo * {@hide} */ - // FIXME: define error codes and throws exceptions according to the error codes. - // (IllegalStateException, IOException, IllegalArgumentException). public void unselectTrack(int index) { + selectOrUnselectTrack(index, false /* select */); + } + + private void selectOrUnselectTrack(int index, boolean select) { Parcel request = Parcel.obtain(); Parcel reply = Parcel.obtain(); request.writeInterfaceToken(IMEDIA_PLAYER); - request.writeInt(INVOKE_ID_UNSELECT_TRACK); + request.writeInt(select? INVOKE_ID_SELECT_TRACK: INVOKE_ID_UNSELECT_TRACK); request.writeInt(index); - invoke(request, reply); + int status = invoke(request, reply); + if (status != 0) { + String msg = select? "selectTrack ": "unselectTrack "; + msg += "failed for track index: " + index; + throw new RuntimeException(msg); + } } + /** * @param reply Parcel with audio/video duration info for battery tracking usage diff --git a/media/java/android/media/MediaSyncEvent.java b/media/java/android/media/MediaSyncEvent.java index d2a0735..31af6b5 100644 --- a/media/java/android/media/MediaSyncEvent.java +++ b/media/java/android/media/MediaSyncEvent.java @@ -23,7 +23,6 @@ package android.media; * only when the playback on a particular audio session is complete. * The audio session ID is retrieved from a player (e.g {@link MediaPlayer}, {@link AudioTrack} or * {@link ToneGenerator}) by use of the getAudioSessionId() method. - * @hide */ public class MediaSyncEvent { @@ -49,7 +48,7 @@ public class MediaSyncEvent { * <p>The type specifies which kind of event is monitored. * For instance, event {@link #SYNC_EVENT_PRESENTATION_COMPLETE} corresponds to the audio being * presented to the user on a particular audio session. - * @param type the synchronization event type. + * @param eventType the synchronization event type. * @return the MediaSyncEvent created. * @throws java.lang.IllegalArgumentException */ diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java index 4907a13..5592105 100644 --- a/media/java/android/media/ToneGenerator.java +++ b/media/java/android/media/ToneGenerator.java @@ -880,7 +880,6 @@ public class ToneGenerator * * @return the ID of the audio session this ToneGenerator belongs to or 0 if an error * occured. - * @hide */ public native final int getAudioSessionId(); diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java index 47c0d57..9197ed8 100755 --- a/media/java/android/media/audiofx/Visualizer.java +++ b/media/java/android/media/audiofx/Visualizer.java @@ -83,13 +83,11 @@ public class Visualizer { // to keep in sync with system/media/audio_effects/include/audio_effects/effect_visualizer.h /** - * @hide * Defines a capture mode where amplification is applied based on the content of the captured * data. This is the default Visualizer mode, and is suitable for music visualization. */ public static final int SCALING_MODE_NORMALIZED = 0; /** - * @hide * Defines a capture mode where the playback volume will affect (scale) the range of the * captured data. A low playback volume will lead to low sample and fft values, and vice-versa. */ @@ -316,7 +314,6 @@ public class Visualizer { } /** - * @hide * Set the type of scaling applied on the captured visualization data. * @param mode see {@link #SCALING_MODE_NORMALIZED} * and {@link #SCALING_MODE_AS_PLAYED} @@ -336,7 +333,6 @@ public class Visualizer { } /** - * @hide * Returns the current scaling mode on the captured visualization data. * @return the scaling mode, see {@link #SCALING_MODE_NORMALIZED} * and {@link #SCALING_MODE_AS_PLAYED}. diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index a120a2f..8009fb5 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -36,6 +36,7 @@ #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/ALooper.h> #include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/foundation/AString.h> #include <media/stagefright/MediaErrors.h> namespace android { @@ -129,8 +130,10 @@ status_t JMediaCodec::flush() { status_t JMediaCodec::queueInputBuffer( size_t index, - size_t offset, size_t size, int64_t timeUs, uint32_t flags) { - return mCodec->queueInputBuffer(index, offset, size, timeUs, flags); + size_t offset, size_t size, int64_t timeUs, uint32_t flags, + AString *errorDetailMsg) { + return mCodec->queueInputBuffer( + index, offset, size, timeUs, flags, errorDetailMsg); } status_t JMediaCodec::queueSecureInputBuffer( @@ -142,10 +145,11 @@ status_t JMediaCodec::queueSecureInputBuffer( const uint8_t iv[16], CryptoPlugin::Mode mode, int64_t presentationTimeUs, - uint32_t flags) { + uint32_t flags, + AString *errorDetailMsg) { return mCodec->queueSecureInputBuffer( index, offset, subSamples, numSubSamples, key, iv, mode, - presentationTimeUs, flags); + presentationTimeUs, flags, errorDetailMsg); } status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) { @@ -251,7 +255,31 @@ static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) { setMediaCodec(env, thiz, NULL); } -static jint throwExceptionAsNecessary(JNIEnv *env, status_t err) { +static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) { + jclass clazz = env->FindClass("android/media/MediaCodec$CryptoException"); + CHECK(clazz != NULL); + + jmethodID constructID = + env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;)V"); + CHECK(constructID != NULL); + + jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error"); + + jthrowable exception = + (jthrowable)env->NewObject(clazz, constructID, err, msgObj); + + env->Throw(exception); +} + +static jint throwExceptionAsNecessary( + JNIEnv *env, status_t err, const char *msg = NULL) { + if (err >= ERROR_DRM_WV_VENDOR_MIN && err <= ERROR_DRM_WV_VENDOR_MAX) { + // We'll throw our custom MediaCodec.CryptoException + + throwCryptoException(env, err, msg); + return 0; + } + switch (err) { case OK: return 0; @@ -383,10 +411,13 @@ static void android_media_MediaCodec_queueInputBuffer( return; } + AString errorDetailMsg; + status_t err = codec->queueInputBuffer( - index, offset, size, timestampUs, flags); + index, offset, size, timestampUs, flags, &errorDetailMsg); - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary( + env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); } static void android_media_MediaCodec_queueSecureInputBuffer( @@ -497,13 +528,17 @@ static void android_media_MediaCodec_queueSecureInputBuffer( } } + AString errorDetailMsg; + if (err == OK) { err = codec->queueSecureInputBuffer( index, offset, subSamples, numSubSamples, (const uint8_t *)key, (const uint8_t *)iv, (CryptoPlugin::Mode)mode, - timestampUs, flags); + timestampUs, + flags, + &errorDetailMsg); } if (iv != NULL) { @@ -519,7 +554,8 @@ static void android_media_MediaCodec_queueSecureInputBuffer( delete[] subSamples; subSamples = NULL; - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary( + env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); } static jint android_media_MediaCodec_dequeueInputBuffer( diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h index 570c33b..e2688be 100644 --- a/media/jni/android_media_MediaCodec.h +++ b/media/jni/android_media_MediaCodec.h @@ -28,6 +28,7 @@ namespace android { struct ALooper; struct AMessage; +struct AString; struct ICrypto; struct ISurfaceTexture; struct MediaCodec; @@ -52,7 +53,8 @@ struct JMediaCodec : public RefBase { status_t queueInputBuffer( size_t index, - size_t offset, size_t size, int64_t timeUs, uint32_t flags); + size_t offset, size_t size, int64_t timeUs, uint32_t flags, + AString *errorDetailMsg); status_t queueSecureInputBuffer( size_t index, @@ -63,7 +65,8 @@ struct JMediaCodec : public RefBase { const uint8_t iv[16], CryptoPlugin::Mode mode, int64_t presentationTimeUs, - uint32_t flags); + uint32_t flags, + AString *errorDetailMsg); status_t dequeueInputBuffer(size_t *index, int64_t timeoutUs); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java index b0bf654..abf85d7 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java @@ -188,6 +188,37 @@ public class MediaVisualizerTest extends ActivityInstrumentationTestCase2<MediaF assertTrue(msg, result); } + //Test case 1.2: check scaling mode + @LargeTest + public void test1_2ScalingMode() throws Exception { + boolean result = false; + String msg = "test1_2ScalingMode()"; + getVisualizer(0); + try { + int res = mVisualizer.setScalingMode(Visualizer.SCALING_MODE_AS_PLAYED); + assertEquals(msg + ": setting SCALING_MODE_AS_PLAYED failed", + res, Visualizer.SUCCESS); + int mode = mVisualizer.getScalingMode(); + assertEquals(msg + ": setting SCALING_MODE_AS_PLAYED didn't stick", + mode, Visualizer.SCALING_MODE_AS_PLAYED); + + res = mVisualizer.setScalingMode(Visualizer.SCALING_MODE_NORMALIZED); + assertEquals(msg + ": setting SCALING_MODE_NORMALIZED failed", + res, Visualizer.SUCCESS); + mode = mVisualizer.getScalingMode(); + assertEquals(msg + ": setting SCALING_MODE_NORMALIZED didn't stick", + mode, Visualizer.SCALING_MODE_NORMALIZED); + + result = true; + } catch (IllegalStateException e) { + msg = msg.concat("IllegalStateException"); + loge(msg, "set/get parameter() called in wrong state: " + e); + } finally { + releaseVisualizer(); + } + assertTrue(msg, result); + } + //----------------------------------------------------------------- // 2 - check capture //---------------------------------- @@ -403,6 +434,91 @@ public class MediaVisualizerTest extends ActivityInstrumentationTestCase2<MediaF assertTrue(msg, result); } + //Test case 2.2: test capture in polling mode with volume scaling + @LargeTest + public void test2_2PollingCaptureVolumeScaling() throws Exception { + // test that when playing a sound, the energy measured with Visualizer in + // SCALING_MODE_AS_PLAYED mode decreases when lowering the volume + boolean result = false; + String msg = "test2_2PollingCaptureVolumeScaling()"; + AudioEffect vc = null; + MediaPlayer mp = null; + AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); + int ringerMode = am.getRingerMode(); + am.setRingerMode(AudioManager.RINGER_MODE_NORMAL); + final int volMax = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC); + am.setStreamVolume(AudioManager.STREAM_MUSIC, volMax, 0); + + try { + // test setup not related to tested functionality: + // creating a volume controller on output mix ensures that ro.audio.silent mutes + // audio after the effects and not before + vc = new AudioEffect( + AudioEffect.EFFECT_TYPE_NULL, + VOLUME_EFFECT_UUID, + 0, + 0); + vc.setEnabled(true); + + mp = new MediaPlayer(); + mp.setDataSource(MediaNames.SINE_200_1000); + mp.setAudioStreamType(AudioManager.STREAM_MUSIC); + getVisualizer(mp.getAudioSessionId()); + + // verify we successfully set the Visualizer in SCALING_MODE_AS_PLAYED mode + mVisualizer.setScalingMode(Visualizer.SCALING_MODE_AS_PLAYED); + assertTrue(msg + " get volume scaling doesn't return SCALING_MODE_AS_PLAYED", + mVisualizer.getScalingMode() == Visualizer.SCALING_MODE_AS_PLAYED); + mVisualizer.setEnabled(true); + mp.prepare(); + mp.start(); + Thread.sleep(500); + + // check capture on sound with music volume at max + byte[] data = new byte[mVisualizer.getCaptureSize()]; + mVisualizer.getWaveForm(data); + int energyAtVolMax = computeEnergy(data, true); + assertTrue(msg +": getWaveForm reads insufficient level", + energyAtVolMax > 0); + log(msg, " engergy at max volume = "+energyAtVolMax); + + // check capture on sound with music volume lowered from max + am.setStreamVolume(AudioManager.STREAM_MUSIC, (volMax * 2) / 3, 0); + Thread.sleep(500); + mVisualizer.getWaveForm(data); + int energyAtLowerVol = computeEnergy(data, true); + assertTrue(msg +": getWaveForm at lower volume reads insufficient level", + energyAtLowerVol > 0); + log(msg, "energy at lower volume = "+energyAtLowerVol); + assertTrue(msg +": getWaveForm didn't report lower energy when volume decreases", + energyAtVolMax > energyAtLowerVol); + + result = true; + } catch (IllegalArgumentException e) { + msg = msg.concat(": IllegalArgumentException"); + loge(msg, " hit exception " + e); + } catch (UnsupportedOperationException e) { + msg = msg.concat(": UnsupportedOperationException"); + loge(msg, " hit exception " + e); + } catch (IllegalStateException e) { + msg = msg.concat("IllegalStateException"); + loge(msg, " hit exception " + e); + } catch (InterruptedException e) { + loge(msg, " sleep() interrupted"); + } + finally { + releaseVisualizer(); + if (mp != null) { + mp.release(); + } + if (vc != null) { + vc.release(); + } + am.setRingerMode(ringerMode); + } + assertTrue(msg, result); + } + //----------------------------------------------------------------- // private methods //---------------------------------- diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 1654eca..d54439e 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Ligging deur GPS gestel"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Verwyder alle kennisgewings."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktiveer sluimerskerm"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 42eef13..0540052 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -118,7 +118,7 @@ <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ብሉቱዝ ማያያዝ።"</string> <string name="accessibility_airplane_mode" msgid="834748999790763092">"የአውሮፕላን ሁነታ።"</string> <string name="accessibility_battery_level" msgid="7451474187113371965">"የባትሪ <xliff:g id="NUMBER">%d</xliff:g> መቶኛ።"</string> - <string name="accessibility_settings_button" msgid="799583911231893380">"የስርዓት ቅንጅቶች"</string> + <string name="accessibility_settings_button" msgid="799583911231893380">"የስርዓት ቅንብሮች"</string> <string name="accessibility_notifications_button" msgid="4498000369779421892">"ማሳወቂያዎች"</string> <string name="accessibility_remove_notification" msgid="3603099514902182350">"ማሳወቂያ አጥራ"</string> <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS ነቅቷል።"</string> @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"በ GPS የተዘጋጀ ሥፍራ"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"ሁሉንም ማሳወቂያዎች አጽዳ"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">" ገፁማያ ማቆያ አንቃ"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 9d6051e..7f1b816 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"تم تعيين الموقع بواسطة GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"محو جميع الإشعارات."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"تنشيط شاشة التوقف"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 433c124..8ce52db 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Месца задана праз GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Выдалiць усе апавяшчэннi."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Актывацыя экраннай застаўкі"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 429f246..b78dbc9 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Местоположението е зададено от GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Изчистване на всички известия."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Активиране на скрийнсейвъра"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 427abce..e5f8776 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"S\'ha establert la ubicació per GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Esborra totes les notificacions."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Activa el protector de pantalla"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 9c9674a..f5a12e4 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Poloha nastavena pomocí systému GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Vymazat všechna oznámení."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktivovat spořič obrazovky"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 6c614cd..62f69ff 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Placeringen er angivet ved hjælp af GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle meddelelser."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktiver pauseskærm"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index e3d82b1..3b06f06 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Standort durch GPS festgelegt"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Alle Benachrichtigungen löschen"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Bildschirmschoner aktivieren"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 5511b1a..1850182 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Ρύθμιση τοποθεσίας με GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Εκκαθάριση όλων των ειδοποιήσεων."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Ενεργοποίηση προφύλαξης οθόνης"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index b20a5f3..7061148 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Location set by GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Clear all notifications."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Activate screen saver"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 96c8c23..7e1fe16 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"La ubicación se estableció por GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Eliminar todas las notificaciones"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Activar el protector de pantalla"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 0b3e4e4..10dbf0d 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Ubicación definida por GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Borrar todas las notificaciones"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Activar salvapantallas"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 055e3ee..8ebd2a5 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS-i määratud asukoht"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Kustuta kõik teatised."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktiveeri ekraanisäästja"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index df25d5e..736d164 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"مکان تنظیم شده توسط GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"پاک کردن تمام اعلانها"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"فعال کردن محافظ صفحه نمایش"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 370d234..698e59c 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Sijainti määritetty GPS:n avulla"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Tyhjennä kaikki ilmoitukset."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Ota näytönsäästäjä käyttöön"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index c7f307c..5c5658d 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Position définie par GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Supprimer toutes les notifications"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Activer l\'économiseur d\'écran"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 9805f90..2b927d7 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारा सेट किया गया स्थान"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"सभी सूचनाएं साफ़ करें."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"स्क्रीन सेवर सक्रिय करें"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 2226aa8..5cd66d3 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokaciju utvrdio GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Brisanje svih obavijesti."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktivirajte čuvar zaslona"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 87a9d45..65a04b8 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"A GPS beállította a helyet"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Minden értesítés törlése"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Képernyővédő aktiválása"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index f246132..3611da2 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi yang disetel oleh GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Menghapus semua pemberitahuan."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktifkan tirai layar"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index a725377..c2c7856 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Posizione stabilita dal GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Cancella tutte le notifiche."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Attiva screensaver"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 03fba7e..17f5a36 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"מיקום מוגדר על ידי GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"נקה את כל ההתראות."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"הפעלת שומר מסך"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 4818ca9..203fe9c 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"GPSにより現在地が設定されました"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"通知をすべて消去。"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"スクリーンセーバーを有効にする"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 3321912..5350cd1 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS에서 위치 설정"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"모든 알림 지우기"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"스크린 세이버 활성화"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 831fa41..a30dd5a 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS nustatyta vieta"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Išvalyti visus pranešimus."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktyvinti ekrano užsklandą"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 158c850..0461ccd 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS iestatītā atrašanās vieta"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Notīrīt visus paziņojumus"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktivizēt ekrānsaudzētāju"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 899a204..dc5128a 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi ditetapkan oleh GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Padamkan semua pemberitahuan."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktifkan gambar skrin"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index c7b272a..39b622e 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Posisjon angitt av GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Fjern alle varslinger."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktiver skjermbeskytter"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index e05e2c9..444b05b 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Locatie bepaald met GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Alle meldingen wissen."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Schermbeveiliging inschakelen"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 0618eb5..d44efbe 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokalizacja ustawiona według GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Usuń wszystkie powiadomienia."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Włącz wygaszacz ekranu."</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 6a278ba..876eb799 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Localização definida por GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Ativar proteção de ecrã"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 23a2ba5..500ee2b 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Local definido por GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Ativar proteção de tela"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml index 3062d48..917306a 100644 --- a/packages/SystemUI/res/values-rm/strings.xml +++ b/packages/SystemUI/res/values-rm/strings.xml @@ -248,4 +248,6 @@ <skip /> <!-- no translation found for dreams_dock_launcher (3541196417659166245) --> <skip /> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index b778e4d..0e7509c 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Locaţie setată prin GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Ştergeţi toate notificările."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Activaţi screensaverul"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 3753309..23eb1d2 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Местоположение установлено с помощью GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Удалить все уведомления"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Активация заставки экрана"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 599f99c..a729cce 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Poloha nastavená pomocou GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Vymazať všetky upozornenia."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktivovať šetrič obrazovky"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index fb229e2..6da01c7 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokacija nastavljena z GPS-om"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Izbriši vsa obvestila."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Vklop ohranjevalnika zaslona"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index fb7c21a..3586b84 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Локацију је подесио GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Обриши сва обавештења."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Активирање чувара екрана"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 8eaa126..ed73106 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Platsen har identifierats av GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Ta bort alla meddelanden."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktivera skärmsläckare"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 19bd4ab..16ccca3 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -137,4 +137,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Mahali pamewekwa na GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Futa arifa zote."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Amilisha hifadhi ya skrini"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 82c5dd7..0e3344e 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"ตำแหน่งที่กำหนดโดย GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"ล้างการแจ้งเตือนทั้งหมด"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"เปิดโปรแกรมรักษาหน้าจอ"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 2054121..7b294ac 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasyong itinatakda ng GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"I-clear ang lahat ng notification."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"I-activate ang screen saver"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index ca422f7..f0da20e 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Konum GPS ile belirlendi"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Tüm bildirimleri temizle"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Ekran koruyucuyu etkinleştir"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 8a13400..c76798c 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Місцезнаходження встановлено за допомогою GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Очистити всі сповіщення."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Активувати заставку"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 05ab87c..35ac681 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Vị trí đặt bởi GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Xóa tất cả thông báo."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Kích hoạt trình bảo vệ màn hình"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index c862d74..996119c 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"已通过 GPS 确定位置"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"激活屏幕保护程序"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 399890b..d075352 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -141,4 +141,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS 已定位"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"啟用螢幕保護程式"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 91f6566..9c02a27 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -139,4 +139,6 @@ <string name="gps_notification_found_text" msgid="4619274244146446464">"Indawo ihlelwe i-GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Susa zonke izaziso."</string> <string name="dreams_dock_launcher" msgid="3541196417659166245">"Yenza ukuthi iskrini seyiva sisebenze"</string> + <!-- no translation found for status_bar_notification_inspect_item_title (1163547729015390250) --> + <skip /> </resources> diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index 326dc32..6ec020c 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -1465,6 +1465,8 @@ void EventHub::dump(String8& dump) { device->keyMap.keyCharacterMapFile.string()); dump.appendFormat(INDENT3 "ConfigurationFile: %s\n", device->configurationFile.string()); + dump.appendFormat(INDENT3 "HaveKeyboardLayoutOverlay: %s\n", + toString(device->overlayKeyMap != NULL)); } } // release lock } diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 95e56bf..4cc3d44 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -963,10 +963,12 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config } if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { - sp<KeyCharacterMap> keyboardLayout = - mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier.descriptor); - if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { - bumpGeneration(); + if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { + sp<KeyCharacterMap> keyboardLayout = + mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier.descriptor); + if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { + bumpGeneration(); + } } } diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java index b943c09..0ed5189 100644 --- a/services/java/com/android/server/DeviceStorageMonitorService.java +++ b/services/java/com/android/server/DeviceStorageMonitorService.java @@ -26,6 +26,7 @@ import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageManager; import android.os.Binder; import android.os.Environment; +import android.os.FileObserver; import android.os.Handler; import android.os.Message; import android.os.Process; @@ -91,6 +92,7 @@ public class DeviceStorageMonitorService extends Binder { private Intent mStorageFullIntent; private Intent mStorageNotFullIntent; private CachePackageDataObserver mClearCacheObserver; + private final CacheFileDeletedObserver mCacheFileDeletedObserver; private static final int _TRUE = 1; private static final int _FALSE = 0; private long mMemLowThreshold; @@ -324,6 +326,9 @@ public class DeviceStorageMonitorService extends Binder { mMemLowThreshold = getMemThreshold(); mMemFullThreshold = getMemFullThreshold(); checkMemory(true); + + mCacheFileDeletedObserver = new CacheFileDeletedObserver(); + mCacheFileDeletedObserver.startWatching(); } @@ -419,4 +424,15 @@ public class DeviceStorageMonitorService extends Binder { public boolean isMemoryLow() { return mLowMemFlag; } + + public static class CacheFileDeletedObserver extends FileObserver { + public CacheFileDeletedObserver() { + super(Environment.getDownloadCacheDirectory().getAbsolutePath(), FileObserver.DELETE); + } + + @Override + public void onEvent(int event, String path) { + EventLogTags.writeCacheFileDeleted(path); + } + } } diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags index 0bcec2e..249513f 100644 --- a/services/java/com/android/server/EventLogTags.logtags +++ b/services/java/com/android/server/EventLogTags.logtags @@ -36,7 +36,7 @@ option java_package com.android.server # --------------------------- -# DeviceStorageMonitoryService.java +# DeviceStorageMonitorService.java # --------------------------- # The disk space free on the /data partition, in bytes 2744 free_storage_changed (data|2|2) @@ -44,6 +44,8 @@ option java_package com.android.server 2745 low_storage (data|2|2) # disk space free on the /data, /system, and /cache partitions in bytes 2746 free_storage_left (data|2|2),(system|2|2),(cache|2|2) +# file on cache partition was deleted +2748 cache_file_deleted (path|3) # --------------------------- diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index 8014e27..f33bf8b 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -17,6 +17,8 @@ package com.android.server; import android.content.Context; +import android.content.ContentResolver; +import android.content.Intent; import android.content.pm.PackageManager; import android.net.nsd.DnsSdServiceInfo; import android.net.nsd.DnsSdTxtRecord; @@ -28,6 +30,7 @@ import android.os.HandlerThread; import android.os.Message; import android.os.Messenger; import android.os.IBinder; +import android.provider.Settings; import android.util.Slog; import java.io.FileDescriptor; @@ -41,6 +44,9 @@ import java.util.concurrent.CountDownLatch; import com.android.internal.app.IBatteryStats; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.AsyncChannel; +import com.android.internal.util.Protocol; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; import com.android.server.am.BatteryStatsService; import com.android.server.NativeDaemonConnector.Command; import com.android.internal.R; @@ -58,6 +64,8 @@ public class NsdService extends INsdManager.Stub { private static final boolean DBG = true; private Context mContext; + private ContentResolver mContentResolver; + private NsdStateMachine mNsdStateMachine; /** * Clients receiving asynchronous messages @@ -69,189 +77,342 @@ public class NsdService extends INsdManager.Stub { private int INVALID_ID = 0; private int mUniqueId = 1; - /** - * Handles client(app) connections - */ - private class AsyncServiceHandler extends Handler { + private static final int BASE = Protocol.BASE_NSD_MANAGER; + private static final int CMD_TO_STRING_COUNT = NsdManager.STOP_RESOLVE - BASE + 1; + private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT]; + + static { + sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER"; + sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER"; + sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER"; + sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER"; + sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE"; + sCmdToString[NsdManager.STOP_RESOLVE - BASE] = "STOP-RESOLVE"; + } - AsyncServiceHandler(android.os.Looper looper) { - super(looper); + private static String cmdToString(int cmd) { + cmd -= BASE; + if ((cmd >= 0) && (cmd < sCmdToString.length)) { + return sCmdToString[cmd]; + } else { + return null; } + } + + private class NsdStateMachine extends StateMachine { + + private DefaultState mDefaultState = new DefaultState(); + private DisabledState mDisabledState = new DisabledState(); + private EnabledState mEnabledState = new EnabledState(); @Override - public void handleMessage(Message msg) { - ClientInfo clientInfo; - DnsSdServiceInfo servInfo; - switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - AsyncChannel c = (AsyncChannel) msg.obj; - if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); - c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED); - ClientInfo cInfo = new ClientInfo(c, msg.replyTo); - if (mClients.size() == 0) { - startMDnsDaemon(); + protected String getMessageInfo(Message msg) { + return cmdToString(msg.what); + } + + NsdStateMachine(String name) { + super(name); + addState(mDefaultState); + addState(mDisabledState, mDefaultState); + addState(mEnabledState, mDefaultState); + if (isNsdEnabled()) { + setInitialState(mEnabledState); + } else { + setInitialState(mDisabledState); + } + setProcessedMessagesSize(25); + } + + class DefaultState extends State { + @Override + public boolean processMessage(Message msg) { + switch (msg.what) { + case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: + if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { + AsyncChannel c = (AsyncChannel) msg.obj; + if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); + c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED); + ClientInfo cInfo = new ClientInfo(c, msg.replyTo); + mClients.put(msg.replyTo, cInfo); + } else { + Slog.e(TAG, "Client connection failure, error=" + msg.arg1); } - mClients.put(msg.replyTo, cInfo); - } else { - Slog.e(TAG, "Client connection failure, error=" + msg.arg1); - } - break; - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { - Slog.e(TAG, "Send failed, client connection lost"); - } else { - if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); - } - mClients.remove(msg.replyTo); - if (mClients.size() == 0) { - stopMDnsDaemon(); - } - break; - case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: - AsyncChannel ac = new AsyncChannel(); - ac.connect(mContext, this, msg.replyTo); - break; - case NsdManager.DISCOVER_SERVICES: - if (DBG) Slog.d(TAG, "Discover services"); - servInfo = (DnsSdServiceInfo) msg.obj; - clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mDiscoveryId != INVALID_ID) { - //discovery already in progress - if (DBG) Slog.d(TAG, "discovery in progress"); - mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, - NsdManager.ALREADY_ACTIVE); break; - } - clientInfo.mDiscoveryId = getUniqueId(); - if (discoverServices(clientInfo.mDiscoveryId, servInfo.getServiceType())) { - mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED); - } else { + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: + if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { + Slog.e(TAG, "Send failed, client connection lost"); + } else { + if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + } + mClients.remove(msg.replyTo); + break; + case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: + AsyncChannel ac = new AsyncChannel(); + ac.connect(mContext, getHandler(), msg.replyTo); + break; + case NsdManager.DISCOVER_SERVICES: mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, - NsdManager.ERROR); - clientInfo.mDiscoveryId = INVALID_ID; - } - break; - case NsdManager.STOP_DISCOVERY: - if (DBG) Slog.d(TAG, "Stop service discovery"); - clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mDiscoveryId == INVALID_ID) { - //already stopped - if (DBG) Slog.d(TAG, "discovery already stopped"); - mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, - NsdManager.ALREADY_ACTIVE); + NsdManager.BUSY); + break; + case NsdManager.STOP_DISCOVERY: + mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, + NsdManager.ERROR); break; - } - if (stopServiceDiscovery(clientInfo.mDiscoveryId)) { - clientInfo.mDiscoveryId = INVALID_ID; - mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED); - } else { - mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, - NsdManager.ERROR); - } - break; - case NsdManager.REGISTER_SERVICE: - if (DBG) Slog.d(TAG, "Register service"); - clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mRegisteredIds.size() >= ClientInfo.MAX_REG) { - if (DBG) Slog.d(TAG, "register service exceeds limit"); - mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, - NsdManager.MAX_REGS_REACHED); - } - - int id = getUniqueId(); - if (registerService(id, (DnsSdServiceInfo) msg.obj)) { - clientInfo.mRegisteredIds.add(id); - } else { + case NsdManager.REGISTER_SERVICE: mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, NsdManager.ERROR); - } - break; - case NsdManager.UNREGISTER_SERVICE: - if (DBG) Slog.d(TAG, "unregister service"); - clientInfo = mClients.get(msg.replyTo); - int regId = msg.arg1; - if (clientInfo.mRegisteredIds.remove(new Integer(regId)) && - unregisterService(regId)) { - mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED); - } else { + break; + case NsdManager.UNREGISTER_SERVICE: mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, NsdManager.ERROR); - } - break; - case NsdManager.UPDATE_SERVICE: - if (DBG) Slog.d(TAG, "Update service"); - //TODO: implement - mReplyChannel.replyToMessage(msg, NsdManager.UPDATE_SERVICE_FAILED); - break; - case NsdManager.RESOLVE_SERVICE: - if (DBG) Slog.d(TAG, "Resolve service"); - servInfo = (DnsSdServiceInfo) msg.obj; - clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mResolveId != INVALID_ID) { - //first cancel existing resolve - stopResolveService(clientInfo.mResolveId); - } - - clientInfo.mResolveId = getUniqueId(); - if (!resolveService(clientInfo.mResolveId, servInfo)) { + break; + case NsdManager.RESOLVE_SERVICE: mReplyChannel.replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, NsdManager.ERROR); - clientInfo.mResolveId = INVALID_ID; - } - break; - case NsdManager.STOP_RESOLVE: - if (DBG) Slog.d(TAG, "Stop resolve"); - clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mResolveId == INVALID_ID) { - //already stopped - if (DBG) Slog.d(TAG, "resolve already stopped"); - mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, - NsdManager.ALREADY_ACTIVE); break; - } - if (stopResolveService(clientInfo.mResolveId)) { - clientInfo.mResolveId = INVALID_ID; - mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_SUCCEEDED); - } else { + case NsdManager.STOP_RESOLVE: mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, NsdManager.ERROR); - } - break; - default: - Slog.d(TAG, "NsdServicehandler.handleMessage ignoring msg=" + msg); - break; + break; + default: + Slog.e(TAG, "Unhandled " + msg); + return NOT_HANDLED; + } + return HANDLED; } } + + class DisabledState extends State { + @Override + public void enter() { + sendNsdStateChangeBroadcast(false); + } + + @Override + public boolean processMessage(Message msg) { + switch (msg.what) { + case NsdManager.ENABLE: + transitionTo(mEnabledState); + break; + default: + return NOT_HANDLED; + } + return HANDLED; + } + } + + class EnabledState extends State { + @Override + public void enter() { + sendNsdStateChangeBroadcast(true); + if (mClients.size() > 0) { + startMDnsDaemon(); + } + } + + @Override + public void exit() { + if (mClients.size() > 0) { + stopMDnsDaemon(); + } + } + + @Override + public boolean processMessage(Message msg) { + ClientInfo clientInfo; + DnsSdServiceInfo servInfo; + boolean result = HANDLED; + switch (msg.what) { + case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: + //First client + if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL && + mClients.size() == 0) { + startMDnsDaemon(); + } + result = NOT_HANDLED; + break; + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: + //Last client + if (mClients.size() == 1) { + stopMDnsDaemon(); + } + result = NOT_HANDLED; + break; + case NsdManager.DISABLE: + //TODO: cleanup clients + transitionTo(mDisabledState); + break; + case NsdManager.DISCOVER_SERVICES: + if (DBG) Slog.d(TAG, "Discover services"); + servInfo = (DnsSdServiceInfo) msg.obj; + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mDiscoveryId != INVALID_ID) { + //discovery already in progress + if (DBG) Slog.d(TAG, "discovery in progress"); + mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, + NsdManager.ALREADY_ACTIVE); + break; + } + clientInfo.mDiscoveryId = getUniqueId(); + if (discoverServices(clientInfo.mDiscoveryId, servInfo.getServiceType())) { + mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, + NsdManager.ERROR); + clientInfo.mDiscoveryId = INVALID_ID; + } + break; + case NsdManager.STOP_DISCOVERY: + if (DBG) Slog.d(TAG, "Stop service discovery"); + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mDiscoveryId == INVALID_ID) { + //already stopped + if (DBG) Slog.d(TAG, "discovery already stopped"); + mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, + NsdManager.ALREADY_ACTIVE); + break; + } + if (stopServiceDiscovery(clientInfo.mDiscoveryId)) { + clientInfo.mDiscoveryId = INVALID_ID; + mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, + NsdManager.ERROR); + } + break; + case NsdManager.REGISTER_SERVICE: + if (DBG) Slog.d(TAG, "Register service"); + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mRegisteredIds.size() >= ClientInfo.MAX_REG) { + if (DBG) Slog.d(TAG, "register service exceeds limit"); + mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, + NsdManager.MAX_REGS_REACHED); + } + + int id = getUniqueId(); + if (registerService(id, (DnsSdServiceInfo) msg.obj)) { + clientInfo.mRegisteredIds.add(id); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, + NsdManager.ERROR); + } + break; + case NsdManager.UNREGISTER_SERVICE: + if (DBG) Slog.d(TAG, "unregister service"); + clientInfo = mClients.get(msg.replyTo); + int regId = msg.arg1; + if (clientInfo.mRegisteredIds.remove(new Integer(regId)) && + unregisterService(regId)) { + mReplyChannel.replyToMessage(msg, + NsdManager.UNREGISTER_SERVICE_SUCCEEDED); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, + NsdManager.ERROR); + } + break; + case NsdManager.UPDATE_SERVICE: + if (DBG) Slog.d(TAG, "Update service"); + //TODO: implement + mReplyChannel.replyToMessage(msg, NsdManager.UPDATE_SERVICE_FAILED); + break; + case NsdManager.RESOLVE_SERVICE: + if (DBG) Slog.d(TAG, "Resolve service"); + servInfo = (DnsSdServiceInfo) msg.obj; + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mResolveId != INVALID_ID) { + //first cancel existing resolve + stopResolveService(clientInfo.mResolveId); + } + + clientInfo.mResolveId = getUniqueId(); + if (!resolveService(clientInfo.mResolveId, servInfo)) { + mReplyChannel.replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.ERROR); + clientInfo.mResolveId = INVALID_ID; + } + break; + case NsdManager.STOP_RESOLVE: + if (DBG) Slog.d(TAG, "Stop resolve"); + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mResolveId == INVALID_ID) { + //already stopped + if (DBG) Slog.d(TAG, "resolve already stopped"); + mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, + NsdManager.ALREADY_ACTIVE); + break; + } + if (stopResolveService(clientInfo.mResolveId)) { + clientInfo.mResolveId = INVALID_ID; + mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_SUCCEEDED); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, + NsdManager.ERROR); + } + break; + default: + result = NOT_HANDLED; + break; + } + return result; + } + } } - private AsyncServiceHandler mAsyncServiceHandler; private NativeDaemonConnector mNativeConnector; private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1); private NsdService(Context context) { mContext = context; - - HandlerThread nsdThread = new HandlerThread("NsdService"); - nsdThread.start(); - mAsyncServiceHandler = new AsyncServiceHandler(nsdThread.getLooper()); + mContentResolver = context.getContentResolver(); mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10, MDNS_TAG, 25); + + mNsdStateMachine = new NsdStateMachine(TAG); + mNsdStateMachine.start(); + Thread th = new Thread(mNativeConnector, MDNS_TAG); th.start(); } public static NsdService create(Context context) throws InterruptedException { NsdService service = new NsdService(context); - /* service.mNativeDaemonConnected.await(); */ + service.mNativeDaemonConnected.await(); return service; } public Messenger getMessenger() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService"); - return new Messenger(mAsyncServiceHandler); + return new Messenger(mNsdStateMachine.getHandler()); + } + + public void setEnabled(boolean enable) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL, + "NsdService"); + Settings.Secure.putInt(mContentResolver, Settings.Secure.NSD_ON, enable ? 1 : 0); + if (enable) { + mNsdStateMachine.sendMessage(NsdManager.ENABLE); + } else { + mNsdStateMachine.sendMessage(NsdManager.DISABLE); + } + } + + private void sendNsdStateChangeBroadcast(boolean enabled) { + final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + if (enabled) { + intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED); + } else { + intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED); + } + mContext.sendStickyBroadcast(intent); + } + + private boolean isNsdEnabled() { + boolean ret = Settings.Secure.getInt(mContentResolver, Settings.Secure.NSD_ON, 1) == 1; + if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret); + return ret; } private int getUniqueId() { @@ -522,7 +683,7 @@ public class NsdService extends INsdManager.Stub { } @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid=" @@ -531,7 +692,12 @@ public class NsdService extends INsdManager.Stub { return; } - pw.println("Internal state:"); + for (ClientInfo client : mClients.values()) { + pw.println("Client Info"); + pw.println(client); + } + + mNsdStateMachine.dump(fd, pw, args); } private ClientInfo getClientByDiscovery(int discoveryId) { @@ -579,5 +745,19 @@ public class NsdService extends INsdManager.Stub { mDiscoveryId = mResolveId = INVALID_ID; if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m); } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("mChannel ").append(mChannel).append("\n"); + sb.append("mMessenger ").append(mMessenger).append("\n"); + sb.append("mDiscoveryId ").append(mDiscoveryId).append("\n"); + sb.append("mResolveId ").append(mResolveId).append("\n"); + sb.append("mResolvedService ").append(mResolvedService).append("\n"); + for(int regId : mRegisteredIds) { + sb.append("regId ").append(regId).append("\n"); + } + return sb.toString(); + } } } diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java index 3a51afe..0cebee7 100644 --- a/services/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/java/com/android/server/wm/WindowStateAnimator.java @@ -978,7 +978,7 @@ class WindowStateAnimator { setSurfaceBoundaries(recoveringMemory); - if (w.mAttachedHidden || !w.isReadyForDisplay() || !w.isDrawnLw()) { + if (w.mAttachedHidden || !w.isReadyForDisplay()) { if (!mLastHidden) { //dump(); mLastHidden = true; @@ -1136,17 +1136,15 @@ class WindowStateAnimator { + " animating=" + mAnimating + " tok animating=" + (mWin.mAppToken != null ? mWin.mAppToken.mAppAnimator.animating : false)); - if (!showSurfaceRobustlyLocked()) { - return false; - } mService.enableScreenIfNeededLocked(); applyEnterAnimationLocked(); + // Force the show in the next prepareSurfaceLocked() call. mLastAlpha = -1; - mLastHidden = false; mDrawState = HAS_DRAWN; + mService.scheduleAnimationLocked(); int i = mWin.mChildWindows.size(); while (i > 0) { diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java index a124c7f..da03f76 100644 --- a/telephony/java/com/android/internal/telephony/DataConnection.java +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -209,7 +209,7 @@ public abstract class DataConnection extends StateMachine { protected static final int EVENT_RIL_CONNECTED = BASE + 5; protected static final int EVENT_DISCONNECT_ALL = BASE + 6; - private static final int CMD_TO_STRING_COUNT = EVENT_DISCONNECT_ALL + 1; + private static final int CMD_TO_STRING_COUNT = EVENT_DISCONNECT_ALL - BASE + 1; private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT]; static { sCmdToString[EVENT_CONNECT - BASE] = "EVENT_CONNECT"; diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java index 4744ff0..96419ae 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionAc.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java @@ -82,7 +82,7 @@ public class DataConnectionAc extends AsyncChannel { public static final int REQ_GET_RECONNECT_INTENT = BASE + 26; public static final int RSP_GET_RECONNECT_INTENT = BASE + 27; - private static final int CMD_TO_STRING_COUNT = RSP_GET_RECONNECT_INTENT + 1; + private static final int CMD_TO_STRING_COUNT = RSP_GET_RECONNECT_INTENT - BASE + 1; private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT]; static { sCmdToString[REQ_IS_INACTIVE - BASE] = "REQ_IS_INACTIVE"; |
