Merge "fix a bug that caused the off animation to not show sometimes"
diff --git a/api/current.txt b/api/current.txt
index 21ee1f1..f380cf9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -709,6 +709,7 @@
field public static final int overScrollFooter = 16843459; // 0x10102c3
field public static final int overScrollHeader = 16843458; // 0x10102c2
field public static final int overScrollMode = 16843457; // 0x10102c1
+ field public static final int overridesImplicitlyEnabledSubtype = 16843696; // 0x10103b0
field public static final int packageNames = 16843649; // 0x1010381
field public static final int padding = 16842965; // 0x10100d5
field public static final int paddingBottom = 16842969; // 0x10100d9
@@ -10668,7 +10669,7 @@
method public void setAuxEffectSendLevel(float);
method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
- method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+ method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDisplay(android.view.SurfaceHolder);
@@ -16774,7 +16775,7 @@
field public static final android.net.Uri CONTENT_URI;
}
- public final class LiveFolders implements android.provider.BaseColumns {
+ public final deprecated class LiveFolders implements android.provider.BaseColumns {
field public static final java.lang.String ACTION_CREATE_LIVE_FOLDER = "android.intent.action.CREATE_LIVE_FOLDER";
field public static final java.lang.String DESCRIPTION = "description";
field public static final int DISPLAY_MODE_GRID = 1; // 0x1
@@ -18463,7 +18464,7 @@
field public static final java.lang.String SERVICE_INTERFACE = "android.service.textservice.SpellCheckerService";
}
- public abstract class SpellCheckerService.Session {
+ public static abstract class SpellCheckerService.Session {
ctor public SpellCheckerService.Session();
method public android.os.Bundle getBundle();
method public java.lang.String getLocale();
@@ -24486,7 +24487,7 @@
method public boolean isWatchingCursor(android.view.View);
method public void restartInput(android.view.View);
method public void sendAppPrivateCommand(android.view.View, java.lang.String, android.os.Bundle);
- method public boolean setAdditionalInputMethodSubtypes(java.lang.String, android.view.inputmethod.InputMethodSubtype[]);
+ method public void setAdditionalInputMethodSubtypes(java.lang.String, android.view.inputmethod.InputMethodSubtype[]);
method public boolean setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype);
method public void setInputMethod(android.os.IBinder, java.lang.String);
method public void setInputMethodAndSubtype(android.os.IBinder, java.lang.String, android.view.inputmethod.InputMethodSubtype);
@@ -24531,8 +24532,7 @@
}
public final class InputMethodSubtype implements android.os.Parcelable {
- ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String);
- ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean);
+ ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean);
method public boolean containsExtraValueKey(java.lang.String);
method public int describeContents();
method public java.lang.CharSequence getDisplayName(android.content.Context, java.lang.String, android.content.pm.ApplicationInfo);
@@ -24543,6 +24543,7 @@
method public java.lang.String getMode();
method public int getNameResId();
method public boolean isAuxiliary();
+ method public boolean overridesImplicitlyEnabledSubtype();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index aa3bc03..b13236a 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -357,9 +357,9 @@
}
sp<IMediaPlayer> player =
- service->create(getpid(), client, source, 0);
+ service->create(getpid(), client, 0);
- if (player != NULL) {
+ if (player != NULL && player->setDataSource(source) == NO_ERROR) {
player->setVideoSurface(surface);
player->start();
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index e5f3273..3918cfd 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -320,15 +320,36 @@
* checking if a {@link #subtract(NetworkStats)} delta passes a threshold.
*/
public long getTotalBytes() {
- long totalBytes = 0;
+ final Entry entry = getTotal(null);
+ return entry.rxBytes + entry.txBytes;
+ }
+
+ /**
+ * Return total of all fields represented by this snapshot object.
+ */
+ public Entry getTotal(Entry recycle) {
+ final Entry entry = recycle != null ? recycle : new Entry();
+
+ entry.iface = IFACE_ALL;
+ entry.uid = UID_ALL;
+ entry.set = SET_ALL;
+ entry.tag = TAG_NONE;
+ entry.rxBytes = 0;
+ entry.rxPackets = 0;
+ entry.txBytes = 0;
+ entry.txPackets = 0;
+
for (int i = 0; i < size; i++) {
// skip specific tags, since already counted in TAG_NONE
if (tag[i] != TAG_NONE) continue;
- totalBytes += rxBytes[i];
- totalBytes += txBytes[i];
+ entry.rxBytes += rxBytes[i];
+ entry.rxPackets += rxPackets[i];
+ entry.txBytes += txBytes[i];
+ entry.txPackets += txPackets[i];
+ entry.operations += operations[i];
}
- return totalBytes;
+ return entry;
}
/**
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index 3cc6820..da878d4 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -20,7 +20,7 @@
import android.os.RemoteException;
import android.util.Log;
-import java.util.HashMap;
+import java.util.WeakHashMap;
/**
* Manages NFC API's that are coupled to the life-cycle of an Activity.
@@ -38,7 +38,7 @@
static final Boolean DBG = false;
final NfcAdapter mAdapter;
- final HashMap<Activity, NfcActivityState> mNfcState; // contents protected by this
+ final WeakHashMap<Activity, NfcActivityState> mNfcState; // contents protected by this
final NfcEvent mDefaultEvent; // can re-use one NfcEvent because it just contains adapter
/**
@@ -60,7 +60,7 @@
public NfcActivityManager(NfcAdapter adapter) {
mAdapter = adapter;
- mNfcState = new HashMap<Activity, NfcActivityState>();
+ mNfcState = new WeakHashMap<Activity, NfcActivityState>();
mDefaultEvent = new NfcEvent(mAdapter);
}
@@ -88,6 +88,13 @@
}
}
+ /**
+ * onDestroy hook from fragment attached to activity
+ */
+ public void onDestroy(Activity activity) {
+ mNfcState.remove(activity);
+ }
+
public synchronized void setNdefPushMessage(Activity activity, NdefMessage message) {
NfcActivityState state = getOrCreateState(activity, message != null);
if (state == null || state.ndefMessage == message) {
@@ -214,4 +221,5 @@
callback.onNdefPushComplete(mDefaultEvent);
}
}
+
}
diff --git a/core/java/android/nfc/NfcFragment.java b/core/java/android/nfc/NfcFragment.java
index c48859b..17278dc 100644
--- a/core/java/android/nfc/NfcFragment.java
+++ b/core/java/android/nfc/NfcFragment.java
@@ -80,4 +80,14 @@
sNfcActivityManager.onPause(getActivity());
}
}
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (sNfcActivityManager != null) {
+ sNfcActivityManager.onDestroy(getActivity());
+ }
+ }
+
+
}
diff --git a/core/java/android/provider/LiveFolders.java b/core/java/android/provider/LiveFolders.java
index 7856bab..cf8ad46 100644
--- a/core/java/android/provider/LiveFolders.java
+++ b/core/java/android/provider/LiveFolders.java
@@ -162,7 +162,17 @@
* </tr>
* </tbody>
* </table>
+ *
+ * @deprecated Live folders are no longer supported by Android. These have been
+ * replaced by the new
+ * <a href="{@docRoot}guide/topics/appwidgets/index.html#collections">AppWidget Collection</a>
+ * APIs introduced in {@link android.os.Build.VERSION_CODES#HONEYCOMB}. These provide
+ * all of the features of live folders plus many more. The use of live folders is greatly
+ * discouraged because of security issues they introduce -- publishing a live folder requires
+ * making all data show for the live folder available to all applications with no
+ * permissions protecting it.
*/
+@Deprecated
public final class LiveFolders implements BaseColumns {
/**
* <p>Content provider column.</p>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index efdb79e..bc5994e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -42,6 +42,7 @@
import android.text.TextUtils;
import android.util.AndroidException;
import android.util.Log;
+import android.view.WindowOrientationListener;
import java.net.URISyntaxException;
import java.util.HashMap;
@@ -59,7 +60,7 @@
* <p>
* Input: Nothing.
* <p>
- * Output: nothing.
+ * Output: Nothing.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SETTINGS = "android.settings.SETTINGS";
@@ -69,7 +70,7 @@
* <p>
* Input: Nothing.
* <p>
- * Output: nothing.
+ * Output: Nothing.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_APN_SETTINGS = "android.settings.APN_SETTINGS";
@@ -328,6 +329,23 @@
"android.settings.USER_DICTIONARY_SETTINGS";
/**
+ * Activity Action: Adds a word to the user dictionary.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: An extra with key <code>word</code> that contains the word
+ * that should be added to the dictionary.
+ * <p>
+ * Output: Nothing.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_USER_DICTIONARY_INSERT =
+ "com.android.settings.USER_DICTIONARY_INSERT";
+
+ /**
* Activity Action: Show settings to allow configuration of application-related settings.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -1462,6 +1480,7 @@
* @hide
* @deprecated
*/
+ @Deprecated
public static final String NOTIFICATIONS_USE_RING_VOLUME =
"notifications_use_ring_volume";
diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java
index 3e2e38e..b96099e 100644
--- a/core/java/android/service/textservice/SpellCheckerService.java
+++ b/core/java/android/service/textservice/SpellCheckerService.java
@@ -66,7 +66,7 @@
/**
* This abstract class should be overridden by a concrete implementation of a spell checker.
*/
- public abstract class Session {
+ public static abstract class Session {
private InternalISpellCheckerSession mInternalSession;
/**
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 355d467..894afbd 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -750,7 +750,7 @@
case SUGGESTION_RANGE_SPAN:
readSpan(p, sp, new SuggestionRangeSpan(p));
break;
-
+
case EASY_EDIT_SPAN:
readSpan(p, sp, new EasyEditSpan());
break;
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index fe96565..b8728ee 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -232,8 +232,7 @@
if (widget.isFocused() && !widget.didTouchFocusSelect()) {
if (action == MotionEvent.ACTION_DOWN) {
- boolean cap = isSelecting(buffer);
- if (cap) {
+ if (isSelecting(buffer)) {
int offset = widget.getOffsetForPosition(event.getX(), event.getY());
buffer.setSpan(LAST_TAP_DOWN, offset, offset, Spannable.SPAN_POINT_POINT);
@@ -245,9 +244,7 @@
widget.getParent().requestDisallowInterceptTouchEvent(true);
}
} else if (action == MotionEvent.ACTION_MOVE) {
- boolean cap = isSelecting(buffer);
-
- if (cap && handled) {
+ if (isSelecting(buffer) && handled) {
// Before selecting, make sure we've moved out of the "slop".
// handled will be true, if we're in select mode AND we're
// OUT of the slop
@@ -279,7 +276,7 @@
if (isSelecting(buffer)) {
buffer.removeSpan(LAST_TAP_DOWN);
Selection.extendSelection(buffer, offset);
- } else {
+ } else if (!widget.shouldIgnoreActionUpEvent()) {
Selection.setSelection(buffer, offset);
}
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index a528044..3f9b945 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -147,12 +147,10 @@
int nx = widget.getScrollX() + (int) dx;
int ny = widget.getScrollY() + (int) dy;
- int padding = widget.getTotalPaddingTop() +
- widget.getTotalPaddingBottom();
+ int padding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom();
Layout layout = widget.getLayout();
- ny = Math.min(ny, layout.getHeight() - (widget.getHeight() -
- padding));
+ ny = Math.min(ny, layout.getHeight() - (widget.getHeight() - padding));
ny = Math.max(ny, 0);
int oldX = widget.getScrollX();
@@ -161,8 +159,7 @@
scrollTo(widget, layout, nx, ny);
// If we actually scrolled, then cancel the up action.
- if (oldX != widget.getScrollX()
- || oldY != widget.getScrollY()) {
+ if (oldX != widget.getScrollX() || oldY != widget.getScrollY()) {
widget.cancelLongPress();
}
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 8625257..693a7a9 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -76,8 +76,11 @@
private final String mNotificationTargetClassName;
private final int mHashCode;
- private float mUnderlineThickness;
- private int mUnderlineColor;
+ private float mEasyCorrectUnderlineThickness;
+ private int mEasyCorrectUnderlineColor;
+
+ private float mMisspelledUnderlineThickness;
+ private int mMisspelledUnderlineColor;
/*
* TODO: If switching IME is required, needs to add parameters for ids of InputMethodInfo
@@ -132,25 +135,22 @@
}
private void initStyle(Context context) {
- int defStyle = 0;
- if ((getFlags() & FLAG_MISSPELLED) != 0) {
- defStyle = com.android.internal.R.attr.textAppearanceMisspelledSuggestion;
- } else if ((getFlags() & FLAG_EASY_CORRECT) != 0) {
- defStyle = com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion;
- } else {
- // No style is applied.
- mUnderlineThickness = 0;
- mUnderlineColor = 0;
- return;
- }
-
- TypedArray typedArray = context.obtainStyledAttributes(null,
- com.android.internal.R.styleable.SuggestionSpan,
- defStyle, 0);
-
- mUnderlineThickness = typedArray.getDimension(
+ int defStyle = com.android.internal.R.attr.textAppearanceMisspelledSuggestion;
+ TypedArray typedArray = context.obtainStyledAttributes(
+ null, com.android.internal.R.styleable.SuggestionSpan, defStyle, 0);
+ mMisspelledUnderlineThickness = typedArray.getDimension(
com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
- mUnderlineColor = typedArray.getColor(
+ mMisspelledUnderlineColor = typedArray.getColor(
+ com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
+
+ defStyle = com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion;
+
+ typedArray = context.obtainStyledAttributes(
+ null, com.android.internal.R.styleable.SuggestionSpan, defStyle, 0);
+
+ mEasyCorrectUnderlineThickness = typedArray.getDimension(
+ com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
+ mEasyCorrectUnderlineColor = typedArray.getColor(
com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
}
@@ -160,8 +160,10 @@
mLocaleString = src.readString();
mNotificationTargetClassName = src.readString();
mHashCode = src.readInt();
- mUnderlineColor = src.readInt();
- mUnderlineThickness = src.readFloat();
+ mEasyCorrectUnderlineColor = src.readInt();
+ mEasyCorrectUnderlineThickness = src.readFloat();
+ mMisspelledUnderlineColor = src.readInt();
+ mMisspelledUnderlineThickness = src.readFloat();
}
/**
@@ -211,8 +213,10 @@
dest.writeString(mLocaleString);
dest.writeString(mNotificationTargetClassName);
dest.writeInt(mHashCode);
- dest.writeInt(mUnderlineColor);
- dest.writeFloat(mUnderlineThickness);
+ dest.writeInt(mEasyCorrectUnderlineColor);
+ dest.writeFloat(mEasyCorrectUnderlineThickness);
+ dest.writeInt(mMisspelledUnderlineColor);
+ dest.writeFloat(mMisspelledUnderlineThickness);
}
@Override
@@ -254,6 +258,10 @@
@Override
public void updateDrawState(TextPaint tp) {
- tp.setUnderlineText(mUnderlineColor, mUnderlineThickness);
+ if ((mFlags & FLAG_MISSPELLED) != 0) {
+ tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
+ } else if ((mFlags & FLAG_EASY_CORRECT) != 0) {
+ tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
+ }
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 4ec4ff9..0119d03 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -164,7 +164,9 @@
a.getString(com.android.internal.R.styleable
.InputMethod_Subtype_imeSubtypeExtraValue),
a.getBoolean(com.android.internal.R.styleable
- .InputMethod_Subtype_isAuxiliary, false));
+ .InputMethod_Subtype_isAuxiliary, false),
+ a.getBoolean(com.android.internal.R.styleable
+ .InputMethod_Subtype_overridesImplicitlyEnabledSubtype, false));
mSubtypes.add(subtype);
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 302be57..3ead9df 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1593,15 +1593,13 @@
* to the current implementation.)
* @param imiId Id of InputMethodInfo which additional input method subtypes will be added to.
* @param subtypes subtypes will be added as additional subtypes of the current input method.
- * @return true if the additional input method subtypes are successfully added.
*/
- public boolean setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
+ public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
synchronized (mH) {
try {
- return mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
+ mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId, e);
- return false;
}
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 4a98336..5670432 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -42,6 +42,7 @@
private static final String EXTRA_VALUE_KEY_VALUE_SEPARATOR = "=";
private final boolean mIsAuxiliary;
+ private final boolean mOverridesImplicitlyEnabledSubtype;
private final int mSubtypeHashCode;
private final int mSubtypeIconResId;
private final int mSubtypeNameResId;
@@ -57,10 +58,12 @@
* @param locale The locale supported by the subtype
* @param mode The mode supported by the subtype
* @param extraValue The extra value of the subtype
+ * @param isAuxiliary true when this subtype is one shot subtype.
+ * @hide
*/
- public InputMethodSubtype(
- int nameId, int iconId, String locale, String mode, String extraValue) {
- this(nameId, iconId, locale, mode, extraValue, false);
+ public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
+ boolean isAuxiliary) {
+ this(nameId, iconId, locale, mode, extraValue, false, false);
}
/**
@@ -71,17 +74,21 @@
* @param mode The mode supported by the subtype
* @param extraValue The extra value of the subtype
* @param isAuxiliary true when this subtype is one shot subtype.
+ * @param overridesImplicitlyEnabledSubtype true when this subtype should be selected by default
+ * if no other subtypes are selected explicitly. Note that a subtype with this parameter being
+ * true will not be shown in the subtypes list.
*/
public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
- boolean isAuxiliary) {
+ boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype) {
mSubtypeNameResId = nameId;
mSubtypeIconResId = iconId;
mSubtypeLocale = locale != null ? locale : "";
mSubtypeMode = mode != null ? mode : "";
mSubtypeExtraValue = extraValue != null ? extraValue : "";
mIsAuxiliary = isAuxiliary;
+ mOverridesImplicitlyEnabledSubtype = overridesImplicitlyEnabledSubtype;
mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue,
- mIsAuxiliary);
+ mIsAuxiliary, mOverridesImplicitlyEnabledSubtype);
}
InputMethodSubtype(Parcel source) {
@@ -95,8 +102,9 @@
s = source.readString();
mSubtypeExtraValue = s != null ? s : "";
mIsAuxiliary = (source.readInt() == 1);
+ mOverridesImplicitlyEnabledSubtype = (source.readInt() == 1);
mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue,
- mIsAuxiliary);
+ mIsAuxiliary, mOverridesImplicitlyEnabledSubtype);
}
/**
@@ -144,6 +152,14 @@
}
/**
+ * @return true when this subtype is selected by default if no other subtypes are selected
+ * explicitly. Note that a subtype that returns true will not be shown in the subtypes list.
+ */
+ public boolean overridesImplicitlyEnabledSubtype() {
+ return mOverridesImplicitlyEnabledSubtype;
+ }
+
+ /**
* @param context Context will be used for getting Locale and PackageManager.
* @param packageName The package name of the IME
* @param appInfo The application info of the IME
@@ -242,6 +258,7 @@
dest.writeString(mSubtypeMode);
dest.writeString(mSubtypeExtraValue);
dest.writeInt(mIsAuxiliary ? 1 : 0);
+ dest.writeInt(mOverridesImplicitlyEnabledSubtype ? 1 : 0);
}
public static final Parcelable.Creator<InputMethodSubtype> CREATOR
@@ -274,8 +291,9 @@
}
private static int hashCodeInternal(String locale, String mode, String extraValue,
- boolean isAuxiliary) {
- return Arrays.hashCode(new Object[] {locale, mode, extraValue, isAuxiliary});
+ boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype) {
+ return Arrays.hashCode(new Object[] {locale, mode, extraValue, isAuxiliary,
+ overridesImplicitlyEnabledSubtype});
}
/**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 2e7f923..64fbae6f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2346,6 +2346,14 @@
}
/**
+ * Return the reading level scale of the WebView
+ * @return The reading level scale.
+ */
+ /*package*/ float getReadingLevelScale() {
+ return mZoomManager.getReadingLevelScale();
+ }
+
+ /**
* Set the initial scale for the WebView. 0 means default. If
* {@link WebSettings#getUseWideViewPort()} is true, it zooms out all the
* way. Otherwise it starts with 100%. If initial scale is greater than 0,
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 73a30c4..c61bd48 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -538,6 +538,8 @@
private native void nativeSendListBoxChoice(int choice);
+ private native void nativeCloseIdleConnections();
+
/* Tell webkit what its width and height are, for the purposes
of layout/line-breaking. These coordinates are in document space,
which is the same as View coords unless we have zoomed the document
@@ -1262,6 +1264,8 @@
if (!JniUtil.useChromiumHttpStack()) {
WebViewWorker.getHandler().sendEmptyMessage(
WebViewWorker.MSG_PAUSE_CACHE_TRANSACTION);
+ } else {
+ nativeCloseIdleConnections();
}
break;
@@ -2456,7 +2460,7 @@
if (mSettings.isNarrowColumnLayout()) {
// In case of automatic text reflow in fixed view port mode.
mInitialViewState.mTextWrapScale =
- ZoomManager.computeReadingLevelScale(data.mScale);
+ mWebView.getReadingLevelScale();
}
} else {
// Scale is given such as when page is restored, use it.
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 2bcb020..0bfb668 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -58,13 +58,6 @@
private ZoomControlExternal mExternalZoomControl;
/*
- * For large screen devices, the defaultScale usually set to 1.0 and
- * equal to the overview scale, to differentiate the zoom level for double tapping,
- * a default reading level scale is used.
- */
- private static final float DEFAULT_READING_LEVEL_SCALE = 1.5f;
-
- /*
* The scale factors that determine the upper and lower bounds for the
* default zoom scale.
*/
@@ -151,6 +144,19 @@
private float mDefaultScale;
private float mInvDefaultScale;
+ /*
+ * The scale factor that is used to determine the zoom level for reading text.
+ * The value is initially set to equal the display density.
+ * TODO: Support changing this in WebSettings
+ */
+ private float mReadingLevelScale;
+
+ /*
+ * The scale factor that is used as the minimum increment when going from
+ * overview to reading level on a double tap.
+ */
+ private static float MIN_DOUBLE_TAP_SCALE_INCREMENT = 0.5f;
+
// the current computed zoom scale and its inverse.
private float mActualScale;
private float mInvActualScale;
@@ -230,6 +236,7 @@
setDefaultZoomScale(density);
mActualScale = density;
mInvActualScale = 1 / density;
+ mReadingLevelScale = density;
mTextWrapScale = density;
}
@@ -304,13 +311,7 @@
}
public final float getReadingLevelScale() {
- return computeScaleWithLimits(computeReadingLevelScale(getZoomOverviewScale()));
- }
-
- /* package */ final static float computeReadingLevelScale(float scale) {
- // The reading scale is at least 0.5f apart from the input scale.
- final float MIN_SCALE_DIFF = 0.5f;
- return Math.max(scale + MIN_SCALE_DIFF, DEFAULT_READING_LEVEL_SCALE);
+ return mReadingLevelScale;
}
public final float getInvDefaultScale() {
@@ -652,7 +653,7 @@
} else if (!mInZoomOverview && willScaleTriggerZoom(getZoomOverviewScale())) {
zoomToOverview();
} else {
- zoomToReadingLevel();
+ zoomToReadingLevelOrMore();
}
}
@@ -683,8 +684,10 @@
!mWebView.getSettings().getUseFixedViewport());
}
- private void zoomToReadingLevel() {
- final float readingScale = getReadingLevelScale();
+ private void zoomToReadingLevelOrMore() {
+ final float zoomScale = Math.max(getReadingLevelScale(),
+ mActualScale + MIN_DOUBLE_TAP_SCALE_INCREMENT);
+
int left = mWebView.nativeGetBlockLeftEdge(mAnchorX, mAnchorY, mActualScale);
if (left != WebView.NO_LEFTEDGE) {
// add a 5pt padding to the left edge.
@@ -693,13 +696,13 @@
// Re-calculate the zoom center so that the new scroll x will be
// on the left edge.
if (viewLeft > 0) {
- mZoomCenterX = viewLeft * readingScale / (readingScale - mActualScale);
+ mZoomCenterX = viewLeft * zoomScale / (zoomScale - mActualScale);
} else {
mWebView.scrollBy(viewLeft, 0);
mZoomCenterX = 0;
}
}
- startZoomAnimation(readingScale,
+ startZoomAnimation(zoomScale,
!mWebView.getSettings().getUseFixedViewport());
}
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 4fcb358..02c9d03 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -161,6 +161,7 @@
mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
// Refresh display with current params
+ refreshDrawableState();
setChecked(isChecked());
}
@@ -632,8 +633,9 @@
int[] myDrawableState = getDrawableState();
// Set the state of the Drawable
- mThumbDrawable.setState(myDrawableState);
- mTrackDrawable.setState(myDrawableState);
+ // Drawable may be null when checked state is set from XML, from super constructor
+ if (mThumbDrawable != null) mThumbDrawable.setState(myDrawableState);
+ if (mTrackDrawable != null) mTrackDrawable.setState(myDrawableState);
invalidate();
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1aa009b..abf1281 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -21,6 +21,7 @@
import android.content.ClipData.Item;
import android.content.ClipboardManager;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -42,6 +43,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
+import android.provider.Settings;
import android.text.BoringLayout;
import android.text.DynamicLayout;
import android.text.Editable;
@@ -8119,6 +8121,7 @@
Selection.setSelection((Spannable) mText, selStart, selEnd);
} else {
hideControllers();
+ downgradeEasyCorrectionSpans();
}
// No need to create the controller
@@ -8243,10 +8246,10 @@
return superResult;
}
- final boolean touchIsFinished = action == MotionEvent.ACTION_UP && !mIgnoreActionUpEvent &&
- isFocused();
+ final boolean touchIsFinished = (action == MotionEvent.ACTION_UP) &&
+ !shouldIgnoreActionUpEvent() && isFocused();
- if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()
+ if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()
&& mText instanceof Spannable && mLayout != null) {
boolean handled = false;
@@ -8254,9 +8257,10 @@
handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
}
- if (mLinksClickable && mAutoLinkMask != 0 && mTextIsSelectable && touchIsFinished) {
+ if (touchIsFinished && mLinksClickable && mAutoLinkMask != 0 && mTextIsSelectable) {
// The LinkMovementMethod which should handle taps on links has not been installed
- // to support text selection. We reproduce its behavior here to open links.
+ // on non editable text that support text selection.
+ // We reproduce its behavior here to open links for these.
ClickableSpan[] links = ((Spannable) mText).getSpans(getSelectionStart(),
getSelectionEnd(), ClickableSpan.class);
@@ -8266,7 +8270,7 @@
}
}
- if ((isTextEditable() || mTextIsSelectable) && touchIsFinished) {
+ if (touchIsFinished && (isTextEditable() || mTextIsSelectable)) {
// Show the IME, except when selecting in read-only text.
final InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
@@ -8277,16 +8281,12 @@
}
boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect();
- if (!selectAllGotFocus && hasSelection()) {
- startSelectionActionMode();
- } else {
- hideControllers();
- if (!selectAllGotFocus && mText.length() > 0) {
- if (isCursorInsideEasyCorrectionSpan()) {
- showSuggestions();
- } else if (hasInsertionController()) {
- getInsertionController().show();
- }
+ hideControllers();
+ if (!selectAllGotFocus && mText.length() > 0) {
+ if (isCursorInsideEasyCorrectionSpan()) {
+ showSuggestions();
+ } else if (hasInsertionController()) {
+ getInsertionController().show();
}
}
@@ -8328,6 +8328,26 @@
return false;
}
+ /**
+ * Downgrades to simple suggestions all the easy correction spans that are not a spell check
+ * span.
+ */
+ private void downgradeEasyCorrectionSpans() {
+ if (mText instanceof Spannable) {
+ Spannable spannable = (Spannable) mText;
+ SuggestionSpan[] suggestionSpans = spannable.getSpans(0,
+ spannable.length(), SuggestionSpan.class);
+ for (int i = 0; i < suggestionSpans.length; i++) {
+ int flags = suggestionSpans[i].getFlags();
+ if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
+ && (flags & SuggestionSpan.FLAG_MISSPELLED) == 0) {
+ flags = flags & ~SuggestionSpan.FLAG_EASY_CORRECT;
+ suggestionSpans[i].setFlags(flags);
+ }
+ }
+ }
+ }
+
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (mMovement != null && mText instanceof Spannable && mLayout != null) {
@@ -8398,7 +8418,18 @@
super.cancelLongPress();
mIgnoreActionUpEvent = true;
}
-
+
+ /**
+ * This method is only valid during a touch event.
+ *
+ * @return true when the ACTION_UP event should be ignored, false otherwise.
+ *
+ * @hide
+ */
+ public boolean shouldIgnoreActionUpEvent() {
+ return mIgnoreActionUpEvent;
+ }
+
@Override
public boolean onTrackballEvent(MotionEvent event) {
if (mMovement != null && mText instanceof Spannable &&
@@ -9152,6 +9183,7 @@
startDrag(data, getTextThumbnailBuilder(selectedText), localState, 0);
stopSelectionActionMode();
} else {
+ getSelectionController().hide();
selectCurrentWord();
getSelectionController().show();
}
@@ -9199,7 +9231,8 @@
}
private interface TextViewPositionListener {
- public void updatePosition(int parentPositionX, int parentPositionY, boolean modified);
+ public void updatePosition(int parentPositionX, int parentPositionY,
+ boolean parentPositionChanged, boolean parentScrolled);
}
private class PositionListener implements ViewTreeObserver.OnPreDrawListener {
@@ -9212,6 +9245,7 @@
// Absolute position of the TextView with respect to its parent window
private int mPositionX, mPositionY;
private int mNumberOfListeners;
+ private boolean mScrollHasChanged;
public void addSubscriber(TextViewPositionListener positionListener, boolean canMove) {
if (mNumberOfListeners == 0) {
@@ -9263,15 +9297,16 @@
updatePosition();
for (int i = 0; i < MAXIMUM_NUMBER_OF_LISTENERS; i++) {
- if (mPositionHasChanged || mCanMove[i]) {
+ if (mPositionHasChanged || mScrollHasChanged || mCanMove[i]) {
TextViewPositionListener positionListener = mPositionListeners[i];
if (positionListener != null) {
positionListener.updatePosition(mPositionX, mPositionY,
- mPositionHasChanged);
+ mPositionHasChanged, mScrollHasChanged);
}
}
}
+ mScrollHasChanged = false;
return true;
}
@@ -9313,6 +9348,18 @@
final int primaryHorizontal = (int) mLayout.getPrimaryHorizontal(offset);
return isVisible(primaryHorizontal, lineBottom);
}
+
+ public void onScrollChanged() {
+ mScrollHasChanged = true;
+ }
+ }
+
+ @Override
+ protected void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) {
+ super.onScrollChanged(horiz, vert, oldHoriz, oldVert);
+ if (mPositionListener != null) {
+ mPositionListener.onScrollChanged();
+ }
}
private abstract class PinnedPopupWindow implements TextViewPositionListener {
@@ -9343,7 +9390,7 @@
}
public void show() {
- TextView.this.getPositionListener().addSubscriber(this, false);
+ TextView.this.getPositionListener().addSubscriber(this, false /* offset is fixed */);
computeLocalPosition();
@@ -9402,8 +9449,11 @@
}
@Override
- public void updatePosition(int parentPositionX, int parentPositionY, boolean modified) {
+ public void updatePosition(int parentPositionX, int parentPositionY,
+ boolean parentPositionChanged, boolean parentScrolled) {
+ // Either parentPositionChanged or parentScrolled is true, check if still visible
if (isShowing() && getPositionListener().isOffsetVisible(getTextOffset())) {
+ if (parentScrolled) computeLocalPosition();
updatePosition(parentPositionX, parentPositionY);
} else {
hide();
@@ -9417,7 +9467,6 @@
private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
private static final int MAX_NUMBER_SUGGESTIONS = SuggestionSpan.SUGGESTIONS_MAX_SIZE;
- private static final int NO_SUGGESTIONS = -1;
private static final float AVERAGE_HIGHLIGHTS_PER_SUGGESTION = 1.4f;
private WordIterator mSuggestionWordIterator;
private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan
@@ -9472,9 +9521,9 @@
listView.setOnItemClickListener(this);
mContentView = listView;
- // Inflate the suggestion items once and for all.
- mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS];
- for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) {
+ // Inflate the suggestion items once and for all. +1 for add to dictionary
+ mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS + 1];
+ for (int i = 0; i < MAX_NUMBER_SUGGESTIONS + 1; i++) {
mSuggestionInfos[i] = new SuggestionInfo();
}
}
@@ -9485,6 +9534,15 @@
SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
int suggestionIndex; // the index of the suggestion inside suggestionSpan
SpannableStringBuilder text = new SpannableStringBuilder();
+
+ void removeMisspelledFlag() {
+ int suggestionSpanFlags = suggestionSpan.getFlags();
+ if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) > 0) {
+ suggestionSpanFlags &= ~(SuggestionSpan.FLAG_MISSPELLED);
+ suggestionSpanFlags &= ~(SuggestionSpan.FLAG_EASY_CORRECT);
+ suggestionSpan.setFlags(suggestionSpanFlags);
+ }
+ }
}
private class SuggestionAdapter extends BaseAdapter {
@@ -9623,6 +9681,8 @@
int spanUnionStart = mText.length();
int spanUnionEnd = 0;
+ SuggestionSpan misspelledSpan = null;
+
for (int spanIndex = 0; spanIndex < nbSpans; spanIndex++) {
SuggestionSpan suggestionSpan = suggestionSpans[spanIndex];
final int spanStart = spannable.getSpanStart(suggestionSpan);
@@ -9630,6 +9690,10 @@
spanUnionStart = Math.min(spanStart, spanUnionStart);
spanUnionEnd = Math.max(spanEnd, spanUnionEnd);
+ if ((suggestionSpan.getFlags() & SuggestionSpan.FLAG_MISSPELLED) != 0) {
+ misspelledSpan = suggestionSpan;
+ }
+
String[] suggestions = suggestionSpan.getSuggestions();
int nbSuggestions = suggestions.length;
for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
@@ -9638,7 +9702,8 @@
suggestionInfo.spanEnd = spanEnd;
suggestionInfo.suggestionSpan = suggestionSpan;
suggestionInfo.suggestionIndex = suggestionIndex;
- suggestionInfo.text = new SpannableStringBuilder(suggestions[suggestionIndex]);
+ suggestionInfo.text.replace(0, suggestionInfo.text.length(),
+ suggestions[suggestionIndex]);
mNumberOfSuggestions++;
if (mNumberOfSuggestions == MAX_NUMBER_SUGGESTIONS) {
@@ -9649,41 +9714,38 @@
}
}
+ for (int i = 0; i < mNumberOfSuggestions; i++) {
+ highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
+ }
+
+ if (misspelledSpan != null) {
+ final int misspelledStart = spannable.getSpanStart(misspelledSpan);
+ final int misspelledEnd = spannable.getSpanEnd(misspelledSpan);
+ if (misspelledStart >= 0 && misspelledEnd > misspelledStart) {
+ SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
+ suggestionInfo.spanStart = misspelledStart;
+ suggestionInfo.spanEnd = misspelledEnd;
+ suggestionInfo.suggestionSpan = misspelledSpan;
+ suggestionInfo.suggestionIndex = -1;
+ suggestionInfo.text.replace(0, suggestionInfo.text.length(),
+ getContext().getString(com.android.internal.R.string.addToDictionary));
+
+ mNumberOfSuggestions++;
+ }
+ }
+
if (mNumberOfSuggestions == 0) return false;
if (mSuggestionRangeSpan == null) mSuggestionRangeSpan =
new SuggestionRangeSpan(mHighlightColor);
-
((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- for (int i = 0; i < mNumberOfSuggestions; i++) {
- highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
- }
mSuggestionsAdapter.notifyDataSetChanged();
return true;
}
- private void onDictionarySuggestionsReceived(String[] suggestions) {
- if (suggestions.length == 0) {
- // TODO Actual implementation of this feature
- suggestions = new String[] {"Add to dictionary"};
- }
-
- WordIterator wordIterator = getWordIterator();
- wordIterator.setCharSequence(mText);
-
- final int pos = getSelectionStart();
- int wordStart = wordIterator.getBeginning(pos);
- int wordEnd = wordIterator.getEnd(pos);
-
- SuggestionSpan suggestionSpan = new SuggestionSpan(getContext(), suggestions, 0);
- ((Editable) mText).setSpan(suggestionSpan, wordStart, wordEnd,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- show();
- }
-
private long[] getWordLimits(CharSequence text) {
// TODO locale for mSuggestionWordIterator
if (mSuggestionWordIterator == null) mSuggestionWordIterator = new WordIterator();
@@ -9836,10 +9898,19 @@
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (view instanceof TextView) {
TextView textView = (TextView) view;
+
SuggestionInfo suggestionInfo = mSuggestionInfos[position];
final int spanStart = suggestionInfo.spanStart;
final int spanEnd = suggestionInfo.spanEnd;
- if (spanStart != NO_SUGGESTIONS) {
+ final String originalText = mText.subSequence(spanStart, spanEnd).toString();
+
+ if (suggestionInfo.suggestionIndex < 0) {
+ Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT);
+ intent.putExtra("word", originalText);
+ intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
+ getContext().startActivity(intent);
+ suggestionInfo.removeMisspelledFlag();
+ } else {
// SuggestionSpans are removed by replace: save them before
Editable editable = (Editable) mText;
SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
@@ -9859,17 +9930,9 @@
final int suggestionEnd = suggestionInfo.suggestionEnd;
final String suggestion = textView.getText().subSequence(
suggestionStart, suggestionEnd).toString();
- final String originalText = mText.subSequence(spanStart, spanEnd).toString();
editable.replace(spanStart, spanEnd, suggestion);
- // A replacement on a misspelled text removes the misspelled flag.
- // TODO restore the flag if the misspelled word is selected back?
- int suggestionSpanFlags = suggestionInfo.suggestionSpan.getFlags();
- if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) > 0) {
- suggestionSpanFlags &= ~(SuggestionSpan.FLAG_MISSPELLED);
- suggestionSpanFlags &= ~(SuggestionSpan.FLAG_EASY_CORRECT);
- suggestionInfo.suggestionSpan.setFlags(suggestionSpanFlags);
- }
+ suggestionInfo.removeMisspelledFlag();
// Notify source IME of the suggestion pick. Do this before swaping texts.
if (!TextUtils.isEmpty(
@@ -9916,12 +9979,6 @@
return mSuggestionsPopupWindow != null && mSuggestionsPopupWindow.isShowing();
}
- void onDictionarySuggestionsReceived(String[] suggestions) {
- if (mSuggestionsPopupWindow != null) {
- mSuggestionsPopupWindow.onDictionarySuggestionsReceived(suggestions);
- }
- }
-
/**
* Return whether or not suggestions are enabled on this TextView. The suggestions are generated
* by the IME or by the spell checker as the user types. This is done by adding
@@ -10349,7 +10406,7 @@
if (i > 0 && i < iMax &&
(now - mPreviousOffsetsTimes[index]) > TOUCH_UP_FILTER_DELAY_BEFORE) {
- positionAtCursorOffset(mPreviousOffsets[index]);
+ positionAtCursorOffset(mPreviousOffsets[index], false);
}
}
@@ -10365,11 +10422,11 @@
public void show() {
if (isShowing()) return;
- getPositionListener().addSubscriber(this, true);
+ getPositionListener().addSubscriber(this, true /* local position may change */);
// Make sure the offset is always considered new, even when focusing at same position
mPreviousOffset = -1;
- positionAtCursorOffset(getCurrentCursorOffset());
+ positionAtCursorOffset(getCurrentCursorOffset(), false);
hideActionPopupWindow();
}
@@ -10434,7 +10491,7 @@
public abstract void updatePosition(float x, float y);
- protected void positionAtCursorOffset(int offset) {
+ protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
// A HandleView relies on the layout, which may be nulled by external methods
if (mLayout == null) {
// Will update controllers' state, hiding them and stopping selection mode if needed
@@ -10442,7 +10499,7 @@
return;
}
- if (offset != mPreviousOffset) {
+ if (offset != mPreviousOffset || parentScrolled) {
updateSelection(offset);
addPositionToTouchUpFilter(offset);
final int line = mLayout.getLineForOffset(offset);
@@ -10459,9 +10516,10 @@
}
}
- public void updatePosition(int parentPositionX, int parentPositionY, boolean modified) {
- positionAtCursorOffset(getCurrentCursorOffset());
- if (modified || mPositionHasChanged) {
+ public void updatePosition(int parentPositionX, int parentPositionY,
+ boolean parentPositionChanged, boolean parentScrolled) {
+ positionAtCursorOffset(getCurrentCursorOffset(), parentScrolled);
+ if (parentPositionChanged || mPositionHasChanged) {
if (mIsDragging) {
// Update touchToWindow offset in case of parent scrolling while dragging
if (parentPositionX != mLastParentX || parentPositionY != mLastParentY) {
@@ -10666,7 +10724,7 @@
@Override
public void updatePosition(float x, float y) {
- positionAtCursorOffset(getOffsetForPosition(x, y));
+ positionAtCursorOffset(getOffsetForPosition(x, y), false);
}
@Override
@@ -10705,17 +10763,13 @@
@Override
public void updatePosition(float x, float y) {
- final int selectionStart = getSelectionStart();
- final int selectionEnd = getSelectionEnd();
-
int offset = getOffsetForPosition(x, y);
- // No need to redraw when the offset is unchanged
- if (offset == selectionStart) return;
// Handles can not cross and selection is at least one character
+ final int selectionEnd = getSelectionEnd();
if (offset >= selectionEnd) offset = selectionEnd - 1;
- positionAtCursorOffset(offset);
+ positionAtCursorOffset(offset, false);
}
public ActionPopupWindow getActionPopupWindow() {
@@ -10746,17 +10800,13 @@
@Override
public void updatePosition(float x, float y) {
- final int selectionStart = getSelectionStart();
- final int selectionEnd = getSelectionEnd();
-
int offset = getOffsetForPosition(x, y);
- // No need to redraw when the offset is unchanged
- if (offset == selectionEnd) return;
// Handles can not cross and selection is at least one character
+ final int selectionStart = getSelectionStart();
if (offset <= selectionStart) offset = selectionStart + 1;
- positionAtCursorOffset(offset);
+ positionAtCursorOffset(offset, false);
}
public void setActionPopupWindow(ActionPopupWindow actionPopupWindow) {
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index ce0299c..683aca5 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -68,5 +68,5 @@
boolean setCurrentInputMethodSubtype(in InputMethodSubtype subtype);
boolean switchToLastInputMethod(in IBinder token);
boolean setInputMethodEnabled(String id, boolean enabled);
- boolean setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
+ oneway void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
}
diff --git a/core/java/com/android/internal/widget/LockScreenWidgetInterface.java b/core/java/com/android/internal/widget/LockScreenWidgetInterface.java
index 6dfcc75..8f80cfc 100644
--- a/core/java/com/android/internal/widget/LockScreenWidgetInterface.java
+++ b/core/java/com/android/internal/widget/LockScreenWidgetInterface.java
@@ -20,4 +20,6 @@
public void setCallback(LockScreenWidgetCallback callback);
+ public boolean providesClock();
+
}
diff --git a/core/java/com/android/internal/widget/TransportControlView.java b/core/java/com/android/internal/widget/TransportControlView.java
index 1c47ca88a..29ad15b 100644
--- a/core/java/com/android/internal/widget/TransportControlView.java
+++ b/core/java/com/android/internal/widget/TransportControlView.java
@@ -381,4 +381,8 @@
mWidgetCallbacks = callback;
}
+ public boolean providesClock() {
+ return false;
+ }
+
}
diff --git a/core/res/res/layout-sw600dp/status_bar_latest_event_ticker.xml b/core/res/res/layout-sw600dp/status_bar_latest_event_ticker.xml
index 7631781..269e086 100644
--- a/core/res/res/layout-sw600dp/status_bar_latest_event_ticker.xml
+++ b/core/res/res/layout-sw600dp/status_bar_latest_event_ticker.xml
@@ -38,8 +38,8 @@
android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_marginTop="-10dp"
+ android:layout_marginBottom="6dip"
+ android:gravity="bottom"
android:singleLine="true"
/>
</LinearLayout>
-
diff --git a/core/res/res/layout-sw600dp/status_bar_latest_event_ticker_large_icon.xml b/core/res/res/layout-sw600dp/status_bar_latest_event_ticker_large_icon.xml
index ff0f7d4..69eac92 100644
--- a/core/res/res/layout-sw600dp/status_bar_latest_event_ticker_large_icon.xml
+++ b/core/res/res/layout-sw600dp/status_bar_latest_event_ticker_large_icon.xml
@@ -33,8 +33,9 @@
android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:layout_marginBottom="6dip"
+ android:gravity="bottom"
android:singleLine="true"
- android:layout_marginTop="-10dp"
/>
<ImageView android:id="@+id/icon"
android:layout_width="wrap_content"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b50c063..0bf5b0a 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2237,6 +2237,10 @@
InputMethodManager#switchToLastInputMethod will ignore auxiliary subtypes when it
chooses a target subtype. -->
<attr name="isAuxiliary" format="boolean" />
+ <!-- Set true when this subtype should be selected by default if no other subtypes are
+ selected explicitly. Note that a subtype with this parameter being true will
+ not be shown in the subtypes list. -->
+ <attr name="overridesImplicitlyEnabledSubtype" format="boolean" />
<!-- The extra value of the subtype. This string can be any string and will be passed to
the IME when the framework calls the IME with the subtype. -->
<attr name="imeSubtypeExtraValue" format="string" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 6988f6b..bc2b907 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2010,4 +2010,5 @@
<public type="attr" name="targetDescriptions" />
<public type="attr" name="directionDescriptions" />
+ <public type="attr" name="overridesImplicitlyEnabledSubtype" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 685ebb7..5e010fe 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2484,6 +2484,9 @@
<!-- Text selection contextual mode title, displayed in the CAB. [CHAR LIMIT=20] -->
<string name="textSelectionCABTitle">Text selection</string>
+ <!-- Option to add the current misspelled word to the user dictionary. [CHAR LIMIT=25] -->
+ <string name="addToDictionary">+ add to dictionary</string>
+
<!-- EditText context menu -->
<string name="inputMethod">Input method</string>
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 1bee47a..e468558 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -46,6 +46,16 @@
</family>
<family>
<fileset>
+ <file>DroidSansArmenian.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file>DroidSansGeorgian.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
<file>Lohit_Hindi.ttf</file>
</fileset>
</family>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 56bd2ce..5bac8f0 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -31,6 +31,8 @@
frameworks/base/data/fonts/DroidSerif-BoldItalic.ttf:system/fonts/DroidSerif-BoldItalic.ttf \
frameworks/base/data/fonts/DroidSansMono.ttf:system/fonts/DroidSansMono.ttf \
frameworks/base/data/fonts/Lohit_Hindi.ttf:system/fonts/Lohit_Hindi.ttf \
+ frameworks/base/data/fonts/DroidSansArmenian.ttf:system/fonts/DroidSansArmenian.ttf \
+ frameworks/base/data/fonts/DroidSansGeorgian.ttf:system/fonts/DroidSansGeorgian.ttf \
frameworks/base/data/fonts/Clockopia.ttf:system/fonts/Clockopia.ttf \
frameworks/base/data/fonts/AndroidClock.ttf:system/fonts/AndroidClock.ttf \
frameworks/base/data/fonts/AndroidClock_Highlight.ttf:system/fonts/AndroidClock_Highlight.ttf \
diff --git a/data/sounds/alarms/wav/Copernicium.wav b/data/sounds/alarms/wav/Copernicium.wav
new file mode 100644
index 0000000..935ea75
--- /dev/null
+++ b/data/sounds/alarms/wav/Copernicium.wav
Binary files differ
diff --git a/data/sounds/alarms/wav/Curium.wav b/data/sounds/alarms/wav/Curium.wav
new file mode 100644
index 0000000..a9942d3
--- /dev/null
+++ b/data/sounds/alarms/wav/Curium.wav
Binary files differ
diff --git a/data/sounds/alarms/wav/Fermium.wav b/data/sounds/alarms/wav/Fermium.wav
new file mode 100644
index 0000000..0174884
--- /dev/null
+++ b/data/sounds/alarms/wav/Fermium.wav
Binary files differ
diff --git a/data/sounds/alarms/wav/Hassium.wav b/data/sounds/alarms/wav/Hassium.wav
new file mode 100644
index 0000000..e3992cf
--- /dev/null
+++ b/data/sounds/alarms/wav/Hassium.wav
Binary files differ
diff --git a/data/sounds/alarms/wav/Neptunium.wav b/data/sounds/alarms/wav/Neptunium.wav
new file mode 100644
index 0000000..cf3684a
--- /dev/null
+++ b/data/sounds/alarms/wav/Neptunium.wav
Binary files differ
diff --git a/data/sounds/alarms/wav/Nobelium.wav b/data/sounds/alarms/wav/Nobelium.wav
new file mode 100644
index 0000000..0e9101a
--- /dev/null
+++ b/data/sounds/alarms/wav/Nobelium.wav
Binary files differ
diff --git a/data/sounds/effects/wav/CameraClick.wav b/data/sounds/effects/wav/CameraClick.wav
new file mode 100644
index 0000000..9fe75f2
--- /dev/null
+++ b/data/sounds/effects/wav/CameraClick.wav
Binary files differ
diff --git a/data/sounds/effects/wav/Dock.wav b/data/sounds/effects/wav/Dock.wav
index 7fa6a7e..7ec64a8 100644
--- a/data/sounds/effects/wav/Dock.wav
+++ b/data/sounds/effects/wav/Dock.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressDelete_14.wav b/data/sounds/effects/wav/KeypressDelete_14.wav
new file mode 100644
index 0000000..1d3498e
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressDelete_14.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressDelete_49.wav b/data/sounds/effects/wav/KeypressDelete_49.wav
new file mode 100644
index 0000000..2404759
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressDelete_49.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressReturn_14.wav b/data/sounds/effects/wav/KeypressReturn_14.wav
new file mode 100644
index 0000000..01573ff
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressReturn_14.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressReturn_49.wav b/data/sounds/effects/wav/KeypressReturn_49.wav
new file mode 100644
index 0000000..6bf216f
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressReturn_49.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressSpacebar_14.wav b/data/sounds/effects/wav/KeypressSpacebar_14.wav
new file mode 100644
index 0000000..77269a6
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressSpacebar_14.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressSpacebar_49.wav b/data/sounds/effects/wav/KeypressSpacebar_49.wav
new file mode 100644
index 0000000..8504a25
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressSpacebar_49.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressStandard_14.wav b/data/sounds/effects/wav/KeypressStandard_14.wav
new file mode 100644
index 0000000..93389ac
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressStandard_14.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressStandard_49.wav b/data/sounds/effects/wav/KeypressStandard_49.wav
new file mode 100644
index 0000000..9a660a1
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressStandard_49.wav
Binary files differ
diff --git a/data/sounds/effects/wav/Lock.wav b/data/sounds/effects/wav/Lock.wav
index 88be052..fead37f 100644
--- a/data/sounds/effects/wav/Lock.wav
+++ b/data/sounds/effects/wav/Lock.wav
Binary files differ
diff --git a/data/sounds/effects/wav/LowBattery.wav b/data/sounds/effects/wav/LowBattery.wav
index 8905534..5d8b48d 100644
--- a/data/sounds/effects/wav/LowBattery.wav
+++ b/data/sounds/effects/wav/LowBattery.wav
Binary files differ
diff --git a/data/sounds/effects/wav/Undock.wav b/data/sounds/effects/wav/Undock.wav
index 358eb18..79abb4e 100644
--- a/data/sounds/effects/wav/Undock.wav
+++ b/data/sounds/effects/wav/Undock.wav
Binary files differ
diff --git a/data/sounds/effects/wav/Unlock.wav b/data/sounds/effects/wav/Unlock.wav
index 4b39c5c..33b80ff 100644
--- a/data/sounds/effects/wav/Unlock.wav
+++ b/data/sounds/effects/wav/Unlock.wav
Binary files differ
diff --git a/data/sounds/effects/wav/VideoRecord.wav b/data/sounds/effects/wav/VideoRecord.wav
index 6880b29..f431023 100644
--- a/data/sounds/effects/wav/VideoRecord.wav
+++ b/data/sounds/effects/wav/VideoRecord.wav
Binary files differ
diff --git a/data/sounds/effects/wav/camera_click.wav b/data/sounds/effects/wav/camera_click.wav
deleted file mode 100644
index 420da7c..0000000
--- a/data/sounds/effects/wav/camera_click.wav
+++ /dev/null
Binary files differ
diff --git a/data/sounds/notifications/wav/Altair.wav b/data/sounds/notifications/wav/Altair.wav
new file mode 100644
index 0000000..0fb9788
--- /dev/null
+++ b/data/sounds/notifications/wav/Altair.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Antares.wav b/data/sounds/notifications/wav/Antares.wav
new file mode 100644
index 0000000..7c2dd23
--- /dev/null
+++ b/data/sounds/notifications/wav/Antares.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Betelgeuse.wav b/data/sounds/notifications/wav/Betelgeuse.wav
new file mode 100644
index 0000000..9ad799f
--- /dev/null
+++ b/data/sounds/notifications/wav/Betelgeuse.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Deneb.wav b/data/sounds/notifications/wav/Deneb.wav
new file mode 100644
index 0000000..ffe7c31
--- /dev/null
+++ b/data/sounds/notifications/wav/Deneb.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Hojus.wav b/data/sounds/notifications/wav/Hojus.wav
new file mode 100644
index 0000000..076a0c7
--- /dev/null
+++ b/data/sounds/notifications/wav/Hojus.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Lalande.wav b/data/sounds/notifications/wav/Lalande.wav
new file mode 100644
index 0000000..14c9fec
--- /dev/null
+++ b/data/sounds/notifications/wav/Lalande.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Mira.wav b/data/sounds/notifications/wav/Mira.wav
new file mode 100644
index 0000000..71be516
--- /dev/null
+++ b/data/sounds/notifications/wav/Mira.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Proxima.wav b/data/sounds/notifications/wav/Proxima.wav
new file mode 100644
index 0000000..109bfdd
--- /dev/null
+++ b/data/sounds/notifications/wav/Proxima.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Upsilon.wav b/data/sounds/notifications/wav/Upsilon.wav
new file mode 100644
index 0000000..ffc959b
--- /dev/null
+++ b/data/sounds/notifications/wav/Upsilon.wav
Binary files differ
diff --git a/data/sounds/ringtones/wav/Cassiopeia.wav b/data/sounds/ringtones/wav/Cassiopeia.wav
new file mode 100644
index 0000000..5c5c6e0
--- /dev/null
+++ b/data/sounds/ringtones/wav/Cassiopeia.wav
Binary files differ
diff --git a/data/sounds/ringtones/wav/Lyra.wav b/data/sounds/ringtones/wav/Lyra.wav
new file mode 100644
index 0000000..2943cf5
--- /dev/null
+++ b/data/sounds/ringtones/wav/Lyra.wav
Binary files differ
diff --git a/data/sounds/ringtones/wav/Sceptrum.wav b/data/sounds/ringtones/wav/Sceptrum.wav
new file mode 100644
index 0000000..3694373
--- /dev/null
+++ b/data/sounds/ringtones/wav/Sceptrum.wav
Binary files differ
diff --git a/data/sounds/ringtones/wav/Solarium.wav b/data/sounds/ringtones/wav/Solarium.wav
new file mode 100644
index 0000000..93f1e01
--- /dev/null
+++ b/data/sounds/ringtones/wav/Solarium.wav
Binary files differ
diff --git a/data/sounds/ringtones/wav/UrsaMinor.wav b/data/sounds/ringtones/wav/UrsaMinor.wav
new file mode 100644
index 0000000..5e16c94
--- /dev/null
+++ b/data/sounds/ringtones/wav/UrsaMinor.wav
Binary files differ
diff --git a/data/sounds/ringtones/wav/Vespa.wav b/data/sounds/ringtones/wav/Vespa.wav
new file mode 100644
index 0000000..7d696f8
--- /dev/null
+++ b/data/sounds/ringtones/wav/Vespa.wav
Binary files differ
diff --git a/docs/html/resources/dashboard/opengl.jd b/docs/html/resources/dashboard/opengl.jd
index 362ee16..2b94b28 100644
--- a/docs/html/resources/dashboard/opengl.jd
+++ b/docs/html/resources/dashboard/opengl.jd
@@ -57,7 +57,7 @@
<div class="dashboard-panel">
<img alt="" width="400" height="250"
-src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1|GL%202.0%20%26%201.1&chd=t%3A8.9,91" />
+src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1|GL%202.0%20%26%201.1&chd=t%3A9.4,90.6" />
<table>
<tr>
@@ -66,14 +66,14 @@
</tr>
<tr>
<td>1.1</th>
-<td>9%</td>
+<td>9.4%</td>
</tr>
<tr>
<td>2.0</th>
-<td>91%</td>
+<td>90.6%</td>
</tr>
</table>
-<p><em>Data collected during a 7-day period ending on July 1, 2011</em></p>
+<p><em>Data collected during a 7-day period ending on September 2, 2011</em></p>
</div>
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index d9adb36..51cbae3 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,27 +52,30 @@
<div class="dashboard-panel">
<img alt="" height="250" width="470"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:1.4,2.2,17.5,59.4,1.0,17.6,0.4,0.5&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3%20-%202.3.2|Android%202.3.3%20-%202.3.4|Android%203.0|Android%203.1&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:1.0,1.8,13.3,51.2,0.6,30.7,0.2,0.7,0.5&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2&chco=c4df9b,6fad0c" />
<table>
<tr>
<th>Platform</th>
+ <th>Codename</th>
<th>API Level</th>
<th>Distribution</th>
</tr>
-<tr><td>Android 1.5</td><td>3</td><td>1.4%</td></tr>
-<tr><td>Android 1.6</td><td>4</td><td>2.2%</td></tr>
-<tr><td>Android 2.1</td><td>7</td><td>17.5%</td></tr>
-<tr><td>Android 2.2</td><td>8</td><td>59.4%</td></tr>
-<tr><td>Android 2.3 -<br/>
- Android 2.3.2</td><td>9</td><td>1%</td></tr>
-<tr><td>Android 2.3.3 -<br/>
- Android 2.3.4</td><td>10</td><td>17.6%</td></tr>
-<tr><td>Android 3.0</td><td>11</td><td>0.4%</td></tr>
-<tr><td>Android 3.1</td><td>12</td><td>0.5%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-1.5.html">Android 1.5</a></td><td>Cupcake</td> <td>3</td><td>1.0%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td> <td>4</td><td>1.8%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td> <td>7</td><td>13.3%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td> <td>8</td><td>51.2%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.3.html">Android 2.3 -<br/>
+ Android 2.3.2</a></td><td rowspan="2">Gingerbread</td> <td>9</td><td>0.6%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.3.3.html">Android 2.3.3 -<br/>
+ Android 2.3.4</a></td><!-- Gingerbread --> <td>10</td><td>30.7%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-3.0.html">Android 3.0</a></td>
+ <td rowspan="3">Honeycomb</td> <td>11</td><td>0.2%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>0.7%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>0.5%</td></tr>
</table>
-<p><em>Data collected during a 14-day period ending on July 5, 2011</em></p>
+<p><em>Data collected during a 14-day period ending on September 2, 2011</em></p>
<!--
<p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
-->
@@ -101,9 +104,9 @@
<div class="dashboard-panel">
<img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C05/15%7C06/01%7C06/15%7C07/01%7C1%3A%7C2011%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:100.0,99.9,99.9,99.9,100.0,99.8,99.7,99.6,99.6,99.5,99.4,99.3,99.2|95.2,95.6,96.0,96.3,96.7,96.8,97.0,97.1,97.3,97.5,97.5,97.5,97.7|87.2,88.3,89.7,90.5,91.5,92.0,93.5,93.9,94.3,94.8,95.0,95.2,95.5|51.8,54.3,58.3,59.7,61.5,63.0,66.4,68.0,69.8,71.5,73.9,75.4,77.6|0.4,0.6,0.7,0.8,1.1,1.7,2.5,3.1,4.0,6.1,9.5,13.6,17.8|0.0,0.0,0.0,0.0,0.0,1.0,1.7,2.2,3.0,5.1,8.4,12.6,16.8&chm=b,c3df9b,0,1,0|b,b4db77,1,2,0|tAndroid 2.1,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|tAndroid2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|tAndroid2.3.3,131d02,5,11,15,,t::-5|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android2.2|Android 2.3|Android 2.3.3&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08" />
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C05/15%7C06/01%7C06/15%7C07/01%7C07/15%7C08/01%7C08/15%7C09/01%7C1%3A%7C2011%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:100.0,99.8,99.7,99.6,99.6,99.5,99.4,99.3,99.2,99.0,98.8,98.7,98.6|96.7,96.8,97.0,97.1,97.3,97.5,97.5,97.5,97.7,97.6,97.5,97.5,97.5|91.5,92.0,93.5,93.9,94.3,94.8,95.0,95.2,95.5,95.5,95.5,95.6,95.8|61.5,63.0,66.4,68.0,69.8,71.5,73.9,75.4,77.6,79.0,80.2,81.1,82.4|1.1,1.7,2.5,3.1,4.0,6.1,9.5,13.6,17.8,20.6,24.3,27.5,31.1|0.0,1.0,1.7,2.2,3.0,5.1,8.4,12.6,16.8,20.0,23.7,26.9,30.5&chm=b,c3df9b,0,1,0|b,b4db77,1,2,0|tAndroid 2.1,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|tAndroid 2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|tAndroid 2.3.3,131d02,5,7,15,,t::-5|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08" />
-<p><em>Last historical dataset collected during a 14-day period ending on July 5, 2011</em></p>
+<p><em>Last historical dataset collected during a 14-day period ending on September 2, 2011</em></p>
</div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/dashboard/screens.jd b/docs/html/resources/dashboard/screens.jd
index e61e799..77fd2d2 100644
--- a/docs/html/resources/dashboard/screens.jd
+++ b/docs/html/resources/dashboard/screens.jd
@@ -59,8 +59,7 @@
<div class="dashboard-panel">
-<img alt="" width="400" height="250"
-src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Small%20/%20hdpi&chd=t%3A0.9,2.8,75,1.0,17,3.3" />
+<img alt="" width="400" height="250" src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi| Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Small%20/%20hdpi&chd=t%3A1.5, 3.2,74,0.9,16.9,3.5" />
<table>
<tr>
@@ -73,29 +72,29 @@
<tr><th scope="row">small</th>
<td></td> <!-- small/ldpi -->
<td></td> <!-- small/mdpi -->
-<td>3.3%</td> <!-- small/hdpi -->
+<td>3.5%</td> <!-- small/hdpi -->
<td></td> <!-- small/xhdpi -->
</tr>
<tr><th scope="row">normal</th>
-<td>1%</td> <!-- normal/ldpi -->
-<td>17%</td> <!-- normal/mdpi -->
-<td>75%</td> <!-- normal/hdpi -->
+<td>0.9%</td> <!-- normal/ldpi -->
+<td>16.9%</td> <!-- normal/mdpi -->
+<td>74%</td> <!-- normal/hdpi -->
<td></td> <!-- normal/xhdpi -->
</tr>
<tr><th scope="row">large</th>
<td></td> <!-- large/ldpi -->
-<td>2.8%</td> <!-- large/mdpi -->
+<td>3.2%</td> <!-- large/mdpi -->
<td></td> <!-- large/hdpi -->
<td></td> <!-- large/xhdpi -->
</tr>
<tr><th scope="row">xlarge</th>
<td></td> <!-- xlarge/ldpi -->
-<td>0.9%</td> <!-- xlarge/mdpi -->
+<td>1.5%</td> <!-- xlarge/mdpi -->
<td></td> <!-- xlarge/hdpi -->
<td></td> <!-- xlarge/xhdpi -->
</tr>
</table>
-<p><em>Data collected during a 7-day period ending on July 1, 2011</em></p>
+<p><em>Data collected during a 7-day period ending on September 2, 2011</em></p>
</div>
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 4418e02a..88c9155 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -111,8 +111,11 @@
alpha += alpha >> 7; // make it 0..256
int baseAlpha = mState.mBaseColor >>> 24;
int useAlpha = baseAlpha * alpha >> 8;
+ int oldUseColor = mState.mUseColor;
mState.mUseColor = (mState.mBaseColor << 8 >>> 8) | (useAlpha << 24);
- invalidateSelf();
+ if (oldUseColor != mState.mUseColor) {
+ invalidateSelf();
+ }
}
/**
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index d552b2e..0e2cdf7 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -20,11 +20,13 @@
#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
+#include <utils/KeyedVector.h>
namespace android {
class Parcel;
class Surface;
+class IStreamSource;
class ISurfaceTexture;
class IMediaPlayer: public IInterface
@@ -34,6 +36,10 @@
virtual void disconnect() = 0;
+ virtual status_t setDataSource(const char *url,
+ const KeyedVector<String8, String8>* headers) = 0;
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0;
+ virtual status_t setDataSource(const sp<IStreamSource>& source) = 0;
virtual status_t setVideoSurface(const sp<Surface>& surface) = 0;
virtual status_t setVideoSurfaceTexture(
const sp<ISurfaceTexture>& surfaceTexture) = 0;
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index 7956788..93bbe13 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -39,17 +39,9 @@
public:
DECLARE_META_INTERFACE(MediaPlayerService);
- virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid) = 0;
+ virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid) = 0;
virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = 0;
- virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client,
- const char* url, const KeyedVector<String8, String8> *headers = NULL,
- int audioSessionId = 0) = 0;
- virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client,
- int fd, int64_t offset, int64_t length, int audioSessionId) = 0;
-
- virtual sp<IMediaPlayer> create(
- pid_t pid, const sp<IMediaPlayerClient> &client,
- const sp<IStreamSource> &source, int audioSessionId) = 0;
+ virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int audioSessionId = 0) = 0;
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 1a67671..e98d55c 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -21,6 +21,7 @@
#include <media/IMediaPlayerClient.h>
#include <media/IMediaPlayer.h>
#include <media/IMediaDeathNotifier.h>
+#include <media/IStreamSource.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
@@ -168,6 +169,7 @@
const KeyedVector<String8, String8> *headers);
status_t setDataSource(int fd, int64_t offset, int64_t length);
+ status_t setDataSource(const sp<IStreamSource> &source);
status_t setVideoSurface(const sp<Surface>& surface);
status_t setVideoSurfaceTexture(
const sp<ISurfaceTexture>& surfaceTexture);
@@ -206,7 +208,7 @@
status_t seekTo_l(int msec);
status_t prepareAsync_l();
status_t getDuration_l(int *msec);
- status_t setDataSource(const sp<IMediaPlayer>& player);
+ status_t attachNewPlayer(const sp<IMediaPlayer>& player);
void disconnectNativeWindow();
status_t reset_l();
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 1ee9a1f..e25f654 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -459,6 +459,9 @@
* android.R.styleable#AndroidManifestUsesPermission <uses-permission>}
* element.
*
+ * <p>This class requires the {@link android.Manifest.permission#INTERNET} permission
+ * when used with network-based content.
+ *
* <a name="Callbacks"></a>
* <h3>Callbacks</h3>
* <p>Applications may want to register for informational and error
@@ -828,6 +831,7 @@
fd.close();
}
}
+
Log.d(TAG, "Couldn't open file on client side, trying server side");
setDataSource(uri.toString(), headers);
return;
@@ -839,7 +843,8 @@
* @param path the path of the file, or the http/rtsp URL of the stream you want to play
* @throws IllegalStateException if it is called in an invalid state
*/
- public native void setDataSource(String path) throws IOException, IllegalArgumentException, IllegalStateException;
+ public native void setDataSource(String path)
+ throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
/**
* Sets the data source (file-path or http/rtsp URL) to use.
@@ -850,7 +855,7 @@
* @hide pending API council
*/
public void setDataSource(String path, Map<String, String> headers)
- throws IOException, IllegalArgumentException, IllegalStateException
+ throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
{
String[] keys = null;
String[] values = null;
@@ -871,7 +876,7 @@
private native void _setDataSource(
String path, String[] keys, String[] values)
- throws IOException, IllegalArgumentException, IllegalStateException;
+ throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
/**
* Sets the data source (FileDescriptor) to use. It is the caller's responsibility
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 354f2c9..5dfbe01 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -155,6 +155,8 @@
} else { // Throw exception!
if ( opStatus == (status_t) INVALID_OPERATION ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
+ jniThrowException(env, "java/lang/SecurityException", NULL);
} else if ( opStatus != (status_t) OK ) {
if (strlen(message) > 230) {
// if the message is too long, don't bother displaying the status code
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 52885d2..bd89ad8 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -21,14 +21,20 @@
#include <binder/Parcel.h>
#include <media/IMediaPlayer.h>
+#include <media/IStreamSource.h>
+
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/Surface.h>
#include <gui/ISurfaceTexture.h>
+#include <utils/String8.h>
namespace android {
enum {
DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+ SET_DATA_SOURCE_URL,
+ SET_DATA_SOURCE_FD,
+ SET_DATA_SOURCE_STREAM,
SET_VIDEO_SURFACE,
PREPARE_ASYNC,
START,
@@ -68,6 +74,43 @@
remote()->transact(DISCONNECT, data, &reply);
}
+ status_t setDataSource(const char* url,
+ const KeyedVector<String8, String8>* headers)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeCString(url);
+ if (headers == NULL) {
+ data.writeInt32(0);
+ } else {
+ // serialize the headers
+ data.writeInt32(headers->size());
+ for (size_t i = 0; i < headers->size(); ++i) {
+ data.writeString8(headers->keyAt(i));
+ data.writeString8(headers->valueAt(i));
+ }
+ }
+ remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setDataSource(int fd, int64_t offset, int64_t length) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeFileDescriptor(fd);
+ data.writeInt64(offset);
+ data.writeInt64(length);
+ remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setDataSource(const sp<IStreamSource> &source) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeStrongBinder(source->asBinder());
+ return reply.readInt32();
+ }
+
// pass the buffered Surface to the media player service
status_t setVideoSurface(const sp<Surface>& surface)
{
@@ -273,6 +316,34 @@
disconnect();
return NO_ERROR;
} break;
+ case SET_DATA_SOURCE_URL: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ const char* url = data.readCString();
+ KeyedVector<String8, String8> headers;
+ int32_t numHeaders = data.readInt32();
+ for (int i = 0; i < numHeaders; ++i) {
+ String8 key = data.readString8();
+ String8 value = data.readString8();
+ headers.add(key, value);
+ }
+ reply->writeInt32(setDataSource(url, numHeaders > 0 ? &headers : NULL));
+ return NO_ERROR;
+ } break;
+ case SET_DATA_SOURCE_FD: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ int fd = data.readFileDescriptor();
+ int64_t offset = data.readInt64();
+ int64_t length = data.readInt64();
+ reply->writeInt32(setDataSource(fd, offset, length));
+ return NO_ERROR;
+ }
+ case SET_DATA_SOURCE_STREAM: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ sp<IStreamSource> source =
+ interface_cast<IStreamSource>(data.readStrongBinder());
+ reply->writeInt32(setDataSource(source));
+ return NO_ERROR;
+ }
case SET_VIDEO_SURFACE: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
sp<Surface> surface = Surface::readFromParcel(data);
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 17a0362..8e4dd04 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -30,9 +30,7 @@
namespace android {
enum {
- CREATE_URL = IBinder::FIRST_CALL_TRANSACTION,
- CREATE_FD,
- CREATE_STREAM,
+ CREATE = IBinder::FIRST_CALL_TRANSACTION,
DECODE_URL,
DECODE_FD,
CREATE_MEDIA_RECORDER,
@@ -60,28 +58,14 @@
}
virtual sp<IMediaPlayer> create(
- pid_t pid, const sp<IMediaPlayerClient>& client,
- const char* url, const KeyedVector<String8, String8> *headers, int audioSessionId) {
+ pid_t pid, const sp<IMediaPlayerClient>& client, int audioSessionId) {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(pid);
data.writeStrongBinder(client->asBinder());
- data.writeCString(url);
-
- if (headers == NULL) {
- data.writeInt32(0);
- } else {
- // serialize the headers
- data.writeInt32(headers->size());
- for (size_t i = 0; i < headers->size(); ++i) {
- data.writeString8(headers->keyAt(i));
- data.writeString8(headers->valueAt(i));
- }
- }
data.writeInt32(audioSessionId);
- remote()->transact(CREATE_URL, data, &reply);
-
+ remote()->transact(CREATE, data, &reply);
return interface_cast<IMediaPlayer>(reply.readStrongBinder());
}
@@ -94,38 +78,6 @@
return interface_cast<IMediaRecorder>(reply.readStrongBinder());
}
- virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd,
- int64_t offset, int64_t length, int audioSessionId)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
- data.writeInt32(pid);
- data.writeStrongBinder(client->asBinder());
- data.writeFileDescriptor(fd);
- data.writeInt64(offset);
- data.writeInt64(length);
- data.writeInt32(audioSessionId);
-
- remote()->transact(CREATE_FD, data, &reply);
-
- return interface_cast<IMediaPlayer>(reply.readStrongBinder());;
- }
-
- virtual sp<IMediaPlayer> create(
- pid_t pid, const sp<IMediaPlayerClient> &client,
- const sp<IStreamSource> &source, int audioSessionId) {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
- data.writeInt32(static_cast<int32_t>(pid));
- data.writeStrongBinder(client->asBinder());
- data.writeStrongBinder(source->asBinder());
- data.writeInt32(static_cast<int32_t>(audioSessionId));
-
- remote()->transact(CREATE_STREAM, data, &reply);
-
- return interface_cast<IMediaPlayer>(reply.readStrongBinder());;
- }
-
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
{
Parcel data, reply;
@@ -181,62 +133,16 @@
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
- case CREATE_URL: {
+ case CREATE: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
pid_t pid = data.readInt32();
sp<IMediaPlayerClient> client =
interface_cast<IMediaPlayerClient>(data.readStrongBinder());
- const char* url = data.readCString();
-
- KeyedVector<String8, String8> headers;
- int32_t numHeaders = data.readInt32();
- for (int i = 0; i < numHeaders; ++i) {
- String8 key = data.readString8();
- String8 value = data.readString8();
- headers.add(key, value);
- }
int audioSessionId = data.readInt32();
-
- sp<IMediaPlayer> player = create(
- pid, client, url, numHeaders > 0 ? &headers : NULL, audioSessionId);
-
+ sp<IMediaPlayer> player = create(pid, client, audioSessionId);
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
} break;
- case CREATE_FD: {
- CHECK_INTERFACE(IMediaPlayerService, data, reply);
- pid_t pid = data.readInt32();
- sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder());
- int fd = dup(data.readFileDescriptor());
- int64_t offset = data.readInt64();
- int64_t length = data.readInt64();
- int audioSessionId = data.readInt32();
-
- sp<IMediaPlayer> player = create(pid, client, fd, offset, length, audioSessionId);
- reply->writeStrongBinder(player->asBinder());
- return NO_ERROR;
- } break;
- case CREATE_STREAM:
- {
- CHECK_INTERFACE(IMediaPlayerService, data, reply);
-
- pid_t pid = static_cast<pid_t>(data.readInt32());
-
- sp<IMediaPlayerClient> client =
- interface_cast<IMediaPlayerClient>(data.readStrongBinder());
-
- sp<IStreamSource> source =
- interface_cast<IStreamSource>(data.readStrongBinder());
-
- int audioSessionId = static_cast<int>(data.readInt32());
-
- sp<IMediaPlayer> player =
- create(pid, client, source, audioSessionId);
-
- reply->writeStrongBinder(player->asBinder());
- return OK;
- break;
- }
case DECODE_URL: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
const char* url = data.readCString();
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 67a66a2..0fc6a8a 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -108,7 +108,7 @@
}
-status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player)
+status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
{
status_t err = UNKNOWN_ERROR;
sp<IMediaPlayer> p;
@@ -117,7 +117,7 @@
if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
(mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
- LOGE("setDataSource called in state %d", mCurrentState);
+ LOGE("attachNewPlayer called in state %d", mCurrentState);
return INVALID_OPERATION;
}
@@ -147,9 +147,11 @@
if (url != NULL) {
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
- sp<IMediaPlayer> player(
- service->create(getpid(), this, url, headers, mAudioSessionId));
- err = setDataSource(player);
+ sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
+ err = attachNewPlayer(player);
+ if (err == NO_ERROR) {
+ err = mPlayer->setDataSource(url, headers);
+ }
}
}
return err;
@@ -161,8 +163,26 @@
status_t err = UNKNOWN_ERROR;
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
- sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length, mAudioSessionId));
- err = setDataSource(player);
+ sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
+ err = attachNewPlayer(player);
+ if (err == NO_ERROR) {
+ err = mPlayer->setDataSource(fd, offset, length);
+ }
+ }
+ return err;
+}
+
+status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)
+{
+ LOGV("setDataSource");
+ status_t err = UNKNOWN_ERROR;
+ const sp<IMediaPlayerService>& service(getMediaPlayerService());
+ if (service != 0) {
+ sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
+ err = attachNewPlayer(player);
+ if (err == NO_ERROR) {
+ err = mPlayer->setDataSource(source);
+ }
}
return err;
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 2051b3b..0386d4b 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -176,6 +176,16 @@
namespace android {
+static bool checkPermission(const char* permissionString) {
+#ifndef HAVE_ANDROID_OS
+ return true;
+#endif
+ if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+ bool ok = checkCallingPermission(String16(permissionString));
+ if (!ok) LOGE("Request requires %s", permissionString);
+ return ok;
+}
+
// TODO: Temp hack until we can register players
typedef struct {
const char *extension;
@@ -245,31 +255,8 @@
return retriever;
}
-sp<IMediaPlayer> MediaPlayerService::create(
- pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,
- const KeyedVector<String8, String8> *headers, int audioSessionId)
-{
- int32_t connId = android_atomic_inc(&mNextConnId);
-
- sp<Client> c = new Client(
- this, pid, connId, client, audioSessionId,
- IPCThreadState::self()->getCallingUid());
-
- LOGV("Create new client(%d) from pid %d, uid %d, url=%s, connId=%d, audioSessionId=%d",
- connId, pid, IPCThreadState::self()->getCallingUid(), url, connId, audioSessionId);
- if (NO_ERROR != c->setDataSource(url, headers))
- {
- c.clear();
- return c;
- }
- wp<Client> w = c;
- Mutex::Autolock lock(mLock);
- mClients.add(w);
- return c;
-}
-
sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client,
- int fd, int64_t offset, int64_t length, int audioSessionId)
+ int audioSessionId)
{
int32_t connId = android_atomic_inc(&mNextConnId);
@@ -277,40 +264,14 @@
this, pid, connId, client, audioSessionId,
IPCThreadState::self()->getCallingUid());
- LOGV("Create new client(%d) from pid %d, uid %d, fd=%d, offset=%lld, "
- "length=%lld, audioSessionId=%d", connId, pid,
- IPCThreadState::self()->getCallingUid(), fd, offset, length, audioSessionId);
- if (NO_ERROR != c->setDataSource(fd, offset, length)) {
- c.clear();
- } else {
- wp<Client> w = c;
+ LOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
+ IPCThreadState::self()->getCallingUid());
+
+ wp<Client> w = c;
+ {
Mutex::Autolock lock(mLock);
mClients.add(w);
}
- ::close(fd);
- return c;
-}
-
-sp<IMediaPlayer> MediaPlayerService::create(
- pid_t pid, const sp<IMediaPlayerClient> &client,
- const sp<IStreamSource> &source, int audioSessionId) {
- int32_t connId = android_atomic_inc(&mNextConnId);
-
- sp<Client> c = new Client(
- this, pid, connId, client, audioSessionId,
- IPCThreadState::self()->getCallingUid());
-
- LOGV("Create new client(%d) from pid %d, audioSessionId=%d",
- connId, pid, audioSessionId);
-
- if (OK != c->setDataSource(source)) {
- c.clear();
- } else {
- wp<Client> w = c;
- Mutex::Autolock lock(mLock);
- mClients.add(w);
- }
-
return c;
}
@@ -701,6 +662,14 @@
if (url == NULL)
return UNKNOWN_ERROR;
+ if ((strncmp(url, "http://", 7) == 0) ||
+ (strncmp(url, "https://", 8) == 0) ||
+ (strncmp(url, "rtsp://", 7) == 0)) {
+ if (!checkPermission("android.permission.INTERNET")) {
+ return PERMISSION_DENIED;
+ }
+ }
+
if (strncmp(url, "content://", 10) == 0) {
// get a filedescriptor for the content Uri and
// pass it to the setDataSource(fd) method
@@ -781,6 +750,7 @@
// now set data source
mStatus = p->setDataSource(fd, offset, length);
if (mStatus == NO_ERROR) mPlayer = p;
+
return mStatus;
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index e32b92a..53e625a 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -188,16 +188,7 @@
void removeMediaRecorderClient(wp<MediaRecorderClient> client);
virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid);
- // House keeping for media player clients
- virtual sp<IMediaPlayer> create(
- pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,
- const KeyedVector<String8, String8> *headers, int audioSessionId);
-
- virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length, int audioSessionId);
-
- virtual sp<IMediaPlayer> create(
- pid_t pid, const sp<IMediaPlayerClient> &client,
- const sp<IStreamSource> &source, int audioSessionId);
+ virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int audioSessionId);
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
@@ -284,13 +275,13 @@
sp<MediaPlayerBase> createPlayer(player_type playerType);
- status_t setDataSource(
+ virtual status_t setDataSource(
const char *url,
const KeyedVector<String8, String8> *headers);
- status_t setDataSource(int fd, int64_t offset, int64_t length);
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
- status_t setDataSource(const sp<IStreamSource> &source);
+ virtual status_t setDataSource(const sp<IStreamSource> &source);
static void notify(void* cookie, int msg,
int ext1, int ext2, const Parcel *obj);
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index f2f3500..0794f57 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -110,6 +110,8 @@
}
status_t FileSource::getSize(off64_t *size) {
+ Mutex::Autolock autoLock(mLock);
+
if (mFd < 0) {
return NO_INIT;
}
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index e99888c..0d17b55 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -37,7 +37,6 @@
android:layout_alignParentTop="true"
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
android:scaleType="center"
- android:clickable="true"
android:background="@drawable/recents_thumbnail_overlay">
<ImageView android:id="@+id/app_thumbnail_image"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index 73ca335..84c89f7 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -33,7 +33,6 @@
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
- android:clickable="true"
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
android:scaleType="center"
android:background="@drawable/recents_thumbnail_overlay">
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
index dd25cf9..ed9ea7a 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
@@ -38,6 +38,7 @@
android:orientation="horizontal"
android:clipChildren="false"
android:layout_marginTop="@*android:dimen/status_bar_height">
+
<com.android.systemui.recent.RecentsVerticalScrollView
android:id="@+id/recents_container"
android:layout_width="match_parent"
@@ -62,7 +63,6 @@
</com.android.systemui.recent.RecentsVerticalScrollView>
-
</LinearLayout>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index cab90fd..9dc6378 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -29,7 +29,6 @@
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
- android:clickable="true"
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
android:scaleType="center"
android:background="@drawable/recents_thumbnail_overlay">
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 14743f4..1ebdfa1 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -196,7 +196,11 @@
final View animView = mCallback.getChildContentView(view);
final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
float newPos;
- if (velocity < 0 || (velocity == 0 && getTranslation(animView) < 0)) {
+
+ if (velocity < 0
+ || (velocity == 0 && getTranslation(animView) < 0)
+ // if we use the Menu to dismiss an item in landscape, animate up
+ || (velocity == 0 && getTranslation(animView) == 0 && mSwipeDirection == Y)) {
newPos = -getSize(animView);
} else {
newPos = getSize(animView);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
index 2de4185..e3c4eb7 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
@@ -28,6 +28,7 @@
void handleSwipe(View selectedView);
void handleLongPress(View selectedView, View anchorView);
void handleShowBackground(boolean show);
+ void dismiss();
// TODO: find another way to get this info from RecentsPanelView
boolean isRecentsVisible();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index e59c109..d7bb3c4 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -243,8 +243,11 @@
}
}
+ public void dismiss() {
+ hide(true);
+ }
+
public void hide(boolean animate) {
- mShowing = false;
if (!animate) {
setVisibility(View.GONE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 3acef08..1978d69 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -84,15 +84,26 @@
if (old == null) {
view.setClickable(true);
view.setOnLongClickListener(mOnLongClick);
-
- final View thumbnail = view.findViewById(R.id.app_thumbnail);
- // thumbnail is set to clickable in the layout file
- thumbnail.setOnClickListener(new OnClickListener() {
+ view.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
- mCallback.handleOnClick(view);
+ mCallback.dismiss();
}
});
+ OnClickListener launchAppListener = new OnClickListener() {
+ public void onClick(View v) {
+ mCallback.handleOnClick(view);
+ }
+ };
+ final View thumbnail = view.findViewById(R.id.app_thumbnail);
+ thumbnail.setClickable(true);
+ thumbnail.setOnClickListener(launchAppListener);
+ final View appTitle = view.findViewById(R.id.app_label);
+ appTitle.setClickable(true);
+ appTitle.setOnClickListener(launchAppListener);
+ final View calloutLine = view.findViewById(R.id.recents_callout_line);
+ calloutLine.setClickable(true);
+ calloutLine.setOnClickListener(launchAppListener);
mLinearLayout.addView(view);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
index d9cb4e8..4a1cafd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
@@ -28,6 +28,10 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
import android.widget.RelativeLayout;
import com.android.systemui.R;
@@ -52,6 +56,8 @@
ViewGroup mContentParent;
TabletStatusBar mBar;
View mClearButton;
+ static Interpolator sAccelerateInterpolator = new AccelerateInterpolator();
+ static Interpolator sDecelerateInterpolator = new DecelerateInterpolator();
// amount to slide mContentParent down by when mContentFrame is missing
float mContentFrameMissingTranslation;
@@ -117,8 +123,13 @@
mShowing = show;
if (show) {
setVisibility(View.VISIBLE);
+ // Don't start the animation until we've created the layer, which is done
+ // right before we are drawn
+ mContentParent.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
+ } else {
+ mChoreo.startAnimation(show);
}
- mChoreo.startAnimation(show);
}
} else {
mShowing = show;
@@ -127,6 +138,20 @@
}
/**
+ * This is used only when we've created a hardware layer and are waiting until it's
+ * been created in order to start the appearing animation.
+ */
+ private ViewTreeObserver.OnPreDrawListener mPreDrawListener =
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ mChoreo.startAnimation(true);
+ return true;
+ }
+ };
+
+ /**
* Whether the panel is showing, or, if it's animating, whether it will be
* when the animation is done.
*/
@@ -330,8 +355,8 @@
AnimatorSet mContentAnim;
// should group this into a multi-property animation
- final static int OPEN_DURATION = 300;
- final static int CLOSE_DURATION = 300;
+ final static int OPEN_DURATION = 250;
+ final static int CLOSE_DURATION = 250;
// the panel will start to appear this many px from the end
final int HYPERSPACE_OFFRAMP = 200;
@@ -362,19 +387,15 @@
Animator posAnim = ObjectAnimator.ofFloat(mContentParent, "translationY",
start, end);
- posAnim.setInterpolator(appearing
- ? new android.view.animation.DecelerateInterpolator(1.0f)
- : new android.view.animation.AccelerateInterpolator(1.0f));
+ posAnim.setInterpolator(appearing ? sDecelerateInterpolator : sAccelerateInterpolator);
if (mContentAnim != null && mContentAnim.isRunning()) {
mContentAnim.cancel();
}
Animator fadeAnim = ObjectAnimator.ofFloat(mContentParent, "alpha",
- mContentParent.getAlpha(), appearing ? 1.0f : 0.0f);
- fadeAnim.setInterpolator(appearing
- ? new android.view.animation.AccelerateInterpolator(2.0f)
- : new android.view.animation.DecelerateInterpolator(2.0f));
+ appearing ? 1.0f : 0.0f);
+ fadeAnim.setInterpolator(appearing ? sAccelerateInterpolator : sDecelerateInterpolator);
mContentAnim = new AnimatorSet();
mContentAnim
@@ -389,8 +410,6 @@
if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
createAnimation(appearing);
-
- mContentParent.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mContentAnim.start();
mVisible = appearing;
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
index 40cc7d8..8654a25 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
@@ -589,6 +589,11 @@
public void onPhoneStateChanged(String newState) {
updateEmergencyCallButtonState();
}
+
+ /** {@inheritDoc} */
+ public void onClockVisibilityChanged() {
+ // ignored
+ }
};
private SimStateCallback mSimStateCallback = new SimStateCallback() {
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
index 2955de3..958f555 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
@@ -81,6 +81,8 @@
private int mFailedAttempts = 0;
+ private boolean mClockVisible;
+
private Handler mHandler;
private ArrayList<InfoCallback> mInfoCallbacks = Lists.newArrayList();
@@ -94,6 +96,7 @@
private static final int MSG_SIM_STATE_CHANGE = 304;
private static final int MSG_RINGER_MODE_CHANGED = 305;
private static final int MSG_PHONE_STATE_CHANGED = 306;
+ private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307;
/**
* When we receive a
@@ -170,6 +173,9 @@
case MSG_PHONE_STATE_CHANGED:
handlePhoneStateChanged((String)msg.obj);
break;
+ case MSG_CLOCK_VISIBILITY_CHANGED:
+ handleClockVisibilityChanged();
+ break;
}
}
};
@@ -334,6 +340,13 @@
}
}
+ private void handleClockVisibilityChanged() {
+ if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()");
+ for (int i = 0; i < mInfoCallbacks.size(); i++) {
+ mInfoCallbacks.get(i).onClockVisibilityChanged();
+ }
+ }
+
/**
* @param status One of the statuses of {@link android.os.BatteryManager}
* @return Whether the status maps to a status for being plugged in.
@@ -448,6 +461,12 @@
*/
void onPhoneStateChanged(String newState);
+ /**
+ * Called when visibility of lockscreen clock changes, such as when
+ * obscured by a widget.
+ */
+ void onClockVisibilityChanged();
+
}
/**
@@ -484,6 +503,11 @@
}
}
+ public void reportClockVisible(boolean visible) {
+ mClockVisible = visible;
+ mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget();
+ }
+
public IccCard.State getSimState() {
return mSimState;
}
@@ -546,4 +570,8 @@
mFailedAttempts++;
}
+ public boolean isClockVisible() {
+ return mClockVisible;
+ }
+
}
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index a544167..2a34f18 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -92,7 +92,7 @@
* thread of the keyguard.
*/
public class KeyguardViewMediator implements KeyguardViewCallback,
- KeyguardUpdateMonitor.SimStateCallback {
+ KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback {
private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
private final static boolean DEBUG = false;
private final static boolean DBG_WAKE = false;
@@ -284,6 +284,7 @@
mUpdateMonitor = new KeyguardUpdateMonitor(context);
+ mUpdateMonitor.registerInfoCallback(this);
mUpdateMonitor.registerSimStateCallback(this);
mLockPatternUtils = new LockPatternUtils(mContext);
@@ -1190,9 +1191,12 @@
flags |= StatusBarManager.DISABLE_NAVIGATION;
if (!mHidden) {
// showing lockscreen exclusively (no activities in front of it)
- // disable clock and back button too
+ // disable back button too
flags |= StatusBarManager.DISABLE_BACK;
- flags |= StatusBarManager.DISABLE_CLOCK;
+ if (mUpdateMonitor.isClockVisible()) {
+ // lockscreen showing a clock, so hide statusbar clock
+ flags |= StatusBarManager.DISABLE_CLOCK;
+ }
}
if (isSecure() || !ENABLE_INSECURE_STATUS_BAR_EXPAND) {
// showing secure lockscreen; disable expanding.
@@ -1283,4 +1287,34 @@
mKeyguardViewManager.onScreenTurnedOn();
}
}
+
+ /** {@inheritDoc} */
+ public void onClockVisibilityChanged() {
+ adjustStatusBarLocked();
+ }
+
+ /** {@inheritDoc} */
+ public void onPhoneStateChanged(String newState) {
+ // ignored
+ }
+
+ /** {@inheritDoc} */
+ public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) {
+ // ignored
+ }
+
+ /** {@inheritDoc} */
+ public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
+ // ignored
+ }
+
+ /** {@inheritDoc} */
+ public void onRingerModeChanged(int state) {
+ // ignored
+ }
+
+ /** {@inheritDoc} */
+ public void onTimeChanged() {
+ // ignored
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 9c14734..62abf20 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -21,6 +21,7 @@
import com.android.internal.telephony.IccCard;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockScreenWidgetCallback;
+import com.android.internal.widget.LockScreenWidgetInterface;
import com.android.internal.widget.TransportControlView;
import android.accounts.Account;
@@ -191,11 +192,17 @@
public void requestShow(View view) {
if (DEBUG) Log.v(TAG, "View " + view + " requested show transports");
view.setVisibility(View.VISIBLE);
+
+ // TODO: examine all widgets to derive clock status
+ mUpdateMonitor.reportClockVisible(false);
}
public void requestHide(View view) {
if (DEBUG) Log.v(TAG, "View " + view + " requested hide transports");
view.setVisibility(View.GONE);
+
+ // TODO: examine all widgets to derive clock status
+ mUpdateMonitor.reportClockVisible(true);
}
};
@@ -743,6 +750,7 @@
if (tcv == null) {
if (DEBUG) Log.w(TAG, "Couldn't find transport control widget");
} else {
+ mUpdateMonitor.reportClockVisible(true);
tcv.setVisibility(View.GONE); // hide tcv until we get the callback below to show it.
tcv.setCallback(mWidgetCallback);
}
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index 5429c0c..f0b5958 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -137,3 +137,10 @@
# [ 8- 3] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
# [ 2- 0] Network type (as defined by ConnectivityManager)
50020 connectivity_state_changed (custom|1|5)
+
+
+# ---------------------------
+# NetworkStatsService.java
+# ---------------------------
+51100 netstats_mobile_sample (iface_rx|2|2),(iface_tx|2|2),(uid_rx|2|2),(uid_tx|2|2)
+51101 netstats_wifi_sample (iface_rx|2|2),(iface_tx|2|2),(uid_rx|2|2),(uid_tx|2|2)
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index bb831f5..0e1a1e3 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -655,7 +655,7 @@
List<InputMethodSubtype> enabledSubtypes =
mSettings.getEnabledInputMethodSubtypeListLocked(imi);
if (allowsImplicitlySelectedSubtypes && enabledSubtypes.isEmpty()) {
- enabledSubtypes = getApplicableSubtypesLocked(mRes, getSubtypes(imi));
+ enabledSubtypes = getImplicitlyApplicableSubtypesLocked(mRes, imi);
}
return InputMethodSubtype.sort(mContext, 0, imi, enabledSubtypes);
}
@@ -1668,13 +1668,13 @@
}
@Override
- public boolean setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
+ public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
// By this IPC call, only a process which shares the same uid with the IME can add
// additional input method subtypes to the IME.
- if (TextUtils.isEmpty(imiId) || subtypes == null || subtypes.length == 0) return false;
+ if (TextUtils.isEmpty(imiId) || subtypes == null || subtypes.length == 0) return;
synchronized (mMethodMap) {
final InputMethodInfo imi = mMethodMap.get(imiId);
- if (imi == null) return false;
+ if (imi == null) return;
final PackageManager pm = mContext.getPackageManager();
final String[] packageInfos = pm.getPackagesForUid(Binder.getCallingUid());
if (packageInfos != null) {
@@ -1688,12 +1688,12 @@
} finally {
Binder.restoreCallingIdentity(ident);
}
- return true;
+ return;
}
}
}
}
- return false;
+ return;
}
private void setInputMethodWithSubtypeId(IBinder token, String id, int subtypeId) {
@@ -1903,6 +1903,20 @@
return subtypes;
}
+
+ private static ArrayList<InputMethodSubtype> getOverridingImplicitlyEnabledSubtypes(
+ InputMethodInfo imi, String mode) {
+ ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final int subtypeCount = imi.getSubtypeCount();
+ for (int i = 0; i < subtypeCount; ++i) {
+ final InputMethodSubtype subtype = imi.getSubtypeAt(i);
+ if (subtype.overridesImplicitlyEnabledSubtype() && subtype.getMode().equals(mode)) {
+ subtypes.add(subtype);
+ }
+ }
+ return subtypes;
+ }
+
private boolean chooseNewDefaultIMELocked() {
List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
if (enabled != null && enabled.size() > 0) {
@@ -2357,8 +2371,9 @@
return NOT_A_SUBTYPE_ID;
}
- private static ArrayList<InputMethodSubtype> getApplicableSubtypesLocked(
- Resources res, List<InputMethodSubtype> subtypes) {
+ private static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
+ Resources res, InputMethodInfo imi) {
+ final List<InputMethodSubtype> subtypes = getSubtypes(imi);
final String systemLocale = res.getConfiguration().locale.toString();
if (TextUtils.isEmpty(systemLocale)) return new ArrayList<InputMethodSubtype>();
HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap =
@@ -2366,6 +2381,19 @@
final int N = subtypes.size();
boolean containsKeyboardSubtype = false;
for (int i = 0; i < N; ++i) {
+ // scan overriding implicitly enabled subtypes.
+ InputMethodSubtype subtype = subtypes.get(i);
+ if (subtype.overridesImplicitlyEnabledSubtype()) {
+ final String mode = subtype.getMode();
+ if (!applicableModeAndSubtypesMap.containsKey(mode)) {
+ applicableModeAndSubtypesMap.put(mode, subtype);
+ }
+ }
+ }
+ if (applicableModeAndSubtypesMap.size() > 0) {
+ return new ArrayList<InputMethodSubtype>(applicableModeAndSubtypesMap.values());
+ }
+ for (int i = 0; i < N; ++i) {
InputMethodSubtype subtype = subtypes.get(i);
final String locale = subtype.getLocale();
final String mode = subtype.getMode();
@@ -2489,16 +2517,21 @@
subtype = findLastResortApplicableSubtypeLocked(
mRes, enabledSubtypes, mode, null, true);
}
+ final ArrayList<InputMethodSubtype> overridingImplicitlyEnabledSubtypes =
+ getOverridingImplicitlyEnabledSubtypes(imi, mode);
+ final ArrayList<InputMethodSubtype> subtypesForSearch =
+ overridingImplicitlyEnabledSubtypes.isEmpty()
+ ? getSubtypes(imi) : overridingImplicitlyEnabledSubtypes;
// 4. Search by the current subtype's locale from all subtypes.
if (subtype == null && mCurrentSubtype != null) {
subtype = findLastResortApplicableSubtypeLocked(
- mRes, getSubtypes(imi), mode, mCurrentSubtype.getLocale(), false);
+ mRes, subtypesForSearch, mode, mCurrentSubtype.getLocale(), false);
}
// 5. Search by the system locale from all subtypes.
// 6. Search the first enabled subtype matched with mode from all subtypes.
if (subtype == null) {
subtype = findLastResortApplicableSubtypeLocked(
- mRes, getSubtypes(imi), mode, null, true);
+ mRes, subtypesForSearch, mode, null, true);
}
if (subtype != null) {
if (imiId.equals(mCurMethodId)) {
@@ -2945,12 +2978,12 @@
if (explicitlyEnabledSubtypes.size() == 0) {
// If there are no explicitly enabled subtypes, applicable subtypes are
// enabled implicitly.
- InputMethodInfo ime = mMethodMap.get(imeId);
+ InputMethodInfo imi = mMethodMap.get(imeId);
// If IME is enabled and no subtypes are enabled, applicable subtypes
// are enabled implicitly, so needs to treat them to be enabled.
- if (ime != null && ime.getSubtypeCount() > 0) {
+ if (imi != null && imi.getSubtypeCount() > 0) {
List<InputMethodSubtype> implicitlySelectedSubtypes =
- getApplicableSubtypesLocked(mRes, getSubtypes(ime));
+ getImplicitlyApplicableSubtypesLocked(mRes, imi);
if (implicitlySelectedSubtypes != null) {
final int N = implicitlySelectedSubtypes.size();
for (int i = 0; i < N; ++i) {
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 85d8cece..1497511 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -1033,6 +1033,38 @@
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
final NetworkStats.Entry entry = new NetworkStats.Entry();
+ final HashSet<String> knownIfaces = Sets.newHashSet();
+ final HashSet<String> activeIfaces = Sets.newHashSet();
+
+ // collect any historical stats and active state
+ // TODO: migrate to reading from single file
+ if (mBandwidthControlEnabled) {
+ for (String iface : fileListWithoutNull(mStatsXtIface)) {
+ final File ifacePath = new File(mStatsXtIface, iface);
+
+ final long active = readSingleLongFromFile(new File(ifacePath, "active"));
+ if (active == 1) {
+ knownIfaces.add(iface);
+ activeIfaces.add(iface);
+ } else if (active == 0) {
+ knownIfaces.add(iface);
+ } else {
+ continue;
+ }
+
+ entry.iface = iface;
+ entry.uid = UID_ALL;
+ entry.set = SET_DEFAULT;
+ entry.tag = TAG_NONE;
+ entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
+ entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
+ entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
+ entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
+
+ stats.addValues(entry);
+ }
+ }
+
final ArrayList<String> values = Lists.newArrayList();
BufferedReader reader = null;
@@ -1058,7 +1090,13 @@
entry.txBytes = Long.parseLong(values.get(9));
entry.txPackets = Long.parseLong(values.get(10));
- stats.addValues(entry);
+ if (activeIfaces.contains(entry.iface)) {
+ // combine stats when iface is active
+ stats.combineValues(entry);
+ } else if (!knownIfaces.contains(entry.iface)) {
+ // add stats when iface is unknown
+ stats.addValues(entry);
+ }
} catch (NumberFormatException e) {
Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
}
@@ -1073,24 +1111,6 @@
IoUtils.closeQuietly(reader);
}
- // splice in historical stats not reflected in mStatsIface
- if (mBandwidthControlEnabled) {
- for (String iface : fileListWithoutNull(mStatsXtIface)) {
- final File ifacePath = new File(mStatsXtIface, iface);
-
- entry.iface = iface;
- entry.uid = UID_ALL;
- entry.set = SET_DEFAULT;
- entry.tag = TAG_NONE;
- entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
- entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
- entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
- entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
-
- stats.combineValues(entry);
- }
- }
-
return stats;
}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index cbd986f..bbc26d6 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -853,6 +853,14 @@
if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
int oldWakeLockState = mWakeLockState;
mWakeLockState = mLocks.reactivateScreenLocksLocked();
+
+ // Disable proximity sensor if if user presses power key while we are in the
+ // "waiting for proximity sensor to go negative" state.
+ if ((mWakeLockState & SCREEN_ON_BIT) != 0
+ && mProximitySensorActive && mProximityWakeLockCount == 0) {
+ mProximitySensorActive = false;
+ }
+
if (mSpew) {
Slog.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState)
+ " mWakeLockState=0x"
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index e0dc96f..4d54fd4 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -31,6 +31,8 @@
import static android.net.NetworkStats.SET_FOREGROUND;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
+import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateWifi;
import static android.net.TrafficStats.UID_REMOVED;
import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
@@ -76,6 +78,7 @@
import android.os.SystemClock;
import android.provider.Settings;
import android.telephony.TelephonyManager;
+import android.util.EventLog;
import android.util.NtpTrustedTime;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -83,6 +86,7 @@
import com.android.internal.os.AtomicFile;
import com.android.internal.util.Objects;
+import com.android.server.EventLogTags;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
@@ -387,7 +391,9 @@
entry.uid = UID_ALL;
entry.tag = TAG_NONE;
entry.rxBytes = historyEntry.rxBytes;
+ entry.rxPackets = historyEntry.rxPackets;
entry.txBytes = historyEntry.txBytes;
+ entry.txPackets = historyEntry.txPackets;
stats.combineValues(entry);
}
@@ -716,6 +722,11 @@
Slog.v(TAG, "performPollLocked() took " + duration + "ms");
}
+ // sample stats after detailed poll
+ if (detailedPoll) {
+ performSample();
+ }
+
// finally, dispatch updated event to any listeners
final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED);
updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -809,6 +820,33 @@
}
/**
+ * Sample recent statistics summary into {@link EventLog}.
+ */
+ private void performSample() {
+ // take sample as total over last 4 hours
+ final long end = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
+ final long start = end - (4 * HOUR_IN_MILLIS);
+
+ NetworkTemplate template = null;
+ NetworkStats.Entry ifaceTotal = null;
+ NetworkStats.Entry uidTotal = null;
+
+ // collect mobile sample
+ template = buildTemplateMobileAll(getActiveSubscriberId(mContext));
+ ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal);
+ uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
+ EventLogTags.writeNetstatsMobileSample(
+ ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes);
+
+ // collect wifi sample
+ template = buildTemplateWifi();
+ ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal);
+ uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
+ EventLogTags.writeNetstatsWifiSample(
+ ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes);
+ }
+
+ /**
* Clean up {@link #mUidStats} after UID is removed.
*/
private void removeUidLocked(int uid) {
@@ -1249,6 +1287,12 @@
}
};
+ private static String getActiveSubscriberId(Context context) {
+ final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ return telephony.getSubscriberId();
+ }
+
/**
* Key uniquely identifying a {@link NetworkStatsHistory} for a UID.
*/
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
index ecf78d9..2a25866 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
@@ -106,6 +106,7 @@
public void testNetworkStatsSummaryDown() throws Exception {
stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
+ stageLong(1L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/active"));
stageLong(1024L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/rx_bytes"));
stageLong(128L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/rx_packets"));
stageLong(2048L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/tx_bytes"));
@@ -119,6 +120,7 @@
public void testNetworkStatsCombined() throws Exception {
stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
+ stageLong(1L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/active"));
stageLong(10L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/rx_bytes"));
stageLong(20L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/rx_packets"));
stageLong(30L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_bytes"));
@@ -129,6 +131,18 @@
2205L + 20L, 489339L + 30L, 2237L + 40L);
}
+ public void testNetworkStatsCombinedInactive() throws Exception {
+ stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
+ stageLong(0L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/active"));
+ stageLong(10L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/rx_bytes"));
+ stageLong(20L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/rx_packets"));
+ stageLong(30L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_bytes"));
+ stageLong(40L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_packets"));
+
+ final NetworkStats stats = mService.getNetworkStatsSummary();
+ assertStatsEntry(stats, "rmnet0", UID_ALL, SET_DEFAULT, TAG_NONE, 10L, 20L, 30L, 40L);
+ }
+
public void testKernelTags() throws Exception {
assertEquals("0", tagToKernel(0x0));
assertEquals("214748364800", tagToKernel(0x32));
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index 23e0ca1..2a52888 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -107,10 +107,9 @@
}
- public boolean setAdditionalInputMethodSubtypes(String arg0, InputMethodSubtype[] arg1)
+ public void setAdditionalInputMethodSubtypes(String arg0, InputMethodSubtype[] arg1)
throws RemoteException {
// TODO Auto-generated method stub
- return false;
}
public boolean setCurrentInputMethodSubtype(InputMethodSubtype arg0) throws RemoteException {
@@ -187,11 +186,4 @@
// TODO Auto-generated method stub
return null;
}
-
- public boolean setAdditionalInputMethodSubtypes(IBinder arg0, InputMethodSubtype[] arg1)
- throws RemoteException {
- // TODO Auto-generated method stub
- return false;
- }
-
}
diff --git a/wifi/java/android/net/wifi/WpsConfiguration.java b/wifi/java/android/net/wifi/WpsConfiguration.java
index 2e7689a..0c2adfd 100644
--- a/wifi/java/android/net/wifi/WpsConfiguration.java
+++ b/wifi/java/android/net/wifi/WpsConfiguration.java
@@ -46,16 +46,21 @@
public Setup setup;
+ /** @hide */
public String BSSID;
public String pin;
+ /** @hide */
public IpAssignment ipAssignment;
+ /** @hide */
public ProxySettings proxySettings;
+ /** @hide */
public LinkProperties linkProperties;
+ /** @hide */
public WpsConfiguration() {
setup = Setup.INVALID;
BSSID = null;
@@ -65,6 +70,7 @@
linkProperties = new LinkProperties();
}
+ /** @hide */
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append(" setup: ").append(setup.toString());
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index 2d57363..686d698 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -28,11 +28,6 @@
public class WifiP2pConfig implements Parcelable {
/**
- * Device name
- */
- public String deviceName;
-
- /**
* Device address
*/
public String deviceAddress;
@@ -53,6 +48,7 @@
/**
* Indicates whether the configuration is saved
+ * @hide
*/
public enum Persist {
SYSTEM_DEFAULT,
@@ -60,6 +56,7 @@
NO
}
+ /** @hide */
public Persist persist = Persist.SYSTEM_DEFAULT;
public WifiP2pConfig() {
@@ -110,7 +107,6 @@
public String toString() {
StringBuffer sbuf = new StringBuffer();
- sbuf.append("Device: ").append(deviceName);
sbuf.append("\n address: ").append(deviceAddress);
sbuf.append("\n wps: ").append(wpsConfig);
sbuf.append("\n groupOwnerIntent: ").append(groupOwnerIntent);
@@ -132,7 +128,6 @@
/** Implement the Parcelable interface {@hide} */
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(deviceName);
dest.writeString(deviceAddress);
dest.writeParcelable(wpsConfig, flags);
dest.writeInt(groupOwnerIntent);
@@ -144,7 +139,6 @@
new Creator<WifiP2pConfig>() {
public WifiP2pConfig createFromParcel(Parcel in) {
WifiP2pConfig config = new WifiP2pConfig();
- config.deviceName = in.readString();
config.deviceAddress = in.readString();
config.wpsConfig = (WpsConfiguration) in.readParcelable(null);
config.groupOwnerIntent = in.readInt();
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index ca6e4d5..14246b4 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -69,7 +69,7 @@
}
/**
- * @param string formats supported include
+ * @param supplicantEvent formats supported include
*
* P2P-GROUP-STARTED p2p-wlan0-0 [client|GO] ssid="DIRECT-W8" freq=2437
* [psk=2182b2e50e53f260d04f3c7b25ef33c965a3291b9b36b455a82d77fd82ca15bc|
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
index 9dc2fbf..a02175e 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
@@ -34,9 +34,11 @@
public InetAddress groupOwnerAddress;
- public WifiP2pInfo() {
+ /** @hide */
+ WifiP2pInfo() {
}
+ /** @hide */
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("groupFormed: ").append(groupFormed)
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 25daf1c..0bdd269 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -35,25 +35,64 @@
import com.android.internal.util.Protocol;
/**
- * This class provides the API for managing Wi-Fi p2p
- * connectivity. Get an instance of this class by calling
- * {@link android.content.Context#getSystemService(String)
+ * This class provides the API for managing Wi-Fi peer-to-peer connectivity. This lets an
+ * application discover available peers, setup connection to peers and query for the list of peers.
+ * When a p2p connection is formed over wifi, the device continues to maintain the uplink
+ * connection over mobile or any other available network for internet connectivity on the device.
+ *
+ * <p> The API is asynchronous and response to a request from an application is sent in the form
+ * of a {@link android.os.Message} on a {@link android.os.Handler} that needs to be initialized
+ * by the application right at the beginning before any p2p operations are performed via
+ * {@link #initialize}.
+ *
+ * <p> An application can request for the current list of peers using {@link #requestPeers}. The
+ * {@link #RESPONSE_PEERS} message on the handler indicates that the peer list is available.
+ * Use {@link #peersInResponse} to extract the peer device list upon the receiving the
+ * {@link #RESPONSE_PEERS} message.
+ *
+ * <p> If an application needs to initiate a discovery, use {@link #discoverPeers} and listen
+ * to {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent action to initiate a request to fetch
+ * list of peers with {@link #requestPeers}. An initiated discovery request from an application
+ * stays active until the device starts connecting to a peer or forms a p2p group.
+ *
+ * <p> An application can initiate a connection request to a peer through {@link #connect}. See
+ * {@link WifiP2pConfig} for details on setting up the configuration. For communication with legacy
+ * Wi-Fi devices that do not support p2p, an app can create a group using {@link #createGroup}
+ * which creates an access point whose details can be fetched with {@link #requestGroupInfo}.
+ *
+ * <p> After a successful group formation through {@link #createGroup} or through {@link #connect},
+ * use {@link #requestConnectionInfo} to fetch the connection details. Connection information
+ * can be obtained with {@link #connectionInfoInResponse} on a {@link #RESPONSE_CONNECTION_INFO}
+ * message. The connection info {@link WifiP2pInfo} contains the address of the group owner
+ * {@link WifiP2pInfo#groupOwnerAddress} and a flag {@link #WifiP2pInfo#isGroupOwner} to indicate
+ * if the current device is a p2p group owner. A p2p client can thus communicate with
+ * the p2p group owner through a socket connection.
+ *
+ * <p> Android has no platform support for service discovery yet, so applications could
+ * run a service discovery protocol to discover services on the peer-to-peer netework.
+ *
+ * <p class="note"><strong>Note:</strong>
+ * Registering an application handler with {@link #initialize} requires the permissions
+ * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and
+ * {@link android.Manifest.permission#CHANGE_WIFI_STATE} to perform any further peer-to-peer
+ * operations.
+ *
+ * Get an instance of this class by calling {@link android.content.Context#getSystemService(String)
* Context.getSystemService(Context.WIFI_P2P_SERVICE)}.
*
- * It deals with the following:
- * <ul>
- * <li>Wi-Fi peer discovery and connection setup. Allows applications to initiate a discovery to
- * find available peers and then setup a connection </li>
- * <li>Configuration and status query. Allows applications to fetch the current list
- * of available and connected peers and query connection status </li>
- * <li>Intent actions that are broadcast to track operations
- * on a p2p connection</li>
- * </ul>
+ * {@see WifiP2pConfig}
+ * {@see WifiP2pInfo}
+ * {@see WifiP2pGroup}
+ * {@see WifiP2pDevice}
+ * {@see WifiP2pDeviceList}
* @hide
*/
public class WifiP2pManager {
/**
- * Broadcast intent action to indicate whether Wi-Fi p2p is enabled or disabled.
+ * Broadcast intent action to indicate whether Wi-Fi p2p is enabled or disabled. An
+ * extra {@link #EXTRA_WIFI_STATE} provides the state information as int.
+ *
+ * @see #EXTRA_WIFI_STATE
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String WIFI_P2P_STATE_CHANGED_ACTION =
@@ -72,7 +111,6 @@
* Wi-Fi p2p is disabled.
*
* @see #WIFI_P2P_STATE_CHANGED_ACTION
- * @see #getWifiP2pState()
*/
public static final int WIFI_P2P_STATE_DISABLED = 1;
@@ -80,14 +118,16 @@
* Wi-Fi p2p is enabled.
*
* @see #WIFI_P2P_STATE_CHANGED_ACTION
- * @see #getWifiP2pState()
*/
public static final int WIFI_P2P_STATE_ENABLED = 2;
/**
* Broadcast intent action indicating that the state of Wi-Fi p2p connectivity
- * has changed. One extra provides the new state
- * in the form of a {@link android.net.NetworkInfo} object.
+ * has changed. One extra {@link #EXTRA_WIFI_P2P_INFO} provides the p2p connection info in
+ * the form of a {@link WifiP2pInfo} object. Another extra {@link #EXTRA_NETWORK_INFO} provides
+ * the network info in the form of a {@link android.net.NetworkInfo}.
+ *
+ * @see #EXTRA_WIFI_P2P_INFO
* @see #EXTRA_NETWORK_INFO
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -124,7 +164,8 @@
public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities";
/**
- * Broadcast intent action indicating that the available peer list has changed
+ * Broadcast intent action indicating that the available peer list has changed. Fetch
+ * the changed list of peers with {@link #requestPeers}
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String WIFI_P2P_PEERS_CHANGED_ACTION =
@@ -134,6 +175,7 @@
* Activity Action: Pick a Wi-Fi p2p network to connect to.
* <p>Input: Nothing.
* <p>Output: Nothing.
+ * @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_PICK_WIFI_P2P_NETWORK =
@@ -141,47 +183,169 @@
IWifiP2pManager mService;
- /* AsyncChannel notifications to apps */
- public static final int HANDLER_CONNECTION = AsyncChannel.CMD_CHANNEL_HALF_CONNECTED;
+ /**
+ * Message {@link android.os.Message#what} sent on the application handler specified
+ * at {@link #initialize} indicating the asynchronous channel has disconnected. An
+ * application could choose to reconnect with {@link #initialize}
+ */
public static final int HANDLER_DISCONNECTION = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
+ /** @hide */
public static final int ENABLE_P2P = BASE + 1;
+ /** @hide */
public static final int ENABLE_P2P_FAILED = BASE + 2;
+ /** @hide */
public static final int ENABLE_P2P_SUCCEEDED = BASE + 3;
+ /** @hide */
public static final int DISABLE_P2P = BASE + 4;
+ /** @hide */
public static final int DISABLE_P2P_FAILED = BASE + 5;
+ /** @hide */
public static final int DISABLE_P2P_SUCCEEDED = BASE + 6;
+ /** @hide */
public static final int DISCOVER_PEERS = BASE + 7;
+
+ /**
+ * Message {@link android.os.Message#what} value indicating that the {@link #discoverPeers}
+ * operation failed.
+ * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #P2P_DISABLED}
+ * or {@link #ALREADY_IN_EFFECT}
+ */
public static final int DISCOVER_PEERS_FAILED = BASE + 8;
+ /**
+ * Message {@link android.os.Message#what} value indicating that the {@link #discoverPeers}
+ * operation succeeded.
+ * <p> The application can register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent
+ * to listen for changes in the peer list as a result of the discovery process.
+ */
public static final int DISCOVER_PEERS_SUCCEEDED = BASE + 9;
+ /** @hide */
public static final int CONNECT = BASE + 10;
+
+ /**
+ * Message {@link android.os.Message#what} value indicating that the {@link #connect}
+ * operation failed.
+ * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #P2P_DISABLED}
+ * or {@link #ALREADY_IN_EFFECT}
+ */
public static final int CONNECT_FAILED = BASE + 11;
+ /**
+ * Message {@link android.os.Message#what} value indicating that the {@link #connect}
+ * operation succeeded.
+ * <p> The application can register for {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} intent
+ * to listen for connectivity change as a result of the connect operation
+ */
public static final int CONNECT_SUCCEEDED = BASE + 12;
+ /** @hide */
public static final int CREATE_GROUP = BASE + 13;
+
+ /**
+ * Message {@link android.os.Message#what} value indicating that the {@link #createGroup}
+ * operation failed.
+ * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #P2P_DISABLED}
+ * or {@link #ALREADY_IN_EFFECT}
+ */
public static final int CREATE_GROUP_FAILED = BASE + 14;
+ /**
+ * Message {@link android.os.Message#what} value indicating that the {@link #createGroup}
+ * operation succeeded.
+ * <p> The application can request the group details with {@link #requestGroupInfo}
+ */
public static final int CREATE_GROUP_SUCCEEDED = BASE + 15;
+ /** @hide */
public static final int REMOVE_GROUP = BASE + 16;
+ /**
+ * Message {@link android.os.Message#what} value indicating that the {@link #removeGroup}
+ * operation failed.
+ * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #P2P_DISABLED}
+ * or {@link #ALREADY_IN_EFFECT}
+ */
public static final int REMOVE_GROUP_FAILED = BASE + 17;
+ /**
+ * Message {@link android.os.Message#what} value indicating that the {@link #removeGroup}
+ * operation succeeded.
+ */
public static final int REMOVE_GROUP_SUCCEEDED = BASE + 18;
- public static final int REQUEST_PEERS = BASE + 19;
- public static final int RESPONSE_PEERS = BASE + 20;
-
- public static final int REQUEST_CONNECTION_INFO = BASE + 21;
- public static final int RESPONSE_CONNECTION_INFO = BASE + 22;
-
- /* arg1 values on response messages from the framework */
+ /**
+ * Supported {@link android.os.Message#arg1} value on the following response messages:
+ * {@link #DISCOVER_PEERS_FAILED}, {@link #CONNECT_FAILED}, {@link #CREATE_GROUP_FAILED}
+ * and {@link #REMOVE_GROUP_FAILED}
+ *
+ * <p> This indicates that the reason for failure is because p2p is unsupported on the
+ * device
+ */
public static final int P2P_UNSUPPORTED = 1;
+ /**
+ * Supported {@link android.os.Message#arg1} value on the following response messages:
+ * {@link #DISCOVER_PEERS_FAILED}, {@link #CONNECT_FAILED}, {@link #CREATE_GROUP_FAILED}
+ * and {@link #REMOVE_GROUP_FAILED}
+ *
+ * <p> This indicates that the reason for failure is because p2p is currently disabled
+ * by the user
+ */
+ public static final int P2P_DISABLED = 2;
+
+ /**
+ * Supported {@link android.os.Message#arg1} value on the following response messages:
+ * {@link #DISCOVER_PEERS_FAILED}, {@link #CONNECT_FAILED}, {@link #CREATE_GROUP_FAILED}
+ * and {@link #REMOVE_GROUP_FAILED}
+ *
+ * <p> This indicates that the reason for failure is because the operation is already in
+ * effect
+ */
+ public static final int ALREADY_IN_EFFECT = 3;
+
+
+ /** @hide */
+ public static final int REQUEST_PEERS = BASE + 19;
+ /**
+ * Message {@link android.os.Message#what} delivered on the application hander
+ * in response to a {@link #requestPeers} call from the application.
+ *
+ * <p> Extract a {@link WifiP2pDeviceList} object by calling {@link #peersInResponse}
+ * on the message object
+ */
+ public static final int RESPONSE_PEERS = BASE + 20;
+
+ /** @hide */
+ public static final int REQUEST_CONNECTION_INFO = BASE + 21;
+
+ /**
+ * Message {@link android.os.Message#what} delivered on the application hander
+ * in response to a {@link #requestConnectionInfo} call from the application.
+ *
+ * <p> Extract a {@link WifiP2pInfo} object by calling {@link #connectionInfoInResponse}
+ * on the message object
+ */
+ public static final int RESPONSE_CONNECTION_INFO = BASE + 22;
+
+ /** @hide */
+ public static final int REQUEST_GROUP_INFO = BASE + 23;
+
+ /**
+ * Message {@link android.os.Message#what} delivered on the application hander
+ * in response to a {@link #requestGroupInfo} call from the application.
+ *
+ * <p> Extract a {@link WifiP2pGroup} object by calling {@link #groupInfoInResponse}
+ * on the message object
+ */
+
+ public static final int RESPONSE_GROUP_INFO = BASE + 24;
+
+ /** @hide */
public static final int WPS_PBC = BASE + 23;
+ /** @hide */
public static final int WPS_PIN = BASE + 24;
+ /** @hide */
public static final int WPS_PIN_AVAILABLE = BASE + 25;
/**
@@ -199,7 +363,8 @@
/**
* A channel that connects the application handler to the Wifi framework.
- * All p2p operations are performed on a channel.
+ * Most p2p operations require a Channel as an argument. An instance of Channel is obtained
+ * by doing a call on {@link #initialize}
*/
public class Channel {
Channel(AsyncChannel c) {
@@ -210,10 +375,17 @@
/**
* Registers the application handler with the Wi-Fi framework. This function
- * must be the first to be called before any p2p control or query operations can be performed.
+ * must be the first to be called before any p2p operations are performed.
+ *
+ * <p class="note"><strong>Note:</strong>
+ * The handler registered with the framework should only handle messages
+ * with {@link android.os.Message#what} values defined in this file. Adding application
+ * specific private {@link android.os.Message#what} types should be done on a seperate handler
+ *
* @param srcContext is the context of the source
- * @param srcHandler is the handler on which the source receives messages
- * @return Channel instance that is necessary for performing p2p operations
+ * @param srcHandler is the handler on which the source will receive message responses
+ * asynchronously
+ * @return Channel instance that is necessary for performing any further p2p operations
*/
public Channel initialize(Context srcContext, Handler srcHandler) {
Messenger messenger = getMessenger();
@@ -229,6 +401,7 @@
}
}
+ /** @hide */
public boolean isP2pSupported() {
try {
return mService.isP2pSupported();
@@ -240,6 +413,7 @@
/**
* Sends in a request to the system to enable p2p. This will pop up a dialog
* to the user and upon authorization will enable p2p.
+ * @hide
*/
public void enableP2p(Channel c) {
if (c == null) return;
@@ -249,6 +423,7 @@
/**
* Sends in a request to the system to disable p2p. This will pop up a dialog
* to the user and upon authorization will enable p2p.
+ * @hide
*/
public void disableP2p(Channel c) {
if (c == null) return;
@@ -256,7 +431,22 @@
}
/**
- * Initiates peer discovery
+ * Initiate peer discovery. A discovery process involves scanning for available Wi-Fi peers
+ * for the purpose of establishing a connection.
+ *
+ * <p> The function call immediately returns after sending a discovery request
+ * to the framework. The application handler is notified of a success or failure to initiate
+ * discovery with {@link #DISCOVER_PEERS_SUCCEEDED} or {@link #DISCOVER_PEERS_FAILED}.
+ *
+ * <p> The discovery remains active until a connection is initiated or
+ * a p2p group is formed. Register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent to
+ * determine when the framework notifies of a change as peers are discovered.
+ *
+ * <p> Upon receiving a {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent, an application
+ * can request for the list of peers using {@link #requestPeers} which will deliver a
+ * {@link #RESPONSE_PEERS} message on the application handler. The application can then
+ * extract a {@link WifiP2pDeviceList} object by calling {@link #peersInResponse}
+ * on the message.
*/
public void discoverPeers(Channel c) {
if (c == null) return;
@@ -264,9 +454,23 @@
}
/**
- * Start a p2p connection
+ * Start a p2p connection to a device with the specified configuration.
*
- * @param peer Configuration described in a {@link WifiP2pConfig} object.
+ * <p> The function call immediately returns after sending a connection request
+ * to the framework. The application handler is notified of a success or failure to initiate
+ * connectivity with {@link #CONNECT_SUCCEEDED} or {@link #CONNECT_FAILED}.
+ *
+ * <p> Register for {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} intent to
+ * determine when the framework notifies of a change in connectivity.
+ *
+ * <p> If the current device is not part of a p2p group, a connect request initiates
+ * a group negotiation with the peer.
+ *
+ * <p> If the current device is part of an existing p2p group or has created
+ * a p2p group with {@link #createGroup}, an invitation to join the group is sent to
+ * the peer device.
+ *
+ * @param config options as described in {@link WifiP2pConfig} class.
*/
public void connect(Channel c, WifiP2pConfig config) {
if (c == null) return;
@@ -274,8 +478,20 @@
}
/**
- * Create a p2p group. This is essentially an access point that can accept
- * client connections.
+ * Create a p2p group with the current device as the group owner. This essentially creates
+ * an access point that can accept connections from legacy clients as well as other p2p
+ * devices.
+ * <p> For p2p operation, this would normally not be used unless the current device needs
+ * to form a p2p connection with a legacy client
+ *
+ * <p> The function call immediately returns after sending a group creation request
+ * to the framework. The application handler is notified of a success or failure to create
+ * group with {@link #CREATE_GROUP_SUCCEEDED} or {@link #CREATE_GROUP_FAILED}.
+ *
+ * <p> Application can request for the group details with {@link #requestGroupInfo} which will
+ * deliver a {@link #RESPONSE_GROUP_INFO} message on the application handler. The application
+ * can then extract a {@link WifiP2pGroup} object by calling {@link #groupInfoInResponse}
+ * on the message.
*/
public void createGroup(Channel c) {
if (c == null) return;
@@ -283,8 +499,11 @@
}
/**
- * Remove the current group. This also removes the p2p interface created
- * during group formation.
+ * Remove the current p2p group.
+ *
+ * <p> The function call immediately returns after sending a group removal request
+ * to the framework. The application handler is notified of a success or failure to remove
+ * a group with {@link #REMOVE_GROUP_SUCCEEDED} or {@link #REMOVE_GROUP_FAILED}.
*/
public void removeGroup(Channel c) {
if (c == null) return;
@@ -292,8 +511,9 @@
}
/**
- * Request the list of peers. This returns a RESPONSE_PEERS on the source
- * handler.
+ * Request the current list of peers. This returns a {@link #RESPONSE_PEERS} on the application
+ * handler. The {@link #RESPONSE_PEERS} message on the handler indicates that the peer list is
+ * available. Use {@link #peersInResponse} to extract {@link WifiP2pDeviceList} from the message
*/
public void requestPeers(Channel c) {
if (c == null) return;
@@ -301,15 +521,18 @@
}
/**
- * Fetch device list from a RESPONSE_PEERS message
+ * Upon receiving a {@link #RESPONSE_PEERS} on the application handler, an application
+ * can extract the peer device list using this function.
*/
public WifiP2pDeviceList peersInResponse(Message msg) {
return (WifiP2pDeviceList) msg.obj;
}
/**
- * Request device connection info. This returns a RESPONSE_CONNECTION_INFO on
- * the source handler.
+ * Request device connection info. This returns a {@link #RESPONSE_CONNECTION_INFO} on
+ * the application handler. The {@link #RESPONSE_CONNECTION_INFO} message on the handler
+ * indicates that connection info is available. Use {@link #connectionInfoInResponse} to
+ * extract {@link WifiP2pInfo} from the message.
*/
public void requestConnectionInfo(Channel c) {
if (c == null) return;
@@ -317,12 +540,31 @@
}
/**
- * Fetch p2p connection status from a RESPONSE_CONNECTION_INFO message
+ * Upon receiving a {@link #RESPONSE_CONNECTION_INFO} on the application handler, an application
+ * can extract the connection info using this function.
*/
public WifiP2pInfo connectionInfoInResponse(Message msg) {
return (WifiP2pInfo) msg.obj;
}
+ /**
+ * Request p2p group info. This returns a {@link #RESPONSE_GROUP_INFO} on
+ * the application handler. The {@link #RESPONSE_GROUP_INFO} message on the handler
+ * indicates that group info is available. Use {@link #groupInfoInResponse} to
+ * extract {@link WifiP2pGroup} from the message.
+ */
+ public void requestGroupInfo(Channel c) {
+ if (c == null) return;
+ c.mAsyncChannel.sendMessage(REQUEST_GROUP_INFO);
+ }
+
+ /**
+ * Upon receiving a {@link #RESPONSE_GROUP_INFO} on the application handler, an application
+ * can extract the group info using this function.
+ */
+ public WifiP2pGroup groupInfoInResponse(Message msg) {
+ return (WifiP2pGroup) msg.obj;
+ }
/**
* Get a reference to WifiP2pService handler. This is used to establish
@@ -339,7 +581,6 @@
}
}
-
/**
* Setup DNS connectivity on the current process to the connected Wi-Fi p2p peers
*