diff options
214 files changed, 2506 insertions, 1221 deletions
diff --git a/api/current.txt b/api/current.txt index 4f50bf3..52b28f5 100644 --- a/api/current.txt +++ b/api/current.txt @@ -709,6 +709,7 @@ package android { 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 @@ package android.media { 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); @@ -15610,7 +15611,7 @@ package android.provider { public static final class CalendarContract.Calendars implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.SyncColumns { field public static final java.lang.String CALENDAR_LOCATION = "calendar_location"; field public static final android.net.Uri CONTENT_URI; - field public static final java.lang.String DEFAULT_SORT_ORDER = "displayName"; + field public static final java.lang.String DEFAULT_SORT_ORDER = "calendar_displayName"; field public static final java.lang.String NAME = "name"; } @@ -18463,7 +18464,7 @@ package android.service.textservice { 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(); @@ -20702,7 +20703,6 @@ package android.text.style { public class EasyEditSpan implements android.text.ParcelableSpan { ctor public EasyEditSpan(); - ctor public EasyEditSpan(android.os.Parcel); method public int describeContents(); method public int getSpanTypeId(); method public void writeToParcel(android.os.Parcel, int); @@ -23046,7 +23046,6 @@ package android.view { method public boolean willNotDraw(); field public static android.util.Property ALPHA; field protected static int DEFAULT_TEXT_DIRECTION; - field protected static float DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD; field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0 field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000 field public static final int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000 @@ -24488,7 +24487,7 @@ package android.view.inputmethod { 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); @@ -24533,8 +24532,7 @@ package android.view.inputmethod { } 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); @@ -24545,6 +24543,7 @@ package android.view.inputmethod { 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 @@ int main(int argc, char **argv) { } 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/app/Activity.java b/core/java/android/app/Activity.java index 0e3eaaa..41e3fdf 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -4471,9 +4471,12 @@ public class Activity extends ContextThemeWrapper ManagedCursor mc = mManagedCursors.get(i); if (mc.mReleased || mc.mUpdated) { if (!mc.mCursor.requery()) { - throw new IllegalStateException( - "trying to requery an already closed cursor " - + mc.mCursor); + if (getApplicationInfo().targetSdkVersion + >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + throw new IllegalStateException( + "trying to requery an already closed cursor " + + mc.mCursor); + } } mc.mReleased = false; mc.mUpdated = false; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index e3075d7..8275cbd 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1291,7 +1291,8 @@ public final class ActivityThread { public final boolean queueIdle() { ActivityClientRecord a = mNewActivities; boolean stopProfiling = false; - if (mBoundApplication.profileFd != null && mBoundApplication.autoStopProfiler) { + if (mBoundApplication != null && mBoundApplication.profileFd != null + && mBoundApplication.autoStopProfiler) { stopProfiling = true; } if (a != null) { diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index 496da41..ef6e131 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -191,6 +191,12 @@ public class SyncManager implements OnAccountsUpdateListener { private static final long SYNC_ALARM_TIMEOUT_MIN = 30 * 1000; // 30 seconds private static final long SYNC_ALARM_TIMEOUT_MAX = 2 * 60 * 60 * 1000; // two hours + /** + * The amount of time to wait after attempting a bind before canceling a sync and disabling + * the sync adapter + */ + public static final long BIND_TIMEOUT_MS = 30 * 1000; + public void onAccountsUpdated(Account[] accounts) { // remember if this was the first time this was called after an update final boolean justBootedUp = mAccounts == INITIAL_ACCOUNTS_ARRAY; @@ -1068,6 +1074,9 @@ public class SyncManager implements OnAccountsUpdateListener { pw.print(" - "); pw.print(activeSyncContext.mSyncOperation.dump(false)); pw.println(); + if (activeSyncContext.mSyncAdapter == null) { + pw.println(" **** Waiting for onServiceConnected ****"); + } } synchronized (mSyncQueue) { @@ -1424,6 +1433,7 @@ public class SyncManager implements OnAccountsUpdateListener { public void handleMessage(Message msg) { long earliestFuturePollTime = Long.MAX_VALUE; long nextPendingSyncTime = Long.MAX_VALUE; + long nextBindTimeoutTime = Long.MAX_VALUE; // Setting the value here instead of a method because we want the dumpsys logs // to have the most recent value used. @@ -1431,6 +1441,7 @@ public class SyncManager implements OnAccountsUpdateListener { waitUntilReadyToRun(); mDataConnectionIsConnected = readDataConnectionState(); mSyncManagerWakeLock.acquire(); + nextBindTimeoutTime = auditRunningSyncsForStuckBindsLocked(); // Always do this first so that we be sure that any periodic syncs that // are ready to run have been converted into pending syncs. This allows the // logic that considers the next steps to take based on the set of pending syncs @@ -1532,6 +1543,7 @@ public class SyncManager implements OnAccountsUpdateListener { break; } } finally { + nextPendingSyncTime = Math.min(nextBindTimeoutTime, nextPendingSyncTime); manageSyncNotificationLocked(); manageSyncAlarmLocked(earliestFuturePollTime, nextPendingSyncTime); mSyncTimeTracker.update(); @@ -1540,6 +1552,36 @@ public class SyncManager implements OnAccountsUpdateListener { } /** + * Looks to see if any of the active syncs have been waiting for a bind for too long, + * and if so the sync is canceled and the sync adapter is disabled for that account. + * @return the earliest time that an active sync can have waited too long to bind, + * relative to {@link android.os.SystemClock#elapsedRealtime()}. + */ + private long auditRunningSyncsForStuckBindsLocked() { + final long now = SystemClock.elapsedRealtime(); + long oldest = Long.MAX_VALUE; + for (ActiveSyncContext active : mActiveSyncContexts) { + if (active.mSyncAdapter == null) { + final long timeoutTime = active.mStartTime + BIND_TIMEOUT_MS; + if (timeoutTime < now) { + Log.w(TAG, "canceling long-running bind and disabling sync for " + + active.mSyncOperation.account + ", authority " + + active.mSyncOperation.authority); + runSyncFinishedOrCanceledLocked(null, active); + ContentResolver.setIsSyncable(active.mSyncOperation.account, + active.mSyncOperation.authority, 0); + } else { + if (oldest > timeoutTime) { + oldest = timeoutTime; + } + } + } + } + + return oldest; + } + + /** * Turn any periodic sync operations that are ready to run into pending sync operations. * @return the desired start time of the earliest future periodic sync operation, * in milliseconds since boot @@ -1819,13 +1861,17 @@ public class SyncManager implements OnAccountsUpdateListener { synchronized (mSyncQueue){ mSyncQueue.remove(candidate); } - dispatchSyncOperation(candidate); + ActiveSyncContext newSyncContext = dispatchSyncOperation(candidate); + if (newSyncContext != null) { + nextReadyToRunTime = Math.min(nextReadyToRunTime, + newSyncContext.mStartTime + BIND_TIMEOUT_MS); + } } return nextReadyToRunTime; } - private boolean dispatchSyncOperation(SyncOperation op) { + private ActiveSyncContext dispatchSyncOperation(SyncOperation op) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "dispatchSyncOperation: we are going to sync " + op); Log.v(TAG, "num active syncs: " + mActiveSyncContexts.size()); @@ -1842,7 +1888,7 @@ public class SyncManager implements OnAccountsUpdateListener { Log.d(TAG, "can't find a sync adapter for " + syncAdapterType + ", removing settings for it"); mSyncStorageEngine.removeAuthority(op.account, op.authority); - return false; + return null; } ActiveSyncContext activeSyncContext = @@ -1855,10 +1901,10 @@ public class SyncManager implements OnAccountsUpdateListener { if (!activeSyncContext.bindToSyncAdapter(syncAdapterInfo)) { Log.e(TAG, "Bind attempt failed to " + syncAdapterInfo); closeActiveSyncContext(activeSyncContext); - return false; + return null; } - return true; + return activeSyncContext; } private void runBoundToSyncAdapter(final ActiveSyncContext activeSyncContext, diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java index b6487bd..5fe42db 100644 --- a/core/java/android/database/AbstractCursor.java +++ b/core/java/android/database/AbstractCursor.java @@ -36,6 +36,8 @@ public abstract class AbstractCursor implements CrossProcessCursor { DataSetObservable mDataSetObservable = new DataSetObservable(); ContentObservable mContentObservable = new ContentObservable(); + Bundle mExtras = Bundle.EMPTY; + /* -------------------------------------------------------- */ /* These need to be implemented by subclasses */ abstract public int getCount(); @@ -71,11 +73,11 @@ public abstract class AbstractCursor implements CrossProcessCursor { public int getColumnCount() { return getColumnNames().length; } - + public void deactivate() { deactivateInternal(); } - + /** * @hide */ @@ -99,7 +101,7 @@ public abstract class AbstractCursor implements CrossProcessCursor { public boolean isClosed() { return mClosed; } - + public void close() { mClosed = true; mContentObservable.unregisterAll(); @@ -120,7 +122,7 @@ public abstract class AbstractCursor implements CrossProcessCursor { return true; } - + public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) { // Default implementation, uses getString String result = getString(columnIndex); @@ -136,7 +138,7 @@ public abstract class AbstractCursor implements CrossProcessCursor { buffer.sizeCopied = 0; } } - + /* -------------------------------------------------------- */ /* Implementation */ public AbstractCursor() { @@ -181,7 +183,7 @@ public abstract class AbstractCursor implements CrossProcessCursor { return result; } - + /** * Copy data from cursor to CursorWindow * @param position start position of data @@ -199,7 +201,7 @@ public abstract class AbstractCursor implements CrossProcessCursor { window.setStartPosition(position); int columnNum = getColumnCount(); window.setNumColumns(columnNum); - while (moveToNext() && window.allocRow()) { + while (moveToNext() && window.allocRow()) { for (int i = 0; i < columnNum; i++) { String field = getString(i); if (field != null) { @@ -215,7 +217,7 @@ public abstract class AbstractCursor implements CrossProcessCursor { } } } - + mPos = oldpos; } catch (IllegalStateException e){ // simply ignore it @@ -314,7 +316,7 @@ public abstract class AbstractCursor implements CrossProcessCursor { mContentObservable.unregisterObserver(observer); } } - + /** * This is hidden until the data set change model has been re-evaluated. * @hide @@ -322,14 +324,14 @@ public abstract class AbstractCursor implements CrossProcessCursor { protected void notifyDataSetChange() { mDataSetObservable.notifyChanged(); } - + /** * This is hidden until the data set change model has been re-evaluated. * @hide */ protected DataSetObservable getDataSetObservable() { return mDataSetObservable; - + } public void registerDataSetObserver(DataSetObserver observer) { @@ -383,8 +385,19 @@ public abstract class AbstractCursor implements CrossProcessCursor { return false; } + /** + * Sets a {@link Bundle} that will be returned by {@link #getExtras()}. <code>null</code> will + * be converted into {@link Bundle#EMPTY}. + * + * @param extras {@link Bundle} to set. + * @hide + */ + public void setExtras(Bundle extras) { + mExtras = (extras == null) ? Bundle.EMPTY : extras; + } + public Bundle getExtras() { - return Bundle.EMPTY; + return mExtras; } public Bundle respond(Bundle extras) { diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index bc45945..63f2244 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -1468,6 +1468,7 @@ public class Camera { private static final String KEY_MAX_NUM_DETECTED_FACES_HW = "max-num-detected-faces-hw"; private static final String KEY_MAX_NUM_DETECTED_FACES_SW = "max-num-detected-faces-sw"; private static final String KEY_RECORDING_HINT = "recording-hint"; + private static final String KEY_VIDEO_SNAPSHOT_SUPPORTED = "video-snapshot-supported"; // Parameter key suffix for supported values. private static final String SUPPORTED_VALUES_SUFFIX = "-values"; @@ -3210,6 +3211,35 @@ public class Camera { set(KEY_RECORDING_HINT, hint ? TRUE : FALSE); } + /** + * Returns true if video snapshot is supported. That is, applications + * can call {@link #takePicture(Camera.ShutterCallback, + * Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)} + * during recording. Applications do not need to call {@link + * #startPreview()} after taking a picture. The preview will be still + * active. Other than that, taking a picture during recording is + * identical to taking a picture normally. All settings and methods + * related to takePicture work identically. Ex: {@link + * #getPictureSize()}, {@link #getSupportedPictureSizes()}, {@link + * #setJpegQuality(int)}, {@link #setRotation(int)}, and etc. The + * picture will have an EXIF header. {@link #FLASH_MODE_AUTO} and {@link + * #FLASH_MODE_ON} also still work, but the video will record the flash. + * + * Applications can set shutter callback as null to avoid the shutter + * sound. It is also recommended to set raw picture and post view + * callbacks to null to avoid the interrupt of preview display. + * + * Field-of-view of the recorded video may be different from that of the + * captured pictures. + * + * @return true if video snapshot is supported. + * @hide + */ + public boolean isVideoSnapshotSupported() { + String str = get(KEY_VIDEO_SNAPSHOT_SUPPORTED); + return TRUE.equals(str); + } + // Splits a comma delimited string to an ArrayList of String. // Return null if the passing string is null or the size is 0. private ArrayList<String> split(String str) { diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3441217..530122c 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -814,4 +814,22 @@ public class ConnectivityManager { } catch (RemoteException e) { } } + + /** + * Returns true if the hardware supports the given network type + * else it returns false. This doesn't indicate we have coverage + * or are authorized onto a network, just whether or not the + * hardware supports it. For example a gsm phone without a sim + * should still return true for mobile data, but a wifi only tablet + * would return false. + * @param networkType The nework type we'd like to check + * @return true if supported, else false + * @hide + */ + public boolean isNetworkSupported(int networkType) { + try { + return mService.isNetworkSupported(networkType); + } catch (RemoteException e) {} + return false; + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index c9553c0..eef658e 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -43,6 +43,8 @@ interface IConnectivityManager NetworkInfo getNetworkInfo(int networkType); NetworkInfo[] getAllNetworkInfo(); + boolean isNetworkSupported(int networkType); + LinkProperties getActiveLinkProperties(); LinkProperties getLinkProperties(int networkType); 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 @@ public class NetworkStats implements Parcelable { * 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/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java index 6fe5124..9ba1fdb 100644 --- a/core/java/android/provider/CalendarContract.java +++ b/core/java/android/provider/CalendarContract.java @@ -599,7 +599,7 @@ public final class CalendarContract { /** * The default sort order for this table */ - public static final String DEFAULT_SORT_ORDER = "displayName"; + public static final String DEFAULT_SORT_ORDER = CALENDAR_DISPLAY_NAME; /** * The name of the calendar. Column name. 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 @@ public abstract class SpellCheckerService extends Service { /** * 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 e914316..355d467 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -24,8 +24,8 @@ import android.text.style.AlignmentSpan; import android.text.style.BackgroundColorSpan; import android.text.style.BulletSpan; import android.text.style.CharacterStyle; -import android.text.style.ForegroundColorSpan; import android.text.style.EasyEditSpan; +import android.text.style.ForegroundColorSpan; import android.text.style.LeadingMarginSpan; import android.text.style.MetricAffectingSpan; import android.text.style.QuoteSpan; @@ -748,11 +748,11 @@ public class TextUtils { break; case SUGGESTION_RANGE_SPAN: - readSpan(p, sp, new SuggestionRangeSpan()); + readSpan(p, sp, new SuggestionRangeSpan(p)); break; case EASY_EDIT_SPAN: - readSpan(p, sp, new EasyEditSpan(p)); + readSpan(p, sp, new EasyEditSpan()); break; default: diff --git a/core/java/android/text/style/EasyEditSpan.java b/core/java/android/text/style/EasyEditSpan.java index e6e4d2c..2feb719 100644 --- a/core/java/android/text/style/EasyEditSpan.java +++ b/core/java/android/text/style/EasyEditSpan.java @@ -33,10 +33,6 @@ public class EasyEditSpan implements ParcelableSpan { // Empty } - public EasyEditSpan(Parcel src) { - this(); - } - @Override public int describeContents() { return 0; diff --git a/core/java/android/text/style/SuggestionRangeSpan.java b/core/java/android/text/style/SuggestionRangeSpan.java index fc91697..a637b1c 100644 --- a/core/java/android/text/style/SuggestionRangeSpan.java +++ b/core/java/android/text/style/SuggestionRangeSpan.java @@ -16,7 +16,6 @@ package android.text.style; -import android.graphics.Color; import android.os.Parcel; import android.text.ParcelableSpan; import android.text.TextPaint; @@ -29,12 +28,20 @@ import android.text.TextUtils; * @hide */ public class SuggestionRangeSpan extends CharacterStyle implements ParcelableSpan { + private final int mBackgroundColor; + @Override public void updateDrawState(TextPaint tp) { - tp.setColor(Color.GREEN); + tp.bgColor = mBackgroundColor; } - public SuggestionRangeSpan() { /* Nothing to do*/ } + public SuggestionRangeSpan(int color) { + mBackgroundColor = color; + } + + public SuggestionRangeSpan(Parcel src) { + mBackgroundColor = src.readInt(); + } @Override public int describeContents() { @@ -42,7 +49,9 @@ public class SuggestionRangeSpan extends CharacterStyle implements ParcelableSpa } @Override - public void writeToParcel(Parcel dest, int flags) { /* Nothing to do*/ } + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mBackgroundColor); + } @Override public int getSpanTypeId() { diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 2bf16d8..1fcde3d 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -344,9 +344,9 @@ public abstract class HardwareRenderer { static final int EGL_SURFACE_TYPE = 0x3033; static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400; - private static final int SURFACE_STATE_ERROR = 0; - private static final int SURFACE_STATE_SUCCESS = 1; - private static final int SURFACE_STATE_UPDATED = 2; + static final int SURFACE_STATE_ERROR = 0; + static final int SURFACE_STATE_SUCCESS = 1; + static final int SURFACE_STATE_UPDATED = 2; static EGL10 sEgl; static EGLDisplay sEglDisplay; @@ -913,8 +913,7 @@ public abstract class HardwareRenderer { @Override void destroyLayers(View view) { - if (view != null && isEnabled()) { - checkCurrent(); + if (view != null && isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) { destroyHardwareLayer(view); GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS); } diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 9d959fb..c735d6b 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -286,6 +286,11 @@ public class TextureView extends View { } @Override + boolean destroyLayer() { + return false; + } + + @Override HardwareLayer getHardwareLayer() { if (mLayer == null) { if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 14677e1..fa1d249 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -2595,11 +2595,6 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit protected static int DEFAULT_TEXT_DIRECTION = TEXT_DIRECTION_INHERIT; /** - * Default threshold for "char count" heuristic. - */ - protected static float DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD = 0.6f; - - /** * The text direction that has been defined by {@link #setTextDirection(int)}. * * {@hide} @@ -6052,23 +6047,29 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit * @see #onHoverChanged */ public boolean onHoverEvent(MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_HOVER_ENTER: - if (!hasHoveredChild() && !mSendingHoverAccessibilityEvents) { - mSendingHoverAccessibilityEvents = true; - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); - } - break; - case MotionEvent.ACTION_HOVER_EXIT: - if (mSendingHoverAccessibilityEvents) { - mSendingHoverAccessibilityEvents = false; - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); - } - break; + // The root view may receive hover (or touch) events that are outside the bounds of + // the window. This code ensures that we only send accessibility events for + // hovers that are actually within the bounds of the root view. + final int action = event.getAction(); + if (!mSendingHoverAccessibilityEvents) { + if ((action == MotionEvent.ACTION_HOVER_ENTER + || action == MotionEvent.ACTION_HOVER_MOVE) + && !hasHoveredChild() + && pointInView(event.getX(), event.getY())) { + mSendingHoverAccessibilityEvents = true; + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); + } + } else { + if (action == MotionEvent.ACTION_HOVER_EXIT + || (action == MotionEvent.ACTION_HOVER_MOVE + && !pointInView(event.getX(), event.getY()))) { + mSendingHoverAccessibilityEvents = false; + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); + } } if (isHoverable()) { - switch (event.getAction()) { + switch (action) { case MotionEvent.ACTION_HOVER_ENTER: setHovered(true); break; @@ -9361,7 +9362,6 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit if (mAttachInfo != null) { mAttachInfo.mHandler.removeMessages(AttachInfo.INVALIDATE_MSG, this); - mAttachInfo.mHandler.removeMessages(AttachInfo.INVALIDATE_RECT_MSG, this); } mCurrentAnimation = null; @@ -13909,6 +13909,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit } public void onReleased(InvalidateInfo element) { + element.target = null; } }, POOL_LIMIT) ); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 5c045bb..7db1b32 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2141,6 +2141,10 @@ public final class ViewRootImpl extends Handler implements ViewParent, void dispatchDetachedFromWindow() { if (mView != null && mView.mAttachInfo != null) { + if (mAttachInfo.mHardwareRenderer != null && + mAttachInfo.mHardwareRenderer.isEnabled()) { + mAttachInfo.mHardwareRenderer.validate(); + } mView.dispatchDetachedFromWindow(); } @@ -3568,6 +3572,11 @@ public final class ViewRootImpl extends Handler implements ViewParent, checkThread(); if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface); synchronized (this) { + if (mAdded) { + mAdded = false; + dispatchDetachedFromWindow(); + } + if (mAdded && !mFirst) { destroyHardwareRenderer(); @@ -3588,10 +3597,6 @@ public final class ViewRootImpl extends Handler implements ViewParent, mSurface.release(); } - if (mAdded) { - mAdded = false; - dispatchDetachedFromWindow(); - } } } diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index a963e10..dc1bbd7 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -872,6 +872,12 @@ public interface WindowManagerPolicy { public void systemReady(); /** + * Called when the system is done booting to the point where the + * user can start interacting with it. + */ + public void systemBooted(); + + /** * Show boot time message to the user. */ public void showBootMessage(final CharSequence msg, final boolean always); diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java index 5d4fbbe..76b47ca 100755 --- a/core/java/android/view/WindowOrientationListener.java +++ b/core/java/android/view/WindowOrientationListener.java @@ -332,7 +332,7 @@ public abstract class WindowOrientationListener { // we perform an orientation change under ideal conditions. It will take // proportionally longer than this to effect an orientation change when // the proposed orientation confidence is low. - private static final float ORIENTATION_SETTLE_TIME_MS = 100; + private static final float ORIENTATION_SETTLE_TIME_MS = 250; // The confidence that we have abount effecting each orientation change. // When one of these values exceeds 1.0, we have determined our new orientation! 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 @@ public final class InputMethodInfo implements Parcelable { 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 @@ public final class InputMethodManager { * 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 @@ public final class InputMethodSubtype implements Parcelable { 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 @@ public final class InputMethodSubtype implements Parcelable { * @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 @@ public final class InputMethodSubtype implements Parcelable { * @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 @@ public final class InputMethodSubtype implements Parcelable { 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 @@ public final class InputMethodSubtype implements Parcelable { } /** + * @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 @@ public final class InputMethodSubtype implements Parcelable { 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 @@ public final class InputMethodSubtype implements Parcelable { } 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/JniUtil.java b/core/java/android/webkit/JniUtil.java index 4264e9d..ef1641d 100644 --- a/core/java/android/webkit/JniUtil.java +++ b/core/java/android/webkit/JniUtil.java @@ -28,6 +28,7 @@ class JniUtil { static { System.loadLibrary("webcore"); + System.loadLibrary("chromium_net"); } private static final String LOGTAG = "webkit"; private JniUtil() {} // Utility class, do not instantiate. diff --git a/core/java/android/webkit/ViewStateSerializer.java b/core/java/android/webkit/ViewStateSerializer.java index 0fc76fa..5f91ed3 100644 --- a/core/java/android/webkit/ViewStateSerializer.java +++ b/core/java/android/webkit/ViewStateSerializer.java @@ -36,11 +36,15 @@ class ViewStateSerializer { static boolean serializeViewState(OutputStream stream, WebView web) throws IOException { + int baseLayer = web.getBaseLayer(); + if (baseLayer == 0) { + return false; + } DataOutputStream dos = new DataOutputStream(stream); dos.writeInt(VERSION); dos.writeInt(web.getContentWidth()); dos.writeInt(web.getContentHeight()); - return nativeSerializeViewState(web.getBaseLayer(), dos, + return nativeSerializeViewState(baseLayer, dos, new byte[WORKING_STREAM_STORAGE]); } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 4748522..2e7f923 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -34,7 +34,6 @@ import android.graphics.BitmapFactory; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.CornerPathEffect; import android.graphics.DrawFilter; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; @@ -58,8 +57,6 @@ import android.os.Message; import android.os.StrictMode; import android.provider.Settings; import android.speech.tts.TextToSpeech; -import android.text.Selection; -import android.text.Spannable; import android.util.AttributeSet; import android.util.EventLog; import android.util.Log; @@ -606,9 +603,15 @@ public class WebView extends AbsoluteLayout // know to handle Shift and arrows natively first private boolean mAccessibilityScriptInjected; + static final boolean USE_JAVA_TEXT_SELECTION = true; + private Region mTextSelectionRegion = new Region(); + private Paint mTextSelectionPaint; + private Drawable mSelectHandleLeft; + private Drawable mSelectHandleRight; + static final boolean USE_WEBKIT_RINGS = true; // the color used to highlight the touch rectangles - private static final int mHightlightColor = 0x6633b5e5; + private static final int HIGHLIGHT_COLOR = 0x6633b5e5; // the round corner for the highlight path private static final float TOUCH_HIGHLIGHT_ARC = 5.0f; // the region indicating where the user touched on the screen @@ -4004,12 +4007,9 @@ public class WebView extends AbsoluteLayout // state. // If mNativeClass is 0, we should not reach here, so we do not // need to check it again. - if (mDrawCursorRing && drawRings) { - // Only update if we are actually going to use the result - nativeRecordButtons(hasFocus() && hasWindowFocus(), - mTouchMode == TOUCH_SHORTPRESS_START_MODE - || mTrackballDown || mGotCenterDown, false); - } + nativeRecordButtons(hasFocus() && hasWindowFocus(), + (mTouchMode == TOUCH_SHORTPRESS_START_MODE && !USE_WEBKIT_RINGS) + || mTrackballDown || mGotCenterDown, false); drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing && drawRings); } @@ -4050,8 +4050,10 @@ public class WebView extends AbsoluteLayout @Override protected void onDraw(Canvas canvas) { - // if mNativeClass is 0, the WebView has been destroyed. Do nothing. + // if mNativeClass is 0, the WebView is either destroyed or not + // initialized. In either case, just draw the background color and return if (mNativeClass == 0) { + canvas.drawColor(mBackgroundColor); return; } @@ -4105,7 +4107,7 @@ public class WebView extends AbsoluteLayout } else { if (mTouchHightlightPaint == null) { mTouchHightlightPaint = new Paint(); - mTouchHightlightPaint.setColor(mHightlightColor); + mTouchHightlightPaint.setColor(HIGHLIGHT_COLOR); } RegionIterator iter = new RegionIterator(mTouchHighlightRegion); Rect r = new Rect(); @@ -4306,6 +4308,9 @@ public class WebView extends AbsoluteLayout } int getBaseLayer() { + if (mNativeClass == 0) { + return 0; + } return nativeGetBaseLayer(); } @@ -4400,7 +4405,7 @@ public class WebView extends AbsoluteLayout int extras = DRAW_EXTRAS_NONE; if (mFindIsUp) { extras = DRAW_EXTRAS_FIND; - } else if (mSelectingText) { + } else if (mSelectingText && !USE_JAVA_TEXT_SELECTION) { extras = DRAW_EXTRAS_SELECTION; nativeSetSelectionPointer(mDrawSelectionPointer, mZoomManager.getInvScale(), @@ -4427,6 +4432,10 @@ public class WebView extends AbsoluteLayout nativeUseHardwareAccelSkia(mHardwareAccelSkia); } + if (mSelectingText && USE_JAVA_TEXT_SELECTION) { + drawTextSelectionHandles(canvas); + } + } else { DrawFilter df = null; if (mZoomManager.isZoomAnimating() || UIAnimationsRunning) { @@ -4461,6 +4470,56 @@ public class WebView extends AbsoluteLayout } } + private void drawTextSelectionHandles(Canvas canvas) { + if (mTextSelectionPaint == null) { + mTextSelectionPaint = new Paint(); + mTextSelectionPaint.setColor(HIGHLIGHT_COLOR); + } + mTextSelectionRegion.setEmpty(); + nativeGetTextSelectionRegion(mTextSelectionRegion); + Rect r = new Rect(); + RegionIterator iter = new RegionIterator(mTextSelectionRegion); + int start_x = -1; + int start_y = -1; + int end_x = -1; + int end_y = -1; + while (iter.next(r)) { + r = new Rect( + contentToViewDimension(r.left), + contentToViewDimension(r.top), + contentToViewDimension(r.right), + contentToViewDimension(r.bottom)); + // Regions are in order. First one is where selection starts, + // last one is where it ends + if (start_x < 0 || start_y < 0) { + start_x = r.left; + start_y = r.bottom; + } + end_x = r.right; + end_y = r.bottom; + canvas.drawRect(r, mTextSelectionPaint); + } + if (mSelectHandleLeft == null) { + mSelectHandleLeft = mContext.getResources().getDrawable( + com.android.internal.R.drawable.text_select_handle_left); + } + // Magic formula copied from TextView + start_x -= (mSelectHandleLeft.getIntrinsicWidth() * 3) / 4; + mSelectHandleLeft.setBounds(start_x, start_y, + start_x + mSelectHandleLeft.getIntrinsicWidth(), + start_y + mSelectHandleLeft.getIntrinsicHeight()); + if (mSelectHandleRight == null) { + mSelectHandleRight = mContext.getResources().getDrawable( + com.android.internal.R.drawable.text_select_handle_right); + } + end_x -= mSelectHandleRight.getIntrinsicWidth() / 4; + mSelectHandleRight.setBounds(end_x, end_y, + end_x + mSelectHandleRight.getIntrinsicWidth(), + end_y + mSelectHandleRight.getIntrinsicHeight()); + mSelectHandleLeft.draw(canvas); + mSelectHandleRight.draw(canvas); + } + // draw history private boolean mDrawHistory = false; private Picture mHistoryPicture = null; @@ -9329,4 +9388,5 @@ public class WebView extends AbsoluteLayout private native int nativeGetBackgroundColor(); native boolean nativeSetProperty(String key, String value); native String nativeGetProperty(String key); + private native void nativeGetTextSelectionRegion(Region region); } diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 3ca3eaa..c895b84 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -57,13 +57,14 @@ public final class WebViewCore { private static final String LOGTAG = "webcore"; static { - // Load libwebcore during static initialization. This happens in the - // zygote process so it will be shared read-only across all app - // processes. + // Load libwebcore and libchromium_net during static initialization. + // This happens in the zygote process so they will be shared read-only + // across all app processes. try { System.loadLibrary("webcore"); + System.loadLibrary("chromium_net"); } catch (UnsatisfiedLinkError e) { - Log.e(LOGTAG, "Unable to load webcore library"); + Log.e(LOGTAG, "Unable to load native support libraries."); } } @@ -537,6 +538,8 @@ public final class WebViewCore { 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 @@ -1040,6 +1043,7 @@ public final class WebViewCore { // Flag for blocking messages. This is used during DESTROY to avoid // posting more messages to the EventHub or to WebView's event handler. private boolean mBlockMessages; + private boolean mDestroying; private int mTid; private int mSavedPriority; @@ -1071,12 +1075,20 @@ public final class WebViewCore { + " arg1=" + msg.arg1 + " arg2=" + msg.arg2 + " obj=" + msg.obj); } - if (mWebView == null + if (mWebView == null || mNativeClass == 0) { + if (DebugFlags.WEB_VIEW_CORE) { + Log.w(LOGTAG, "Rejecting message " + msg.what + + " because we are destroyed"); + } + return; + } + if (mDestroying == true && msg.what != EventHub.RESUME_TIMERS - && msg.what != EventHub.PAUSE_TIMERS) { + && msg.what != EventHub.PAUSE_TIMERS + && msg.what != EventHub.DESTROY) { if (DebugFlags.WEB_VIEW_CORE) { Log.v(LOGTAG, "Rejecting message " + msg.what - + " because we are destroyed"); + + " because we are being destroyed"); } return; } @@ -1252,6 +1264,8 @@ public final class WebViewCore { if (!JniUtil.useChromiumHttpStack()) { WebViewWorker.getHandler().sendEmptyMessage( WebViewWorker.MSG_PAUSE_CACHE_TRANSACTION); + } else { + nativeCloseIdleConnections(); } break; @@ -1780,7 +1794,8 @@ public final class WebViewCore { // or RESUME_TIMERS messages, which we must still handle as they // are per process. DESTROY will instead trigger a white list in // mEventHub, skipping any remaining messages in the queue - mEventHub.sendMessageAtFrontOfQueue( + mEventHub.mDestroying = true; + mEventHub.sendMessage( Message.obtain(null, EventHub.DESTROY)); mEventHub.blockMessages(); } diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index f267458c..4ba604d 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -926,6 +926,8 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { } event.setItemCount(getCount()); event.setCurrentItemIndex(getSelectedItemPosition()); + event.setFromIndex(mFirstPosition); + event.setToIndex(mFirstPosition + getChildCount()); } @Override diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 4812283..3b67f44 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -30,6 +30,7 @@ import android.util.Log; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; import android.widget.NumberPicker.OnValueChangeListener; import com.android.internal.R; @@ -264,6 +265,11 @@ public class DatePicker extends FrameLayout { // re-order the number spinners to match the current date format reorderSpinners(); + + // set content descriptions + if (AccessibilityManager.getInstance(mContext).isEnabled()) { + setContentDescriptions(); + } } /** @@ -357,11 +363,16 @@ public class DatePicker extends FrameLayout { } @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + onPopulateAccessibilityEvent(event); + return true; + } + + @Override public void onPopulateAccessibilityEvent(AccessibilityEvent event) { super.onPopulateAccessibilityEvent(event); - final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY - | DateUtils.FORMAT_SHOW_YEAR; + final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR; String selectedDateUtterance = DateUtils.formatDateTime(mContext, mCurrentDate.getTimeInMillis(), flags); event.getText().add(selectedDateUtterance); @@ -709,5 +720,22 @@ public class DatePicker extends FrameLayout { } }; } -} + private void setContentDescriptions() { + // Day + String text = mContext.getString(R.string.date_picker_increment_day_button); + mDaySpinner.findViewById(R.id.increment).setContentDescription(text); + text = mContext.getString(R.string.date_picker_decrement_day_button); + mDaySpinner.findViewById(R.id.decrement).setContentDescription(text); + // Month + text = mContext.getString(R.string.date_picker_increment_month_button); + mMonthSpinner.findViewById(R.id.increment).setContentDescription(text); + text = mContext.getString(R.string.date_picker_decrement_month_button); + mMonthSpinner.findViewById(R.id.decrement).setContentDescription(text); + // Year + text = mContext.getString(R.string.date_picker_increment_year_button); + mYearSpinner.findViewById(R.id.increment).setContentDescription(text); + text = mContext.getString(R.string.date_picker_decrement_year_button); + mYearSpinner.findViewById(R.id.decrement).setContentDescription(text); + } +} diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index 2a299bd..35e48f2 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -33,6 +33,7 @@ import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Paint.Align; import android.graphics.drawable.Drawable; +import android.os.SystemClock; import android.text.InputFilter; import android.text.InputType; import android.text.Spanned; @@ -48,6 +49,8 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.LayoutInflater.Filter; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; import android.view.animation.DecelerateInterpolator; import android.view.inputmethod.InputMethodManager; @@ -471,7 +474,7 @@ public class NumberPicker extends LinearLayout { // the fading edge effect implemented by View and we need our // draw() method to be called. Therefore, we declare we will draw. setWillNotDraw(false); - setDrawSelectorWheel(false); + setDrawScrollWheel(false); LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE); @@ -561,7 +564,7 @@ public class NumberPicker extends LinearLayout { public void onAnimationEnd(Animator animation) { if (!mCanceled) { // if canceled => we still want the wheel drawn - setDrawSelectorWheel(false); + setDrawScrollWheel(false); } mCanceled = false; mSelectorPaint.setAlpha(255); @@ -587,7 +590,7 @@ public class NumberPicker extends LinearLayout { // Start with shown selector wheel and hidden controls. When made // visible hide the selector and fade-in the controls to suggest // fling interaction. - setDrawSelectorWheel(true); + setDrawScrollWheel(true); hideInputControls(); } } @@ -630,7 +633,7 @@ public class NumberPicker extends LinearLayout { || (!mDecrementButton.isShown() && isEventInViewHitRect(event, mDecrementButton))) { mAdjustScrollerOnUpEvent = false; - setDrawSelectorWheel(true); + setDrawScrollWheel(true); hideInputControls(); return true; } @@ -641,7 +644,7 @@ public class NumberPicker extends LinearLayout { if (deltaDownY > mTouchSlop) { mBeginEditOnUpEvent = false; onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); - setDrawSelectorWheel(true); + setDrawScrollWheel(true); hideInputControls(); return true; } @@ -678,7 +681,7 @@ public class NumberPicker extends LinearLayout { break; case MotionEvent.ACTION_UP: if (mBeginEditOnUpEvent) { - setDrawSelectorWheel(false); + setDrawScrollWheel(false); showInputControls(mShowInputControlsAnimimationDuration); mInputText.requestFocus(); InputMethodManager imm = (InputMethodManager) getContext().getSystemService( @@ -1135,6 +1138,12 @@ public class NumberPicker extends LinearLayout { } } + @Override + public void sendAccessibilityEvent(int eventType) { + // Do not send accessibility events - we want the user to + // perceive this widget as several controls rather as a whole. + } + /** * Resets the selector indices and clear the cached * string representation of these indices. @@ -1192,10 +1201,19 @@ public class NumberPicker extends LinearLayout { /** * Sets if to <code>drawSelectionWheel</code>. */ - private void setDrawSelectorWheel(boolean drawSelectorWheel) { + private void setDrawScrollWheel(boolean drawSelectorWheel) { mDrawSelectorWheel = drawSelectorWheel; // do not fade if the selector wheel not shown setVerticalFadingEdgeEnabled(drawSelectorWheel); + + if (mFlingable && mDrawSelectorWheel + && AccessibilityManager.getInstance(mContext).isEnabled()) { + AccessibilityManager.getInstance(mContext).interrupt(); + String text = mContext.getString(R.string.number_picker_increment_scroll_action); + mInputText.setContentDescription(text); + mInputText.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + mInputText.setContentDescription(null); + } } private void initializeScrollWheel() { @@ -1429,6 +1447,12 @@ public class NumberPicker extends LinearLayout { mInputText.setText(mDisplayedValues[mValue - mMinValue]); } mInputText.setSelection(mInputText.getText().length()); + + if (mFlingable && AccessibilityManager.getInstance(mContext).isEnabled()) { + String text = mContext.getString(R.string.number_picker_increment_scroll_mode, + mInputText.getText()); + mInputText.setContentDescription(text); + } } /** diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index b89b8ec..14cbf6f 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -1,4 +1,18 @@ -// Copyright 2011 Google Inc. All Rights Reserved. +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package android.widget; @@ -32,7 +46,7 @@ public class SpellChecker implements SpellCheckerSessionListener { private final TextView mTextView; - final SpellCheckerSession spellCheckerSession; + final SpellCheckerSession mSpellCheckerSession; final int mCookie; // Paired arrays for the (id, spellCheckSpan) pair. mIndex is the next available position @@ -49,7 +63,7 @@ public class SpellChecker implements SpellCheckerSessionListener { final TextServicesManager textServicesManager = (TextServicesManager) textView.getContext(). getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE); - spellCheckerSession = textServicesManager.newSpellCheckerSession( + mSpellCheckerSession = textServicesManager.newSpellCheckerSession( null /* not currently used by the textServicesManager */, Locale.getDefault(), this, true /* means use the languages defined in Settings */); mCookie = hashCode(); @@ -112,7 +126,7 @@ public class SpellChecker implements SpellCheckerSessionListener { private void scheduleSpellCheck() { if (mLength == 0) return; - if (spellCheckerSession == null) return; + if (mSpellCheckerSession == null) return; if (mChecker != null) { mTextView.removeCallbacks(mChecker); @@ -157,7 +171,7 @@ public class SpellChecker implements SpellCheckerSessionListener { System.arraycopy(textInfos, 0, textInfosCopy, 0, textInfosCount); textInfos = textInfosCopy; } - spellCheckerSession.getSuggestions(textInfos, SuggestionSpan.SUGGESTIONS_MAX_SIZE, + mSpellCheckerSession.getSuggestions(textInfos, SuggestionSpan.SUGGESTIONS_MAX_SIZE, false /* TODO Set sequentialWords to true for initial spell check */); } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 4ce2d90..1aa009b 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -63,8 +63,8 @@ import android.text.TextDirectionHeuristic; import android.text.TextDirectionHeuristics; import android.text.TextPaint; import android.text.TextUtils; -import android.text.TextWatcher; import android.text.TextUtils.TruncateAt; +import android.text.TextWatcher; import android.text.method.AllCapsTransformationMethod; import android.text.method.ArrowKeyMovementMethod; import android.text.method.DateKeyListener; @@ -82,7 +82,6 @@ import android.text.method.TimeKeyListener; import android.text.method.TransformationMethod; import android.text.method.TransformationMethod2; import android.text.method.WordIterator; -import android.text.style.CharacterStyle; import android.text.style.ClickableSpan; import android.text.style.EasyEditSpan; import android.text.style.ParagraphStyle; @@ -131,6 +130,7 @@ import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; +import android.widget.AdapterView.OnItemClickListener; import android.widget.RemoteViews.RemoteView; import com.android.internal.util.FastMath; @@ -7868,7 +7868,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override protected void initContentView() { - mContentView.setOrientation(LinearLayout.HORIZONTAL); + LinearLayout linearLayout = new LinearLayout(TextView.this.getContext()); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + mContentView = linearLayout; mContentView.setBackgroundResource( com.android.internal.R.drawable.text_edit_side_paste_window); @@ -8177,17 +8179,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener startStopMarquee(hasWindowFocus); } - private void removeSpans(int start, int end, Class<?> type) { - if (mText instanceof Editable) { - Editable editable = ((Editable) mText); - Object[] spans = editable.getSpans(start, end, type); - final int length = spans.length; - for (int i = 0; i < length; i++) { - editable.removeSpan(spans[i]); - } - } - } - @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); @@ -9326,7 +9317,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private abstract class PinnedPopupWindow implements TextViewPositionListener { protected PopupWindow mPopupWindow; - protected LinearLayout mContentView; + protected ViewGroup mContentView; int mPositionX, mPositionY; protected abstract void createPopupWindow(); @@ -9342,23 +9333,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); - mContentView = new LinearLayout(TextView.this.getContext()); - LayoutParams wrapContent = new LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + initContentView(); + + LayoutParams wrapContent = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); mContentView.setLayoutParams(wrapContent); - initContentView(); mPopupWindow.setContentView(mContentView); } public void show() { - final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); - mContentView.measure( - View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels, - View.MeasureSpec.AT_MOST), - View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels, - View.MeasureSpec.AT_MOST)); - TextView.this.getPositionListener().addSubscriber(this, false); computeLocalPosition(); @@ -9366,11 +9350,24 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final PositionListener positionListener = TextView.this.getPositionListener(); updatePosition(positionListener.getPositionX(), positionListener.getPositionY()); } + + protected void measureContent() { + final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); + mContentView.measure( + View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels, + View.MeasureSpec.AT_MOST), + View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels, + View.MeasureSpec.AT_MOST)); + } + /* The popup window will be horizontally centered on the getTextOffset() and vertically + * positioned according to viewportToContentHorizontalOffset. + * + * This method assumes that mContentView has properly been measured from its content. */ private void computeLocalPosition() { - final int offset = getTextOffset(); - + measureContent(); final int width = mContentView.getMeasuredWidth(); + final int offset = getTextOffset(); mPositionX = (int) (mLayout.getPrimaryHorizontal(offset) - width / 2.0f); mPositionX += viewportToContentHorizontalOffset(); @@ -9418,42 +9415,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - private static class SuggestionRangeSpan extends CharacterStyle { - - private final int mTextColor; - private final int mBackgroundColor; - - public SuggestionRangeSpan(Context context) { - TypedArray typedArray = context.obtainStyledAttributes(null, - com.android.internal.R.styleable.SuggestionRangeSpan, - com.android.internal.R.attr.textAppearanceSuggestionRange, 0); - - mTextColor = typedArray.getColor( - com.android.internal.R.styleable.SuggestionRangeSpan_textColor, 0); - mBackgroundColor = typedArray.getColor( - com.android.internal.R.styleable.SuggestionRangeSpan_colorBackground, 0); - } - - @Override - public void updateDrawState(TextPaint tp) { - if (mTextColor != 0) { - tp.setColor(mTextColor); - } - - if (mBackgroundColor != 0) { - tp.bgColor = mBackgroundColor; - } - } - } - - private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnClickListener { + 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 [(int) (AVERAGE_HIGHLIGHTS_PER_SUGGESTION * MAX_NUMBER_SUGGESTIONS)]; + private SuggestionInfo[] mSuggestionInfos; + private int mNumberOfSuggestions; private boolean mCursorWasVisibleBeforeSuggestions; + private SuggestionAdapter mSuggestionsAdapter; private class CustomPopupWindow extends PopupWindow { public CustomPopupWindow(Context context, int defStyle) { @@ -9494,29 +9466,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override protected void initContentView() { - mContentView.setOrientation(LinearLayout.VERTICAL); - - LayoutInflater inflater = (LayoutInflater) TextView.this.mContext. - getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - if (inflater == null) { - throw new IllegalArgumentException( - "Unable to create inflater for TextEdit suggestions"); - } + ListView listView = new ListView(TextView.this.getContext()); + mSuggestionsAdapter = new SuggestionAdapter(); + listView.setAdapter(mSuggestionsAdapter); + 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++) { - View childView = inflater.inflate(mTextEditSuggestionItemLayout, - mContentView, false); - - if (! (childView instanceof TextView)) { - throw new IllegalArgumentException( - "Inflated TextEdit suggestion item is not a TextView: " + childView); - } - - childView.setTag(new SuggestionInfo()); - mContentView.addView(childView); - childView.setOnClickListener(this); + mSuggestionInfos[i] = new SuggestionInfo(); } } @@ -9525,6 +9484,40 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int spanStart, spanEnd; // range in TextView where text should be inserted SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents int suggestionIndex; // the index of the suggestion inside suggestionSpan + SpannableStringBuilder text = new SpannableStringBuilder(); + } + + private class SuggestionAdapter extends BaseAdapter { + private LayoutInflater mInflater = (LayoutInflater) TextView.this.mContext. + getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + @Override + public int getCount() { + return mNumberOfSuggestions; + } + + @Override + public Object getItem(int position) { + return mSuggestionInfos[position]; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + TextView textView = (TextView) convertView; + + if (textView == null) { + textView = (TextView) mInflater.inflate(mTextEditSuggestionItemLayout, parent, + false); + } + + textView.setText(mSuggestionInfos[position].text); + return textView; + } } /** @@ -9569,6 +9562,36 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } @Override + protected void measureContent() { + final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); + final int horizontalMeasure = View.MeasureSpec.makeMeasureSpec( + displayMetrics.widthPixels, View.MeasureSpec.AT_MOST); + final int verticalMeasure = View.MeasureSpec.makeMeasureSpec( + displayMetrics.heightPixels, View.MeasureSpec.AT_MOST); + + int width = 0; + View view = null; + for (int i = 0; i < mNumberOfSuggestions; i++) { + view = mSuggestionsAdapter.getView(i, view, mContentView); + view.measure(horizontalMeasure, verticalMeasure); + width = Math.max(width, view.getMeasuredWidth()); + } + + // Enforce the width based on actual text widths + mContentView.measure( + View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), + verticalMeasure); + + Drawable popupBackground = mPopupWindow.getBackground(); + if (popupBackground != null) { + if (mTempRect == null) mTempRect = new Rect(); + popupBackground.getPadding(mTempRect); + width += mTempRect.left + mTempRect.right; + } + mPopupWindow.setWidth(width); + } + + @Override protected int getTextOffset() { return getSelectionStart(); } @@ -9596,7 +9619,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int nbSpans = suggestionSpans.length; - int totalNbSuggestions = 0; + mNumberOfSuggestions = 0; int spanUnionStart = mText.length(); int spanUnionEnd = 0; @@ -9610,17 +9633,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener String[] suggestions = suggestionSpan.getSuggestions(); int nbSuggestions = suggestions.length; for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) { - TextView textView = (TextView) mContentView.getChildAt( - totalNbSuggestions); - textView.setText(suggestions[suggestionIndex]); - SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag(); + SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions]; suggestionInfo.spanStart = spanStart; suggestionInfo.spanEnd = spanEnd; suggestionInfo.suggestionSpan = suggestionSpan; suggestionInfo.suggestionIndex = suggestionIndex; + suggestionInfo.text = new SpannableStringBuilder(suggestions[suggestionIndex]); - totalNbSuggestions++; - if (totalNbSuggestions == MAX_NUMBER_SUGGESTIONS) { + mNumberOfSuggestions++; + if (mNumberOfSuggestions == MAX_NUMBER_SUGGESTIONS) { // Also end outer for loop spanIndex = nbSpans; break; @@ -9628,31 +9649,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - if (totalNbSuggestions == 0) return false; + if (mNumberOfSuggestions == 0) return false; - if (mSuggestionRangeSpan == null) { - mSuggestionRangeSpan = new SuggestionRangeSpan(getContext()); - } - - ((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = + new SuggestionRangeSpan(mHighlightColor); - if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = - new SuggestionRangeSpan(getContext()); ((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - for (int i = 0; i < totalNbSuggestions; i++) { - final TextView textView = (TextView) mContentView.getChildAt(i); - highlightTextDifferences(textView, spanUnionStart, spanUnionEnd); - } - - for (int i = 0; i < totalNbSuggestions; i++) { - mContentView.getChildAt(i).setVisibility(VISIBLE); - } - for (int i = totalNbSuggestions; i < MAX_NUMBER_SUGGESTIONS; i++) { - mContentView.getChildAt(i).setVisibility(GONE); + for (int i = 0; i < mNumberOfSuggestions; i++) { + highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd); } + mSuggestionsAdapter.notifyDataSetChanged(); return true; } @@ -9719,13 +9727,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return highlightSpan; } - private void highlightTextDifferences(TextView textView, int unionStart, int unionEnd) { - SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag(); + private void highlightTextDifferences(SuggestionInfo suggestionInfo, + int unionStart, int unionEnd) { final int spanStart = suggestionInfo.spanStart; final int spanEnd = suggestionInfo.spanEnd; // Remove all text formating by converting to Strings - final String text = textView.getText().toString(); + final String text = suggestionInfo.text.toString(); final String sourceText = mText.subSequence(spanStart, spanEnd).toString(); long[] sourceWordLimits = getWordLimits(sourceText); @@ -9800,7 +9808,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (previousCommonWordIndex < words.length - 1) { int firstDifferentPosition = previousCommonWordIndex < 0 ? 0 : extractRangeEndFromLong(wordLimits[previousCommonWordIndex]); - int lastDifferentPosition = textView.length(); + int lastDifferentPosition = text.length(); ssb.setSpan(highlightSpan(nbHighlightSpans++), shift + firstDifferentPosition, shift + lastDifferentPosition, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -9811,25 +9819,24 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int lastCommonTextWordEnd = previousCommonWordIndex < 0 ? 0 : extractRangeEndFromLong(wordLimits[previousCommonWordIndex]); - String textSpaces = text.substring(lastCommonTextWordEnd, textView.length()); + String textSpaces = text.substring(lastCommonTextWordEnd, text.length()); if (!sourceSpaces.equals(textSpaces) && textSpaces.length() > 0) { ssb.setSpan(highlightSpan(nbHighlightSpans++), - shift + lastCommonTextWordEnd, shift + textView.length(), + shift + lastCommonTextWordEnd, shift + text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } // Final part, text after the current suggestion range. ssb.append(mText.subSequence(spanEnd, unionEnd).toString()); - textView.setText(ssb); } @Override - public void onClick(View view) { + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (view instanceof TextView) { TextView textView = (TextView) view; - SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag(); + SuggestionInfo suggestionInfo = mSuggestionInfos[position]; final int spanStart = suggestionInfo.spanStart; final int spanEnd = suggestionInfo.spanEnd; if (spanStart != NO_SUGGESTIONS) { @@ -10190,9 +10197,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override protected void initContentView() { - mContentView.setOrientation(LinearLayout.HORIZONTAL); + LinearLayout linearLayout = new LinearLayout(TextView.this.getContext()); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + mContentView = linearLayout; mContentView.setBackgroundResource( - com.android.internal.R.drawable.text_edit_side_paste_window); + com.android.internal.R.drawable.text_edit_paste_window); LayoutInflater inflater = (LayoutInflater)TextView.this.mContext. getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -11282,7 +11291,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private final TextPaint mTextPaint; private boolean mUserSetTextScaleX; private final Paint mHighlightPaint; - private int mHighlightColor = 0xCC475925; + private int mHighlightColor = 0x4C33B5E5; /** * This is temporarily visible to fix bug 3085564 in webView. Do not rely on * this field being protected. Will be restored as private when lineHeight diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index 0547438..2350229 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -29,6 +29,7 @@ import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; import android.widget.NumberPicker.OnValueChangeListener; import java.text.DateFormatSymbols; @@ -227,6 +228,11 @@ public class TimePicker extends FrameLayout { if (!isEnabled()) { setEnabled(false); } + + // set the content descriptions + if (AccessibilityManager.getInstance(mContext).isEnabled()) { + setContentDescriptions(); + } } @Override @@ -433,6 +439,12 @@ public class TimePicker extends FrameLayout { } @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + onPopulateAccessibilityEvent(event); + return true; + } + + @Override public void onPopulateAccessibilityEvent(AccessibilityEvent event) { super.onPopulateAccessibilityEvent(event); @@ -487,4 +499,22 @@ public class TimePicker extends FrameLayout { mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute()); } } + + private void setContentDescriptions() { + // Minute + String text = mContext.getString(R.string.time_picker_increment_minute_button); + mMinuteSpinner.findViewById(R.id.increment).setContentDescription(text); + text = mContext.getString(R.string.time_picker_decrement_minute_button); + mMinuteSpinner.findViewById(R.id.decrement).setContentDescription(text); + // Hour + text = mContext.getString(R.string.time_picker_increment_hour_button); + mHourSpinner.findViewById(R.id.increment).setContentDescription(text); + text = mContext.getString(R.string.time_picker_decrement_hour_button); + mHourSpinner.findViewById(R.id.decrement).setContentDescription(text); + // AM/PM + text = mContext.getString(R.string.time_picker_increment_set_pm_button); + mAmPmSpinner.findViewById(R.id.increment).setContentDescription(text); + text = mContext.getString(R.string.time_picker_decrement_set_am_button); + mAmPmSpinner.findViewById(R.id.decrement).setContentDescription(text); + } } 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 @@ interface IInputMethodManager { 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/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java index 76bc535..cd1f8ba 100644 --- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java +++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java @@ -902,13 +902,13 @@ public class MultiWaveView extends View { String directionDescription = getDirectionDescription(i); if (!TextUtils.isEmpty(targetDescription) && !TextUtils.isEmpty(directionDescription)) { - utterance.append(targetDescription); - utterance.append(" "); - utterance.append(directionDescription); - utterance.append("."); + String text = String.format(directionDescription, targetDescription); + utterance.append(text); + } + if (utterance.length() > 0) { + announceText(utterance.toString()); } } - announceText(utterance.toString()); } private void announceText(String text) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 01f2a8f..f50cecd 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -920,7 +920,7 @@ <!-- Allows applications to write the apn settings --> <permission android:name="android.permission.WRITE_APN_SETTINGS" android:permissionGroup="android.permission-group.SYSTEM_TOOLS" - android:protectionLevel="dangerous" + android:protectionLevel="signatureOrSystem" android:description="@string/permdesc_writeApnSettings" android:label="@string/permlab_writeApnSettings" /> diff --git a/core/res/res/anim/wallpaper_close_exit.xml b/core/res/res/anim/wallpaper_close_exit.xml index 7e0e05f..987fd89 100644 --- a/core/res/res/anim/wallpaper_close_exit.xml +++ b/core/res/res/anim/wallpaper_close_exit.xml @@ -29,4 +29,7 @@ android:fillEnabled="true" android:fillAfter="true" android:interpolator="@interpolator/decelerate_quint" android:duration="300" /> + <!-- This is needed to keep the animation running while wallpaper_close_enter completes --> + <alpha android:fromAlpha="1.0" android:toAlpha="1.0" + android:duration="600" /> </set>
\ No newline at end of file diff --git a/core/res/res/anim/wallpaper_open_exit.xml b/core/res/res/anim/wallpaper_open_exit.xml index 075831b..1804fa8 100644 --- a/core/res/res/anim/wallpaper_open_exit.xml +++ b/core/res/res/anim/wallpaper_open_exit.xml @@ -29,5 +29,7 @@ android:interpolator="@interpolator/accelerate_quint" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" android:duration="200" /> - + <!-- This is needed to keep the animation running while wallpaper_open_enter completes --> + <alpha android:fromAlpha="1.0" android:toAlpha="1.0" + android:duration="500" /> </set>
\ No newline at end of file diff --git a/core/res/res/drawable-hdpi/text_edit_paste_window.9.png b/core/res/res/drawable-hdpi/text_edit_paste_window.9.png Binary files differindex 6654e4d..b74f37b 100644 --- a/core/res/res/drawable-hdpi/text_edit_paste_window.9.png +++ b/core/res/res/drawable-hdpi/text_edit_paste_window.9.png diff --git a/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png b/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png Binary files differindex c97514f..b74f37b 100644 --- a/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png +++ b/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png diff --git a/core/res/res/drawable-mdpi/text_edit_paste_window.9.png b/core/res/res/drawable-mdpi/text_edit_paste_window.9.png Binary files differindex 41886eb..16f623d 100644 --- a/core/res/res/drawable-mdpi/text_edit_paste_window.9.png +++ b/core/res/res/drawable-mdpi/text_edit_paste_window.9.png diff --git a/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png b/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png Binary files differindex 88be6e1..16f623d 100644 --- a/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png +++ b/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png diff --git a/core/res/res/drawable-xhdpi/text_edit_paste_window.9.png b/core/res/res/drawable-xhdpi/text_edit_paste_window.9.png Binary files differnew file mode 100644 index 0000000..5c043b6 --- /dev/null +++ b/core/res/res/drawable-xhdpi/text_edit_paste_window.9.png diff --git a/core/res/res/drawable-xhdpi/text_edit_suggestions_window.9.png b/core/res/res/drawable-xhdpi/text_edit_suggestions_window.9.png Binary files differnew file mode 100644 index 0000000..5c043b6 --- /dev/null +++ b/core/res/res/drawable-xhdpi/text_edit_suggestions_window.9.png diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml index 4c8c0d1..0368530 100644 --- a/core/res/res/layout/keyguard_screen_tab_unlock.xml +++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml @@ -131,7 +131,7 @@ android:targetDrawables="@array/lockscreen_targets_with_camera" android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera" - android:directionDescriptions="@array/lockscreen_direction_descriptions_with_camera" + android:directionDescriptions="@array/lockscreen_direction_descriptions" android:handleDrawable="@drawable/ic_lockscreen_handle" android:waveDrawable="@drawable/ic_lockscreen_outerring" android:outerRadius="@dimen/multiwaveview_target_placement_radius" diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml index ba55f0c0..2849376 100644 --- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml +++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml @@ -136,7 +136,7 @@ android:targetDrawables="@array/lockscreen_targets_with_camera" android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera" - android:directionDescriptions="@array/lockscreen_direction_descriptions_with_camera" + android:directionDescriptions="@array/lockscreen_direction_descriptions" android:handleDrawable="@drawable/ic_lockscreen_handle" android:waveDrawable="@drawable/ic_lockscreen_outerring" android:outerRadius="@dimen/multiwaveview_target_placement_radius" diff --git a/core/res/res/layout/text_edit_action_popup_text.xml b/core/res/res/layout/text_edit_action_popup_text.xml index aa6a5e1..42e6f2e 100644 --- a/core/res/res/layout/text_edit_action_popup_text.xml +++ b/core/res/res/layout/text_edit_action_popup_text.xml @@ -25,4 +25,5 @@ android:textAppearance="?android:attr/textAppearanceSmallInverse" android:textColor="@android:color/black" android:textAllCaps="true" + android:textStyle="bold" /> diff --git a/core/res/res/values-land/arrays.xml b/core/res/res/values-land/arrays.xml index 57aafc8..68e5cfd 100644 --- a/core/res/res/values-land/arrays.xml +++ b/core/res/res/values-land/arrays.xml @@ -34,7 +34,7 @@ <item>@string/description_target_soundon</item> </array> - <array name="lockscreen_direction_descriptions_when_silent"> + <array name="lockscreen_direction_descriptions"> <item>@null</item> <item>@string/description_direction_up</item> <item>@null</item> @@ -55,13 +55,6 @@ <item>@string/description_target_silent</item> </array> - <array name="lockscreen_direction_descriptions_when_soundon"> - <item>@null</item> - <item>@string/description_direction_up</item> - <item>@null</item> - <item>@string/description_direction_down</item> - </array> - <array name="lockscreen_targets_with_camera"> <item>@null</item> <item>@drawable/ic_lockscreen_unlock</item> @@ -76,11 +69,4 @@ <item>@string/description_target_camera</item> </array> - <array name="lockscreen_direction_descriptions_with_camera"> - <item>@null</item> - <item>@string/description_direction_up</item> - <item>@null</item> - <item>@string/description_direction_down</item> - </array> - </resources> diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml index c9043ba..8d5bd0b 100644 --- a/core/res/res/values/arrays.xml +++ b/core/res/res/values/arrays.xml @@ -356,7 +356,7 @@ <item>@null</item> </array> - <array name="lockscreen_direction_descriptions_when_silent"> + <array name="lockscreen_direction_descriptions"> <item>@string/description_direction_right</item> <item>@null</item> <item>@string/description_direction_left</item> @@ -377,13 +377,6 @@ <item>@null</item> </array> - <array name="lockscreen_direction_descriptions_when_soundon"> - <item>@string/description_direction_right</item> - <item>@null</item> - <item>@string/description_direction_left</item> - <item>@null</item> - </array> - <array name="lockscreen_targets_with_camera"> <item>@drawable/ic_lockscreen_unlock</item> <item>@null</item> @@ -398,11 +391,4 @@ <item>@null</item> </array> - <array name="lockscreen_direction_descriptions_with_camera"> - <item>@string/description_direction_right</item> - <item>@null</item> - <item>@string/description_direction_left</item> - <item>@null</item> - </array> - </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index fed5651..0bf5b0a 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -158,10 +158,6 @@ <!-- The underline color and thickness for misspelled suggestion --> <attr name="textAppearanceMisspelledSuggestion" format="reference" /> - <!-- The text color and the background for suggestion range span. This span identifies the - portion of text the suggestions refer to). --> - <attr name="textAppearanceSuggestionRange" format="reference" /> - <!-- The underline color --> <attr name="textUnderlineColor" format="reference|color" /> <!-- The underline thickness --> @@ -2241,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" /> @@ -3154,10 +3154,6 @@ <attr name="textUnderlineColor" /> <attr name="textUnderlineThickness" /> </declare-styleable> - <declare-styleable name="SuggestionRangeSpan"> - <attr name="textColor" /> - <attr name="colorBackground" /> - </declare-styleable> <!-- An <code>input-extras</code> is a container for extra data to supply to an input method. Contains one more more {@link #Extra <extra>} tags. --> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index aee7ea4..fd525f3 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -54,8 +54,6 @@ <color name="dim_foreground_light_inverse">#bebebe</color> <color name="dim_foreground_light_inverse_disabled">#80bebebe</color> <color name="hint_foreground_light">#808080</color> - <color name="highlight_background">#cc475925</color> - <color name="highlight_background_inverse">#ccd2e461</color> <color name="highlighted_text_dark">#9983CC39</color> <color name="highlighted_text_light">#9983CC39</color> <color name="link_text_dark">#5c5cff</color> @@ -135,10 +133,8 @@ <color name="dim_foreground_inverse_holo_light">#bebebe</color> <color name="dim_foreground_inverse_disabled_holo_light">#80bebebe</color> <color name="hint_foreground_holo_light">#808080</color> - <color name="highlight_background_holo">#cc475925</color> - <color name="highlight_background_inverse_holo">#ccd2e461</color> - <color name="highlighted_text_holo_dark">#9983CC39</color> - <color name="highlighted_text_holo_light">#9983CC39</color> + <color name="highlighted_text_holo_dark">#4c33b5e5</color> + <color name="highlighted_text_holo_light">#4c33b5e5</color> <color name="link_text_holo_dark">#5c5cff</color> <color name="link_text_holo_light">#0000ee</color> 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 a9e2971..685ebb7 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3091,6 +3091,38 @@ <string name="number_picker_increment_button">Increment</string> <!-- Description of the button to decrement the NumberPicker value. [CHAR LIMIT=NONE] --> <string name="number_picker_decrement_button">Decrement</string> + <!-- Description of the tap and hold action to get into scroll mode in NumberPicker. [CHAR LIMIT=NONE] --> + <string name="number_picker_increment_scroll_mode"><xliff:g id="value" example="3">%s</xliff:g> tap and hold.</string> + <!-- Description of the scrolling action in NumberPicker. [CHAR LIMIT=NONE] --> + <string name="number_picker_increment_scroll_action">Slide up to increment and down to decrement.</string> + + <!-- TimePicker - accessibility support --> + <!-- Description of the button to increment the TimePicker's minute value. [CHAR LIMIT=NONE] --> + <string name="time_picker_increment_minute_button">Increment minute</string> + <!-- Description of the button to decrement the TimePicker's minute value. [CHAR LIMIT=NONE] --> + <string name="time_picker_decrement_minute_button">Decrement minute</string> + <!-- Description of the button to increment the TimePicker's hour value. [CHAR LIMIT=NONE] --> + <string name="time_picker_increment_hour_button">Increment hour</string> + <!-- Description of the button to decrement the TimePicker's hour value. [CHAR LIMIT=NONE] --> + <string name="time_picker_decrement_hour_button">Decrement hour</string> + <!-- Description of the button to increment the TimePicker's set PM value. [CHAR LIMIT=NONE] --> + <string name="time_picker_increment_set_pm_button">Set PM</string> + <!-- Description of the button to decrement the TimePicker's set AM value. [CHAR LIMIT=NONE] --> + <string name="time_picker_decrement_set_am_button">Set AM</string> + + <!-- DatePicker - accessibility support --> + <!-- Description of the button to increment the DatePicker's month value. [CHAR LIMIT=NONE] --> + <string name="date_picker_increment_month_button">Increment month</string> + <!-- Description of the button to decrement the DatePicker's month value. [CHAR LIMIT=NONE] --> + <string name="date_picker_decrement_month_button">Decrement month</string> + <!-- Description of the button to increment the DatePicker's day value. [CHAR LIMIT=NONE] --> + <string name="date_picker_increment_day_button">Increment day</string> + <!-- Description of the button to decrement the DatePicker's day value. [CHAR LIMIT=NONE] --> + <string name="date_picker_decrement_day_button">Decrement day</string> + <!-- Description of the button to increment the DatePicker's year value. [CHAR LIMIT=NONE] --> + <string name="date_picker_increment_year_button">Increment year</string> + <!-- Description of the button to decrement the DatePicker's year value. [CHAR LIMIT=NONE] --> + <string name="date_picker_decrement_year_button">Decrement year</string> <!-- CheckBox - accessibility support --> <!-- Description of the checked state of a CheckBox. [CHAR LIMIT=NONE] --> @@ -3138,13 +3170,13 @@ <string name="content_description_sliding_handle">"Sliding handle. Tap and hold."</string> <!-- Description of the up direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] --> - <string name="description_direction_up">"Up</string> + <string name="description_direction_up">Up for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string> <!-- Description of the down direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] --> - <string name="description_direction_down">Down</string> + <string name="description_direction_down">Down for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string> <!-- Description of the left direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] --> - <string name="description_direction_left">"Left</string> + <string name="description_direction_left">"Left for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string> <!-- Description of the right direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] --> - <string name="description_direction_right">Right</string> + <string name="description_direction_right">Right for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string> <!-- Description of the unlock target in the Slide unlock screen. [CHAR LIMIT=NONE] --> <string name="description_target_unlock">Unlock</string> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 1a2ad05..1a6a523 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -255,11 +255,6 @@ please see styles_device_defaults.xml. <item name="android:textUnderlineColor">@color/holo_red_light</item> </style> - <style name="TextAppearance.SuggestionRange"> - <item name="android:textColor">@color/white</item> - <item name="android:colorBackground">@color/holo_blue_dark</item> - </style> - <!-- Widget Styles --> <style name="Widget"> @@ -1554,6 +1549,7 @@ please see styles_device_defaults.xml. <style name="Widget.Holo.TextView.ListSeparator" parent="Widget.TextView.ListSeparator"> <item name="android:background">@android:drawable/list_section_divider_holo_dark</item> + <item name="android:textAllCaps">true</item> </style> <style name="Widget.Holo.TextSelectHandle" parent="Widget.TextSelectHandle"> @@ -1997,6 +1993,7 @@ please see styles_device_defaults.xml. <style name="Widget.Holo.Light.TextView.ListSeparator" parent="Widget.TextView.ListSeparator"> <item name="android:background">@android:drawable/list_section_divider_holo_light</item> + <item name="android:textAllCaps">true</item> </style> <style name="Widget.Holo.Light.TextSelectHandle" parent="Widget.TextSelectHandle"> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index 899c9d5..f434ce8 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -91,7 +91,6 @@ please see themes_device_defaults.xml. <item name="textAppearanceEasyCorrectSuggestion">@android:style/TextAppearance.EasyCorrectSuggestion</item> <item name="textAppearanceMisspelledSuggestion">@android:style/TextAppearance.MisspelledSuggestion</item> - <item name="textAppearanceSuggestionRange">@android:style/TextAppearance.SuggestionRange</item> <item name="textAppearanceButton">@android:style/TextAppearance.Widget.Button</item> diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk index cacbdaa..56bd2ce 100644 --- a/data/fonts/fonts.mk +++ b/data/fonts/fonts.mk @@ -14,15 +14,14 @@ # Warning: this is actually a product definition, to be inherited from +# On space-constrained devices, we include a subset of fonts: +# First, core/required fonts PRODUCT_COPY_FILES := \ frameworks/base/data/fonts/Roboto-Regular.ttf:system/fonts/Roboto-Regular.ttf \ frameworks/base/data/fonts/Roboto-Bold.ttf:system/fonts/Roboto-Bold.ttf \ frameworks/base/data/fonts/Roboto-Italic.ttf:system/fonts/Roboto-Italic.ttf \ frameworks/base/data/fonts/Roboto-BoldItalic.ttf:system/fonts/Roboto-BoldItalic.ttf \ - frameworks/base/data/fonts/DroidSans.ttf:system/fonts/DroidSans.ttf \ - frameworks/base/data/fonts/DroidSans-Bold.ttf:system/fonts/DroidSans-Bold.ttf \ frameworks/base/data/fonts/DroidNaskh-Regular.ttf:system/fonts/DroidNaskh-Regular.ttf \ - frameworks/base/data/fonts/DroidSansEthiopic-Regular.ttf:system/fonts/DroidSansEthiopic-Regular.ttf \ frameworks/base/data/fonts/DroidSansHebrew-Regular.ttf:system/fonts/DroidSansHebrew-Regular.ttf \ frameworks/base/data/fonts/DroidSansHebrew-Bold.ttf:system/fonts/DroidSansHebrew-Bold.ttf \ frameworks/base/data/fonts/DroidSansThai.ttf:system/fonts/DroidSansThai.ttf \ @@ -33,9 +32,22 @@ PRODUCT_COPY_FILES := \ 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/Clockopia.ttf:system/fonts/Clockopia.ttf \ - frameworks/base/data/fonts/DroidSansFallback.ttf:system/fonts/DroidSansFallback.ttf \ frameworks/base/data/fonts/AndroidClock.ttf:system/fonts/AndroidClock.ttf \ frameworks/base/data/fonts/AndroidClock_Highlight.ttf:system/fonts/AndroidClock_Highlight.ttf \ frameworks/base/data/fonts/AndroidClock_Solid.ttf:system/fonts/AndroidClock_Solid.ttf \ frameworks/base/data/fonts/system_fonts.xml:system/etc/system_fonts.xml \ frameworks/base/data/fonts/fallback_fonts.xml:system/etc/fallback_fonts.xml + +# Next, include additional fonts, depending on how much space we have +ifeq ($(SMALLER_FONT_FOOTPRINT),true) +# Smaller fonts alternatives +PRODUCT_COPY_FILES += \ + frameworks/base/data/fonts/DroidSansFallback.ttf:system/fonts/DroidSansFallback.ttf +else +# Full font set alternatives +PRODUCT_COPY_FILES += \ + frameworks/base/data/fonts/DroidSansFallbackFull.ttf:system/fonts/DroidSansFallback.ttf \ + frameworks/base/data/fonts/DroidSans.ttf:system/fonts/DroidSans.ttf \ + frameworks/base/data/fonts/DroidSans-Bold.ttf:system/fonts/DroidSans-Bold.ttf \ + frameworks/base/data/fonts/DroidSansEthiopic-Regular.ttf:system/fonts/DroidSansEthiopic-Regular.ttf +endif diff --git a/data/sounds/AudioPackage6.mk b/data/sounds/AudioPackage6.mk index fd6bf17..610e821 100755 --- a/data/sounds/AudioPackage6.mk +++ b/data/sounds/AudioPackage6.mk @@ -41,29 +41,4 @@ PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/notifications/ogg/Thallium.ogg:system/media/audio/notifications/Thallium.ogg \ $(LOCAL_PATH)/notifications/ogg/Xenon.ogg:system/media/audio/notifications/Xenon.ogg \ $(LOCAL_PATH)/notifications/ogg/Zirconium.ogg:system/media/audio/notifications/Zirconium.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \ - $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Bootes.ogg:system/media/audio/ringtones/Bootes.ogg \ - $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Cassiopeia.ogg:system/media/audio/ringtones/Cassiopeia.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Eridani.ogg:system/media/audio/ringtones/Eridani.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/hydra.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Iridium.ogg:system/media/audio/ringtones/Iridium.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Lyra.ogg:system/media/audio/ringtones/Lyra.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \ $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Testudo.ogg:system/media/audio/ringtones/Testudo.ogg \ - $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Vespa.ogg:system/media/audio/ringtones/Vespa.ogg diff --git a/data/sounds/alarms/ogg/Copernicium.ogg b/data/sounds/alarms/ogg/Copernicium.ogg Binary files differindex c619e8b..65d2867 100644 --- a/data/sounds/alarms/ogg/Copernicium.ogg +++ b/data/sounds/alarms/ogg/Copernicium.ogg diff --git a/data/sounds/alarms/ogg/Curium.ogg b/data/sounds/alarms/ogg/Curium.ogg Binary files differindex ebce391..125a236 100644 --- a/data/sounds/alarms/ogg/Curium.ogg +++ b/data/sounds/alarms/ogg/Curium.ogg diff --git a/data/sounds/alarms/ogg/Fermium.ogg b/data/sounds/alarms/ogg/Fermium.ogg Binary files differindex 6132565..6940442 100644 --- a/data/sounds/alarms/ogg/Fermium.ogg +++ b/data/sounds/alarms/ogg/Fermium.ogg diff --git a/data/sounds/alarms/ogg/Hassium.ogg b/data/sounds/alarms/ogg/Hassium.ogg Binary files differindex 408b7c2..86b2b71 100644 --- a/data/sounds/alarms/ogg/Hassium.ogg +++ b/data/sounds/alarms/ogg/Hassium.ogg diff --git a/data/sounds/alarms/ogg/Neptunium.ogg b/data/sounds/alarms/ogg/Neptunium.ogg Binary files differindex 058e2db..1a99141 100644 --- a/data/sounds/alarms/ogg/Neptunium.ogg +++ b/data/sounds/alarms/ogg/Neptunium.ogg diff --git a/data/sounds/alarms/ogg/Nobelium.ogg b/data/sounds/alarms/ogg/Nobelium.ogg Binary files differindex 33878c9..4309bc6 100644 --- a/data/sounds/alarms/ogg/Nobelium.ogg +++ b/data/sounds/alarms/ogg/Nobelium.ogg diff --git a/data/sounds/notifications/ogg/Altair.ogg b/data/sounds/notifications/ogg/Altair.ogg Binary files differindex d84b59e..407aeb9 100755..100644 --- a/data/sounds/notifications/ogg/Altair.ogg +++ b/data/sounds/notifications/ogg/Altair.ogg diff --git a/data/sounds/notifications/ogg/Antares.ogg b/data/sounds/notifications/ogg/Antares.ogg Binary files differindex 9d60917..409c684 100755..100644 --- a/data/sounds/notifications/ogg/Antares.ogg +++ b/data/sounds/notifications/ogg/Antares.ogg diff --git a/data/sounds/notifications/ogg/Betelgeuse.ogg b/data/sounds/notifications/ogg/Betelgeuse.ogg Binary files differindex 83c7722..488d1e8 100644 --- a/data/sounds/notifications/ogg/Betelgeuse.ogg +++ b/data/sounds/notifications/ogg/Betelgeuse.ogg diff --git a/data/sounds/notifications/ogg/Deneb.ogg b/data/sounds/notifications/ogg/Deneb.ogg Binary files differindex e58b3b6..b84eae3 100755..100644 --- a/data/sounds/notifications/ogg/Deneb.ogg +++ b/data/sounds/notifications/ogg/Deneb.ogg diff --git a/data/sounds/notifications/ogg/Hojus.ogg b/data/sounds/notifications/ogg/Hojus.ogg Binary files differindex fc8f73f..65b780c 100644 --- a/data/sounds/notifications/ogg/Hojus.ogg +++ b/data/sounds/notifications/ogg/Hojus.ogg diff --git a/data/sounds/notifications/ogg/Lalande.ogg b/data/sounds/notifications/ogg/Lalande.ogg Binary files differindex b6e253a..eda9c9d 100755..100644 --- a/data/sounds/notifications/ogg/Lalande.ogg +++ b/data/sounds/notifications/ogg/Lalande.ogg diff --git a/data/sounds/notifications/ogg/Mira.ogg b/data/sounds/notifications/ogg/Mira.ogg Binary files differindex f21e3c4..f5a6e94 100644 --- a/data/sounds/notifications/ogg/Mira.ogg +++ b/data/sounds/notifications/ogg/Mira.ogg diff --git a/data/sounds/notifications/ogg/Proxima.ogg b/data/sounds/notifications/ogg/Proxima.ogg Binary files differindex 235b5ca..53bf899 100644 --- a/data/sounds/notifications/ogg/Proxima.ogg +++ b/data/sounds/notifications/ogg/Proxima.ogg diff --git a/data/sounds/notifications/ogg/Upsilon.ogg b/data/sounds/notifications/ogg/Upsilon.ogg Binary files differindex 036dcad..e970422 100644 --- a/data/sounds/notifications/ogg/Upsilon.ogg +++ b/data/sounds/notifications/ogg/Upsilon.ogg diff --git a/data/sounds/ringtones/ogg/Cassiopeia.ogg b/data/sounds/ringtones/ogg/Cassiopeia.ogg Binary files differindex 61c4d27..b871940 100644 --- a/data/sounds/ringtones/ogg/Cassiopeia.ogg +++ b/data/sounds/ringtones/ogg/Cassiopeia.ogg diff --git a/data/sounds/ringtones/ogg/Lyra.ogg b/data/sounds/ringtones/ogg/Lyra.ogg Binary files differindex b7f740d..d170bc0 100644 --- a/data/sounds/ringtones/ogg/Lyra.ogg +++ b/data/sounds/ringtones/ogg/Lyra.ogg diff --git a/data/sounds/ringtones/ogg/Sceptrum.ogg b/data/sounds/ringtones/ogg/Sceptrum.ogg Binary files differindex 89d64d70..e94abe0 100644 --- a/data/sounds/ringtones/ogg/Sceptrum.ogg +++ b/data/sounds/ringtones/ogg/Sceptrum.ogg diff --git a/data/sounds/ringtones/ogg/Solarium.ogg b/data/sounds/ringtones/ogg/Solarium.ogg Binary files differindex 361367a..8dac71e 100644 --- a/data/sounds/ringtones/ogg/Solarium.ogg +++ b/data/sounds/ringtones/ogg/Solarium.ogg diff --git a/data/sounds/ringtones/ogg/UrsaMinor.ogg b/data/sounds/ringtones/ogg/UrsaMinor.ogg Binary files differindex a80801d..a90d1de 100644 --- a/data/sounds/ringtones/ogg/UrsaMinor.ogg +++ b/data/sounds/ringtones/ogg/UrsaMinor.ogg diff --git a/data/sounds/ringtones/ogg/Vespa.ogg b/data/sounds/ringtones/ogg/Vespa.ogg Binary files differindex 1f75ec8..f637831 100644 --- a/data/sounds/ringtones/ogg/Vespa.ogg +++ b/data/sounds/ringtones/ogg/Vespa.ogg diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 896f81e..ee65223 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -1594,7 +1594,7 @@ public class Paint { } /** - * Return the glypth Ids for the characters in the string. + * Return the glyph Ids for the characters in the string. * * @param text The text to measure * @param start The index of the first char to to measure @@ -1613,7 +1613,7 @@ public class Paint { * * Used only for BiDi / RTL Tests */ - public int getTextGlypths(String text, int start, int end, int contextStart, int contextEnd, + public int getTextGlyphs(String text, int start, int end, int contextStart, int contextEnd, int flags, char[] glyphs) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h index 6c91dfc..4a4bcfb 100644 --- a/include/camera/CameraParameters.h +++ b/include/camera/CameraParameters.h @@ -495,6 +495,25 @@ public: // Example value: "true" or "false". Read/write. static const char KEY_RECORDING_HINT[]; + // Returns true if video snapshot is supported. That is, applications + // can call Camera.takePicture during recording. Applications do not need to + // call Camera.startPreview after taking a picture. The preview will be + // still active. Other than that, taking a picture during recording is + // identical to taking a picture normally. All settings and methods related + // to takePicture work identically. Ex: KEY_PICTURE_SIZE, + // KEY_SUPPORTED_PICTURE_SIZES, KEY_JPEG_QUALITY, KEY_ROTATION, and etc. + // The picture will have an EXIF header. FLASH_MODE_AUTO and FLASH_MODE_ON + // also still work, but the video will record the flash. + // + // Applications can set shutter callback as null to avoid the shutter + // sound. It is also recommended to set raw picture and post view callbacks + // to null to avoid the interrupt of preview display. + // + // Field-of-view of the recorded video may be different from that of the + // captured pictures. + // Example value: "true" or "false". Read only. + static const char KEY_VIDEO_SNAPSHOT_SUPPORTED[]; + // Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED. static const char TRUE[]; static const char FALSE[]; 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 @@ public: 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 @@ class IMediaPlayerService: public IInterface 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 @@ public: 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 @@ private: 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/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h index f7f0ed7..d0940bb 100644 --- a/include/media/stagefright/SurfaceMediaSource.h +++ b/include/media/stagefright/SurfaceMediaSource.h @@ -34,7 +34,7 @@ class GraphicBuffer; class SurfaceMediaSource : public BnSurfaceTexture, public MediaSource, public MediaBufferObserver { public: - enum { MIN_UNDEQUEUED_BUFFERS = 3 }; + enum { MIN_UNDEQUEUED_BUFFERS = 4 }; enum { MIN_ASYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1, MIN_SYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp index 0eb5d50..0dcab6b 100644 --- a/libs/camera/CameraParameters.cpp +++ b/libs/camera/CameraParameters.cpp @@ -87,6 +87,7 @@ const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW[] = "max-num-detected-faces-hw"; const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw"; const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint"; +const char CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED[] = "video-snapshot-supported"; const char CameraParameters::TRUE[] = "true"; const char CameraParameters::FALSE[] = "false"; diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp index 44ea79c..0755fb7 100644 --- a/libs/rs/driver/rsdBcc.cpp +++ b/libs/rs/driver/rsdBcc.cpp @@ -37,6 +37,7 @@ using namespace android::renderscript; struct DrvScript { int (*mRoot)(); void (*mInit)(); + void (*mFreeChildren)(); BCCScriptRef mBccScript; @@ -125,6 +126,7 @@ bool rsdScriptInit(const Context *rsc, drv->mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(drv->mBccScript, "root")); drv->mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, "init")); + drv->mFreeChildren = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, ".rs.dtor")); exportFuncCount = drv->ME->getExportFuncCount(); if (exportFuncCount > 0) { @@ -430,6 +432,13 @@ void rsdScriptInvokeInit(const Context *dc, Script *script) { } } +void rsdScriptInvokeFreeChildren(const Context *dc, Script *script) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + + if (drv->mFreeChildren) { + drv->mFreeChildren(); + } +} void rsdScriptInvokeFunction(const Context *dc, Script *script, uint32_t slot, diff --git a/libs/rs/driver/rsdBcc.h b/libs/rs/driver/rsdBcc.h index 67929bc..5f83ed2 100644 --- a/libs/rs/driver/rsdBcc.h +++ b/libs/rs/driver/rsdBcc.h @@ -43,6 +43,8 @@ int rsdScriptInvokeRoot(const android::renderscript::Context *dc, android::renderscript::Script *script); void rsdScriptInvokeInit(const android::renderscript::Context *dc, android::renderscript::Script *script); +void rsdScriptInvokeFreeChildren(const android::renderscript::Context *dc, + android::renderscript::Script *script); void rsdScriptSetGlobalVar(const android::renderscript::Context *, const android::renderscript::Script *, diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp index 171d045..a38fff7 100644 --- a/libs/rs/driver/rsdCore.cpp +++ b/libs/rs/driver/rsdCore.cpp @@ -60,6 +60,7 @@ static RsdHalFunctions FunctionTable = { rsdScriptInvokeRoot, rsdScriptInvokeForEach, rsdScriptInvokeInit, + rsdScriptInvokeFreeChildren, rsdScriptSetGlobalVar, rsdScriptSetGlobalBind, rsdScriptSetGlobalObj, diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp index f62c72e..93513fe 100644 --- a/libs/rs/rsScript.cpp +++ b/libs/rs/rsScript.cpp @@ -72,6 +72,12 @@ void Script::setVarObj(uint32_t slot, ObjectBase *val) { mRSC->mHal.funcs.script.setGlobalObj(mRSC, this, slot, val); } +bool Script::freeChildren() { + incSysRef(); + mRSC->mHal.funcs.script.invokeFreeChildren(mRSC, this); + return decSysRef(); +} + namespace android { namespace renderscript { diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h index c0324dd..d645421 100644 --- a/libs/rs/rsScript.h +++ b/libs/rs/rsScript.h @@ -73,6 +73,8 @@ public: void setVar(uint32_t slot, const void *val, size_t len); void setVarObj(uint32_t slot, ObjectBase *val); + virtual bool freeChildren(); + virtual void runForEach(Context *rsc, const Allocation * ain, Allocation * aout, diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp index dccf71f..2e7f213 100644 --- a/libs/rs/rsScriptC.cpp +++ b/libs/rs/rsScriptC.cpp @@ -44,6 +44,7 @@ ScriptC::~ScriptC() { BT = NULL; } #endif + mRSC->mHal.funcs.script.invokeFreeChildren(mRSC, this); mRSC->mHal.funcs.script.destroy(mRSC, this); } diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h index 21dff21..b8d7351 100644 --- a/libs/rs/rs_hal.h +++ b/libs/rs/rs_hal.h @@ -90,6 +90,7 @@ typedef struct { uint32_t usrLen, const RsScriptCall *sc); void (*invokeInit)(const Context *rsc, Script *s); + void (*invokeFreeChildren)(const Context *rsc, Script *s); void (*setGlobalVar)(const Context *rsc, const Script *s, uint32_t slot, diff --git a/libs/rs/scriptc/rs_cl.rsh b/libs/rs/scriptc/rs_cl.rsh index 98b0b1d..bbc8fc5 100644 --- a/libs/rs/scriptc/rs_cl.rsh +++ b/libs/rs/scriptc/rs_cl.rsh @@ -660,7 +660,6 @@ FN_FUNC_FN(tgamma) extern float __attribute__((overloadable)) trunc(float); FN_FUNC_FN(trunc) -// Int ops (partial), 6.11.3 #define XN_FUNC_YN(typeout, fnc, typein) \ extern typeout __attribute__((overloadable)) fnc(typein); \ @@ -704,14 +703,29 @@ XN_FUNC_XN_XN_BODY(float, fnc, body) UIN_FUNC_IN(abs) IN_FUNC_IN(clz) +/** + * Return the minimum of two values. + * + * Supports 1,2,3,4 components of uchar, char, ushort, short, uint, int, float. + */ IN_FUNC_IN_IN_BODY(min, (v1 < v2 ? v1 : v2)) FN_FUNC_FN_F(min) +/** + * Return the maximum of two values. + * + * Supports 1,2,3,4 components of uchar, char, ushort, short, uint, int, float. + */ IN_FUNC_IN_IN_BODY(max, (v1 > v2 ? v1 : v2)) FN_FUNC_FN_F(max) -// 6.11.4 - +/** + * Clamp a value to a specified high and low bound. + * + * @param amount value to be clamped. Supports 1,2,3,4 components + * @param low Lower bound, must be scalar or matching vector. + * @param high High bound, must match type of low + */ _RS_RUNTIME float __attribute__((overloadable)) clamp(float amount, float low, float high); _RS_RUNTIME float2 __attribute__((overloadable)) clamp(float2 amount, float2 low, float2 high); _RS_RUNTIME float3 __attribute__((overloadable)) clamp(float3 amount, float3 low, float3 high); @@ -720,9 +734,19 @@ _RS_RUNTIME float2 __attribute__((overloadable)) clamp(float2 amount, float low, _RS_RUNTIME float3 __attribute__((overloadable)) clamp(float3 amount, float low, float high); _RS_RUNTIME float4 __attribute__((overloadable)) clamp(float4 amount, float low, float high); +/** + * Convert from radians to degrees. + * + * Supports 1,2,3,4 components + */ _RS_RUNTIME float __attribute__((overloadable)) degrees(float radians); FN_FUNC_FN(degrees) +/** + * return start + ((stop - start) * amount); + * + * Supports 1,2,3,4 components + */ _RS_RUNTIME float __attribute__((overloadable)) mix(float start, float stop, float amount); _RS_RUNTIME float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float2 amount); _RS_RUNTIME float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float3 amount); @@ -731,9 +755,22 @@ _RS_RUNTIME float2 __attribute__((overloadable)) mix(float2 start, float2 stop, _RS_RUNTIME float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float amount); _RS_RUNTIME float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float amount); +/** + * Convert from degrees to radians. + * + * Supports 1,2,3,4 components + */ _RS_RUNTIME float __attribute__((overloadable)) radians(float degrees); FN_FUNC_FN(radians) +/** + * if (v < edge) + * return 0.f; + * else + * return 1.f; + * + * Supports 1,2,3,4 components + */ _RS_RUNTIME float __attribute__((overloadable)) step(float edge, float v); _RS_RUNTIME float2 __attribute__((overloadable)) step(float2 edge, float2 v); _RS_RUNTIME float3 __attribute__((overloadable)) step(float3 edge, float3 v); @@ -742,6 +779,7 @@ _RS_RUNTIME float2 __attribute__((overloadable)) step(float2 edge, float v); _RS_RUNTIME float3 __attribute__((overloadable)) step(float3 edge, float v); _RS_RUNTIME float4 __attribute__((overloadable)) step(float4 edge, float v); +// not implemented extern float __attribute__((overloadable)) smoothstep(float, float, float); extern float2 __attribute__((overloadable)) smoothstep(float2, float2, float2); extern float3 __attribute__((overloadable)) smoothstep(float3, float3, float3); @@ -750,29 +788,59 @@ extern float2 __attribute__((overloadable)) smoothstep(float, float, float2); extern float3 __attribute__((overloadable)) smoothstep(float, float, float3); extern float4 __attribute__((overloadable)) smoothstep(float, float, float4); +/** + * if (v < 0) return -1.f; + * else if (v > 0) return 1.f; + * else return 0.f; + * + * Supports 1,2,3,4 components + */ _RS_RUNTIME float __attribute__((overloadable)) sign(float v); FN_FUNC_FN(sign) -// 6.11.5 +/** + * Compute the cross product of two vectors. + * + * Supports 3,4 components + */ _RS_RUNTIME float3 __attribute__((overloadable)) cross(float3 lhs, float3 rhs); - _RS_RUNTIME float4 __attribute__((overloadable)) cross(float4 lhs, float4 rhs); +/** + * Compute the dot product of two vectors. + * + * Supports 1,2,3,4 components + */ _RS_RUNTIME float __attribute__((overloadable)) dot(float lhs, float rhs); _RS_RUNTIME float __attribute__((overloadable)) dot(float2 lhs, float2 rhs); _RS_RUNTIME float __attribute__((overloadable)) dot(float3 lhs, float3 rhs); _RS_RUNTIME float __attribute__((overloadable)) dot(float4 lhs, float4 rhs); +/** + * Compute the length of a vector. + * + * Supports 1,2,3,4 components + */ _RS_RUNTIME float __attribute__((overloadable)) length(float v); _RS_RUNTIME float __attribute__((overloadable)) length(float2 v); _RS_RUNTIME float __attribute__((overloadable)) length(float3 v); _RS_RUNTIME float __attribute__((overloadable)) length(float4 v); +/** + * Compute the distance between two points. + * + * Supports 1,2,3,4 components + */ _RS_RUNTIME float __attribute__((overloadable)) distance(float lhs, float rhs); _RS_RUNTIME float __attribute__((overloadable)) distance(float2 lhs, float2 rhs); _RS_RUNTIME float __attribute__((overloadable)) distance(float3 lhs, float3 rhs); _RS_RUNTIME float __attribute__((overloadable)) distance(float4 lhs, float4 rhs); +/** + * Normalize a vector. + * + * Supports 1,2,3,4 components + */ _RS_RUNTIME float __attribute__((overloadable)) normalize(float v); _RS_RUNTIME float2 __attribute__((overloadable)) normalize(float2 v); _RS_RUNTIME float3 __attribute__((overloadable)) normalize(float3 v); diff --git a/libs/rs/scriptc/rs_quaternion.rsh b/libs/rs/scriptc/rs_quaternion.rsh index 36e6736..23945ae 100644 --- a/libs/rs/scriptc/rs_quaternion.rsh +++ b/libs/rs/scriptc/rs_quaternion.rsh @@ -14,7 +14,7 @@ * limitations under the License. */ -/** @file rs_matrix.rsh +/** @file rs_quaternion.rsh * \brief Quaternion routines * * diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index ddd9d1f..cd15718 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -2638,7 +2638,7 @@ public class AudioService extends IAudioService.Stub { notifyTopOfAudioFocusStack(); // there's a new top of the stack, let the remote control know synchronized(mRCStack) { - checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL); + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } } } else { @@ -2681,7 +2681,7 @@ public class AudioService extends IAudioService.Stub { notifyTopOfAudioFocusStack(); // there's a new top of the stack, let the remote control know synchronized(mRCStack) { - checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL); + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } } } @@ -2785,7 +2785,7 @@ public class AudioService extends IAudioService.Stub { // there's a new top of the stack, let the remote control know synchronized(mRCStack) { - checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL); + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } }//synchronized(mAudioFocusLock) @@ -3183,7 +3183,7 @@ public class AudioService extends IAudioService.Stub { * Helper function: * Called synchronized on mRCStack */ - private void clearRemoteControlDisplay_syncRcs() { + private void clearRemoteControlDisplay_syncAfRcs() { synchronized(mCurrentRcLock) { mCurrentRcClient = null; } @@ -3192,18 +3192,21 @@ public class AudioService extends IAudioService.Stub { } /** - * Helper function: - * Called synchronized on mRCStack - * mRCStack.isEmpty() is false + * Helper function for code readability: only to be called from + * checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for + * this method. + * Preconditions: + * - called synchronized mAudioFocusLock then on mRCStack + * - mRCStack.isEmpty() is false */ - private void updateRemoteControlDisplay_syncRcs(int infoChangedFlags) { + private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { RemoteControlStackEntry rcse = mRCStack.peek(); int infoFlagsAboutToBeUsed = infoChangedFlags; // this is where we enforce opt-in for information display on the remote controls // with the new AudioManager.registerRemoteControlClient() API if (rcse.mRcClient == null) { //Log.w(TAG, "Can't update remote control display with null remote control client"); - clearRemoteControlDisplay_syncRcs(); + clearRemoteControlDisplay_syncAfRcs(); return; } synchronized(mCurrentRcLock) { @@ -3220,17 +3223,17 @@ public class AudioService extends IAudioService.Stub { /** * Helper function: - * Called synchronized on mFocusLock, then mRCStack + * Called synchronized on mAudioFocusLock, then mRCStack * Check whether the remote control display should be updated, triggers the update if required * @param infoChangedFlags the flags corresponding to the remote control client information * that has changed, if applicable (checking for the update conditions might trigger a * clear, rather than an update event). */ - private void checkUpdateRemoteControlDisplay_syncRcs(int infoChangedFlags) { + private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { // determine whether the remote control display should be refreshed // if either stack is empty, there is a mismatch, so clear the RC display if (mRCStack.isEmpty() || mFocusStack.isEmpty()) { - clearRemoteControlDisplay_syncRcs(); + clearRemoteControlDisplay_syncAfRcs(); return; } // if the top of the two stacks belong to different packages, there is a mismatch, clear @@ -3238,18 +3241,18 @@ public class AudioService extends IAudioService.Stub { && (mFocusStack.peek().mPackageName != null) && !(mRCStack.peek().mCallingPackageName.compareTo( mFocusStack.peek().mPackageName) == 0)) { - clearRemoteControlDisplay_syncRcs(); + clearRemoteControlDisplay_syncAfRcs(); return; } // if the audio focus didn't originate from the same Uid as the one in which the remote // control information will be retrieved, clear if (mRCStack.peek().mCallingUid != mFocusStack.peek().mCallingUid) { - clearRemoteControlDisplay_syncRcs(); + clearRemoteControlDisplay_syncAfRcs(); return; } // refresh conditions were verified: update the remote controls - // ok to call, mRCStack is not empty - updateRemoteControlDisplay_syncRcs(infoChangedFlags); + // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty + updateRemoteControlDisplay_syncAfRcs(infoChangedFlags); } /** see AudioManager.registerMediaButtonEventReceiver(ComponentName eventReceiver) */ @@ -3260,7 +3263,7 @@ public class AudioService extends IAudioService.Stub { synchronized(mRCStack) { pushMediaButtonReceiver(eventReceiver); // new RC client, assume every type of information shall be queried - checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL); + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } } } @@ -3275,7 +3278,7 @@ public class AudioService extends IAudioService.Stub { removeMediaButtonReceiver(eventReceiver); if (topOfStackWillChange) { // current RC client will change, assume every type of info needs to be queried - checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL); + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } } } @@ -3284,6 +3287,7 @@ public class AudioService extends IAudioService.Stub { /** see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) */ public void registerRemoteControlClient(ComponentName eventReceiver, IRemoteControlClient rcClient, String clientName, String callingPackageName) { + if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient); synchronized(mAudioFocusLock) { synchronized(mRCStack) { // store the new display information @@ -3331,7 +3335,7 @@ public class AudioService extends IAudioService.Stub { // if the eventReceiver is at the top of the stack // then check for potential refresh of the remote controls if (isCurrentRcController(eventReceiver)) { - checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL); + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } } } @@ -3436,35 +3440,35 @@ public class AudioService extends IAudioService.Stub { */ public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) { if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")"); - synchronized(mRCStack) { - if ((mRcDisplay == rcd) || (rcd == null)) { - return; - } - // if we had a display before, stop monitoring its death - rcDisplay_stopDeathMonitor_syncRcStack(); - mRcDisplay = rcd; - // new display, start monitoring its death - rcDisplay_startDeathMonitor_syncRcStack(); + synchronized(mAudioFocusLock) { + synchronized(mRCStack) { + if ((mRcDisplay == rcd) || (rcd == null)) { + return; + } + // if we had a display before, stop monitoring its death + rcDisplay_stopDeathMonitor_syncRcStack(); + mRcDisplay = rcd; + // new display, start monitoring its death + rcDisplay_startDeathMonitor_syncRcStack(); - // let all the remote control clients there is a new display - // no need to unplug the previous because we only support one display - // and the clients don't track the death of the display - Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); - while(stackIterator.hasNext()) { - RemoteControlStackEntry rcse = stackIterator.next(); - if(rcse.mRcClient != null) { - try { - rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay); - } catch (RemoteException e) { - Log.e(TAG, "Error connecting remote control display to client: " + e); - e.printStackTrace(); + // let all the remote control clients there is a new display + // no need to unplug the previous because we only support one display + // and the clients don't track the death of the display + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + RemoteControlStackEntry rcse = stackIterator.next(); + if(rcse.mRcClient != null) { + try { + rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay); + } catch (RemoteException e) { + Log.e(TAG, "Error connecting remote control display to client: " + e); + e.printStackTrace(); + } } } - } - if (!mRCStack.isEmpty()) { // we have a new display, of which all the clients are now aware: have it be updated - updateRemoteControlDisplay_syncRcs(RC_INFO_ALL); + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } } } 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 @@ import java.lang.ref.WeakReference; * 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 @@ public class MediaPlayer fd.close(); } } + Log.d(TAG, "Couldn't open file on client side, trying server side"); setDataSource(uri.toString(), headers); return; @@ -839,7 +843,8 @@ public class MediaPlayer * @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 @@ public class MediaPlayer * @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 @@ public class MediaPlayer 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 @@ static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStat } 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 @@ public: 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 @@ status_t BnMediaPlayer::onTransact( 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 @@ public: } 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 @@ public: 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 @@ status_t BnMediaPlayerService::onTransact( 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); - - 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); + sp<IMediaPlayer> player = create(pid, client, 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::setListener(const sp<MediaPlayerListener>& listener) } -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 @@ status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player) 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 @@ status_t MediaPlayer::setDataSource( 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 MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length) 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 @@ bool findMetadata(const Metadata::Filter& filter, const int32_t val) 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 @@ sp<IMediaMetadataRetriever> MediaPlayerService::createMetadataRetriever(pid_t pi 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 @@ sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClie 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; - 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); + LOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid, + IPCThreadState::self()->getCallingUid()); - if (OK != c->setDataSource(source)) { - c.clear(); - } else { - wp<Client> w = c; + wp<Client> w = c; + { Mutex::Autolock lock(mLock); mClients.add(w); } - return c; } @@ -701,6 +662,14 @@ status_t MediaPlayerService::Client::setDataSource( 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 @@ status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64 // 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 @@ public: 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 @@ private: 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/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index f98b0de..47224cc 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -978,7 +978,7 @@ status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) { CHECK(!mAudioPlayer->isSeeking()); // We will have finished the seek while starting the audio player. - postAudioSeekComplete_l(); + postAudioSeekComplete(); } } else { mAudioPlayer->resume(); @@ -1877,7 +1877,8 @@ void AwesomePlayer::postVideoLagEvent_l() { mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll); } -void AwesomePlayer::postCheckAudioStatusEvent_l(int64_t delayUs) { +void AwesomePlayer::postCheckAudioStatusEvent(int64_t delayUs) { + Mutex::Autolock autoLock(mAudioLock); if (mAudioStatusEventPending) { return; } @@ -1886,14 +1887,18 @@ void AwesomePlayer::postCheckAudioStatusEvent_l(int64_t delayUs) { } void AwesomePlayer::onCheckAudioStatus() { - Mutex::Autolock autoLock(mLock); - if (!mAudioStatusEventPending) { - // Event was dispatched and while we were blocking on the mutex, - // has already been cancelled. - return; + { + Mutex::Autolock autoLock(mAudioLock); + if (!mAudioStatusEventPending) { + // Event was dispatched and while we were blocking on the mutex, + // has already been cancelled. + return; + } + + mAudioStatusEventPending = false; } - mAudioStatusEventPending = false; + Mutex::Autolock autoLock(mLock); if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) { mWatchForAudioSeekComplete = false; @@ -2239,17 +2244,11 @@ uint32_t AwesomePlayer::flags() const { } void AwesomePlayer::postAudioEOS(int64_t delayUs) { - Mutex::Autolock autoLock(mLock); - postCheckAudioStatusEvent_l(delayUs); + postCheckAudioStatusEvent(delayUs); } void AwesomePlayer::postAudioSeekComplete() { - Mutex::Autolock autoLock(mLock); - postAudioSeekComplete_l(); -} - -void AwesomePlayer::postAudioSeekComplete_l() { - postCheckAudioStatusEvent_l(0 /* delayUs */); + postCheckAudioStatusEvent(0); } status_t AwesomePlayer::setParameter(int key, const Parcel &request) { 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 @@ ssize_t FileSource::readAt(off64_t offset, void *data, size_t size) { } status_t FileSource::getSize(off64_t *size) { + Mutex::Autolock autoLock(mLock); + if (mFd < 0) { return NO_INIT; } diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 24cf77c..8e73121 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -148,6 +148,7 @@ private: mutable Mutex mLock; Mutex mMiscStateLock; mutable Mutex mStatsLock; + Mutex mAudioLock; OMXClient mClient; TimedEventQueue mQueue; @@ -223,7 +224,7 @@ private: void postVideoEvent_l(int64_t delayUs = -1); void postBufferingEvent_l(); void postStreamDoneEvent_l(status_t status); - void postCheckAudioStatusEvent_l(int64_t delayUs); + void postCheckAudioStatusEvent(int64_t delayUs); void postVideoLagEvent_l(); status_t play_l(); @@ -295,7 +296,6 @@ private: void ensureCacheIsFetching_l(); status_t startAudioPlayer_l(bool sendErrorNotification = true); - void postAudioSeekComplete_l(); void shutdownVideoDecoder_l(); status_t setNativeWindow_l(const sp<ANativeWindow> &native); diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index 017d01c..e13464e 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -89,7 +89,7 @@ struct ATSParser::Stream : public RefBase { unsigned pid() const { return mElementaryPID; } void setPID(unsigned pid) { mElementaryPID = pid; } - void parse( + status_t parse( unsigned payload_unit_start_indicator, ABitReader *br); @@ -114,8 +114,8 @@ private: ElementaryStreamQueue *mQueue; - void flush(); - void parsePES(ABitReader *br); + status_t flush(); + status_t parsePES(ABitReader *br); void onPayloadData( unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS, @@ -159,7 +159,7 @@ bool ATSParser::Program::parsePID( return false; } - mStreams.editValueAt(index)->parse( + *err = mStreams.editValueAt(index)->parse( payload_unit_start_indicator, br); return true; @@ -438,10 +438,10 @@ ATSParser::Stream::~Stream() { mQueue = NULL; } -void ATSParser::Stream::parse( +status_t ATSParser::Stream::parse( unsigned payload_unit_start_indicator, ABitReader *br) { if (mQueue == NULL) { - return; + return OK; } if (payload_unit_start_indicator) { @@ -450,14 +450,18 @@ void ATSParser::Stream::parse( // of a PES packet that we never saw the start of and assuming // we have a a complete PES packet. - flush(); + status_t err = flush(); + + if (err != OK) { + return err; + } } mPayloadStarted = true; } if (!mPayloadStarted) { - return; + return OK; } size_t payloadSizeBits = br->numBitsLeft(); @@ -478,6 +482,8 @@ void ATSParser::Stream::parse( memcpy(mBuffer->data() + mBuffer->size(), br->data(), payloadSizeBits / 8); mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8); + + return OK; } void ATSParser::Stream::signalDiscontinuity( @@ -526,7 +532,7 @@ void ATSParser::Stream::signalEOS(status_t finalResult) { } } -void ATSParser::Stream::parsePES(ABitReader *br) { +status_t ATSParser::Stream::parsePES(ABitReader *br) { unsigned packet_startcode_prefix = br->getBits(24); LOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix); @@ -534,7 +540,8 @@ void ATSParser::Stream::parsePES(ABitReader *br) { if (packet_startcode_prefix != 1) { LOGV("Supposedly payload_unit_start=1 unit does not start " "with startcode."); - return; + + return ERROR_MALFORMED; } CHECK_EQ(packet_startcode_prefix, 0x000001u); @@ -661,6 +668,14 @@ void ATSParser::Stream::parsePES(ABitReader *br) { unsigned dataLength = PES_packet_length - 3 - PES_header_data_length; + if (br->numBitsLeft() < dataLength * 8) { + LOGE("PES packet does not carry enough data to contain " + "payload. (numBitsLeft = %d, required = %d)", + br->numBitsLeft(), dataLength * 8); + + return ERROR_MALFORMED; + } + CHECK_GE(br->numBitsLeft(), dataLength * 8); onPayloadData( @@ -684,19 +699,24 @@ void ATSParser::Stream::parsePES(ABitReader *br) { CHECK_NE(PES_packet_length, 0u); br->skipBits(PES_packet_length * 8); } + + return OK; } -void ATSParser::Stream::flush() { +status_t ATSParser::Stream::flush() { if (mBuffer->size() == 0) { - return; + return OK; } LOGV("flushing stream 0x%04x size = %d", mElementaryPID, mBuffer->size()); ABitReader br(mBuffer->data(), mBuffer->size()); - parsePES(&br); + + status_t err = parsePES(&br); mBuffer->setRange(0, 0); + + return err; } void ATSParser::Stream::onPayloadData( diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index ddad2d3..ca62908 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -95,12 +95,12 @@ void initEglTraceLevel() { if (fgets(cmdline, sizeof(cmdline) - 1, file)) { if (!strcmp(value, cmdline)) - sEGLTraceLevel = 1; + gEGLDebugLevel = 1; } fclose(file); } - if (sEGLTraceLevel > 0) + if (gEGLDebugLevel > 0) { property_get("debug.egl.debug_port", value, "5039"); const unsigned short port = (unsigned short)atoi(value); @@ -117,7 +117,7 @@ void setGLHooksThreadSpecific(gl_hooks_t const *value) { if (sEGLTraceLevel > 0) { setGlTraceThreadSpecific(value); setGlThreadSpecific(&gHooksTrace); - } else if (sEGLTraceLevel > 0 && value != &gHooksNoContext) { + } else if (gEGLDebugLevel > 0 && value != &gHooksNoContext) { setGlTraceThreadSpecific(value); setGlThreadSpecific(&gHooksDebug); } else { diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp index ff9be3c..9e77665 100644 --- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp +++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp @@ -88,7 +88,7 @@ DbgContext* CreateDbgContext(const unsigned version, const gl_hooks_t * const ho msg.set_arg1(MAX_COMBINED_TEXTURE_IMAGE_UNITS); Send(msg, cmd); - *(DbgContext **)pthread_getspecific(dbgEGLThreadLocalStorageKey) = dbg; + pthread_setspecific(dbgEGLThreadLocalStorageKey, dbg); return dbg; } diff --git a/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png Binary files differdeleted file mode 100644 index 87c7be6..0000000 --- a/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png Binary files differindex 4f4ae78..4362836 100644 --- a/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png +++ b/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/recents_callout_line.9.png b/packages/SystemUI/res/drawable-hdpi/recents_callout_line.9.png Binary files differnew file mode 100644 index 0000000..335d5a8 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/recents_callout_line.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png Binary files differdeleted file mode 100644 index 5f4c035..0000000 --- a/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png Binary files differnew file mode 100644 index 0000000..1ad16f7 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png Binary files differdeleted file mode 100644 index 23aabce..0000000 --- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png Binary files differnew file mode 100644 index 0000000..6e806ee --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png Binary files differdeleted file mode 100644 index 0b0765b..0000000 --- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-large-hdpi/app_icon.png b/packages/SystemUI/res/drawable-large-hdpi/app_icon.png Binary files differdeleted file mode 100644 index 52354bd..0000000 --- a/packages/SystemUI/res/drawable-large-hdpi/app_icon.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png Binary files differdeleted file mode 100644 index ce01276..0000000 --- a/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-large-hdpi/recents_blue_glow.9.png Binary files differdeleted file mode 100644 index 1848fcd..0000000 --- a/packages/SystemUI/res/drawable-large-hdpi/recents_blue_glow.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-large-hdpi/recents_callout_line.png Binary files differdeleted file mode 100644 index 61a3f87..0000000 --- a/packages/SystemUI/res/drawable-large-hdpi/recents_callout_line.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg.png Binary files differdeleted file mode 100644 index b6aca49..0000000 --- a/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg_press.png Binary files differdeleted file mode 100644 index 226aaac..0000000 --- a/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg_press.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-large-mdpi/app_icon.png b/packages/SystemUI/res/drawable-large-mdpi/app_icon.png Binary files differdeleted file mode 100644 index 001811f..0000000 --- a/packages/SystemUI/res/drawable-large-mdpi/app_icon.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png Binary files differdeleted file mode 100644 index 3d0fbf2..0000000 --- a/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png Binary files differdeleted file mode 100644 index 4362836..0000000 --- a/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png Binary files differdeleted file mode 100644 index f4ccd7e..0000000 --- a/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png Binary files differdeleted file mode 100644 index 6392fa1..0000000 --- a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png Binary files differdeleted file mode 100644 index f6ee596..0000000 --- a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png Binary files differdeleted file mode 100644 index 87c7be6..0000000 --- a/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png Binary files differindex 4f4ae78..4362836 100644 --- a/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png +++ b/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/recents_callout_line.9.png b/packages/SystemUI/res/drawable-mdpi/recents_callout_line.9.png Binary files differnew file mode 100644 index 0000000..724a5cd --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/recents_callout_line.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png Binary files differdeleted file mode 100644 index 5f4c035..0000000 --- a/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png Binary files differnew file mode 100644 index 0000000..82ba091 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png Binary files differdeleted file mode 100644 index 23aabce..0000000 --- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png Binary files differnew file mode 100644 index 0000000..7376085 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png Binary files differdeleted file mode 100644 index 0b0765b..0000000 --- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/recents_blue_glow.9.png Binary files differnew file mode 100644 index 0000000..4ac131a --- /dev/null +++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/recents_blue_glow.9.png diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_blue_glow.9.png Binary files differindex 4f4ae78..4362836 100644 --- a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_blue_glow.9.png +++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_blue_glow.9.png diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_callout_line.png Binary files differdeleted file mode 100644 index 5f4c035..0000000 --- a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_callout_line.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg.png Binary files differdeleted file mode 100644 index 87a67c9..0000000 --- a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg_press.png Binary files differdeleted file mode 100644 index a1c39e6..0000000 --- a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg_press.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_bg_protect_tile.png Binary files differnew file mode 100644 index 0000000..59908ad --- /dev/null +++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_bg_protect_tile.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_blue_glow.9.png Binary files differnew file mode 100644 index 0000000..3938502 --- /dev/null +++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_blue_glow.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png Binary files differnew file mode 100644 index 0000000..e1e08c6 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_callout_line.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_callout_line.9.png Binary files differnew file mode 100644 index 0000000..1bd018a --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/recents_callout_line.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png Binary files differnew file mode 100644 index 0000000..0352aca --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png Binary files differnew file mode 100644 index 0000000..507ee22 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/app_icon.png b/packages/SystemUI/res/drawable-xlarge-hdpi/app_icon.png Binary files differdeleted file mode 100644 index 52354bd..0000000 --- a/packages/SystemUI/res/drawable-xlarge-hdpi/app_icon.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_bg_protect_tile.png Binary files differdeleted file mode 100644 index ce01276..0000000 --- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_bg_protect_tile.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_blue_glow.9.png Binary files differdeleted file mode 100644 index 1848fcd..0000000 --- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_blue_glow.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_callout_line.png Binary files differdeleted file mode 100644 index 846bc49..0000000 --- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_callout_line.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg.png Binary files differdeleted file mode 100644 index a983e12..0000000 --- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg_press.png Binary files differdeleted file mode 100644 index 7c6e44e..0000000 --- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg_press.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/app_icon.png b/packages/SystemUI/res/drawable-xlarge-mdpi/app_icon.png Binary files differdeleted file mode 100644 index 001811f..0000000 --- a/packages/SystemUI/res/drawable-xlarge-mdpi/app_icon.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_bg_protect_tile.png Binary files differdeleted file mode 100644 index 3d0fbf2..0000000 --- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_bg_protect_tile.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_blue_glow.9.png Binary files differdeleted file mode 100644 index 4362836..0000000 --- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_blue_glow.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_callout_line.png Binary files differdeleted file mode 100644 index f4ccd7e..0000000 --- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_callout_line.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg.png Binary files differdeleted file mode 100644 index 6392fa1..0000000 --- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg_press.png Binary files differdeleted file mode 100644 index f6ee596..0000000 --- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg_press.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml b/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml index 200bac4..6d05095 100644 --- a/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml +++ b/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml @@ -15,5 +15,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_pressed="true" /> + <item android:drawable="@drawable/recents_thumbnail_bg" android:state_activated="true" /> <item android:drawable="@*android:color/transparent"/> </selector> 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 16008a3..e99888c 100644 --- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml +++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml @@ -19,70 +19,74 @@ --> <!-- android:background="@drawable/status_bar_closed_default_background" --> -<RelativeLayout +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_height="wrap_content" - android:layout_width="@dimen/status_bar_recents_thumbnail_view_width"> + android:layout_height="match_parent" + android:layout_width="wrap_content"> - <FrameLayout android:id="@+id/app_thumbnail" - android:layout_width="wrap_content" + <RelativeLayout android:id="@+id/recent_item" + android:layout_gravity="bottom" android:layout_height="wrap_content" - android:layout_alignParentLeft="true" - 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_bg" - android:foreground="@drawable/recents_thumbnail_overlay"> - <ImageView android:id="@+id/app_thumbnail_image" - android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_width="wrap_content" + android:paddingBottom="@*android:dimen/status_bar_height"> + + <FrameLayout android:id="@+id/app_thumbnail" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + 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" + android:layout_height="match_parent" + android:visibility="invisible" + /> + </FrameLayout> + + <ImageView android:id="@+id/app_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignLeft="@id/app_thumbnail" + android:layout_alignTop="@id/app_thumbnail" + android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin" + android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin" + android:maxWidth="@dimen/status_bar_recents_app_icon_max_width" + android:maxHeight="@dimen/status_bar_recents_app_icon_max_height" + android:adjustViewBounds="true" android:visibility="invisible" /> - </FrameLayout> - - <ImageView android:id="@+id/app_icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignLeft="@id/app_thumbnail" - android:layout_alignTop="@id/app_thumbnail" - android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin" - android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin" - android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width" - android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height" - android:adjustViewBounds="true" - android:visibility="invisible" - /> - <TextView android:id="@+id/app_label" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textSize="@dimen/status_bar_recents_app_label_text_size" - android:fadingEdge="horizontal" - android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length" - android:scrollHorizontally="true" - android:layout_alignLeft="@id/app_thumbnail" - android:layout_below="@id/app_thumbnail" - android:layout_marginTop="@dimen/status_bar_recents_text_description_padding" - android:layout_marginLeft="@dimen/recents_thumbnail_bg_padding_left" - android:singleLine="true" - android:ellipsize="marquee" - android:visibility="invisible" - /> + <TextView android:id="@+id/app_label" + android:layout_width="@dimen/status_bar_recents_app_label_width" + android:layout_height="wrap_content" + android:textSize="@dimen/status_bar_recents_app_label_text_size" + android:fadingEdge="horizontal" + android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length" + android:scrollHorizontally="true" + android:layout_alignLeft="@id/app_thumbnail" + android:layout_below="@id/app_thumbnail" + android:layout_marginTop="@dimen/status_bar_recents_text_description_padding" + android:singleLine="true" + android:ellipsize="marquee" + android:visibility="invisible" + /> - <TextView android:id="@+id/app_description" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textSize="@dimen/status_bar_recents_app_description_text_size" - android:fadingEdge="horizontal" - android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length" - android:scrollHorizontally="true" - android:layout_alignLeft="@id/app_thumbnail" - android:layout_below="@id/app_label" - android:layout_marginTop="@dimen/status_bar_recents_text_description_padding" - android:layout_marginLeft="@dimen/recents_thumbnail_bg_padding_left" - android:singleLine="true" - android:ellipsize="marquee" - /> + <TextView android:id="@+id/app_description" + android:layout_width="@dimen/status_bar_recents_app_label_width" + android:layout_height="wrap_content" + android:textSize="@dimen/status_bar_recents_app_description_text_size" + android:fadingEdge="horizontal" + android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length" + android:scrollHorizontally="true" + android:layout_alignLeft="@id/app_thumbnail" + android:layout_below="@id/app_label" + android:layout_marginTop="@dimen/status_bar_recents_text_description_padding" + android:singleLine="true" + android:ellipsize="marquee" + /> -</RelativeLayout> + </RelativeLayout> +</FrameLayout> diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml index 20ef7cf..f84cc19 100644 --- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml +++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml @@ -30,13 +30,12 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentBottom="true" - android:paddingBottom="@*android:dimen/status_bar_height" android:clipToPadding="false" android:clipChildren="false"> <LinearLayout android:id="@+id/recents_glow" android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_height="match_parent" android:layout_gravity="bottom|right" android:orientation="horizontal" android:clipToPadding="false" @@ -44,7 +43,7 @@ > <com.android.systemui.recent.RecentsHorizontalScrollView android:id="@+id/recents_container" android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_height="match_parent" android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin" android:divider="@null" android:stackFromBottom="true" @@ -58,7 +57,7 @@ <LinearLayout android:id="@+id/recents_linear_layout" android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_height="match_parent" android:orientation="horizontal" android:clipToPadding="false" android:clipChildren="false"> 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 c0fce71..73ca335 100644 --- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml +++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml @@ -19,79 +19,83 @@ --> <!-- android:background="@drawable/status_bar_closed_default_background" --> -<RelativeLayout +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="wrap_content" - android:layout_width="@dimen/status_bar_recents_thumbnail_view_width"> + android:layout_width="match_parent"> - <FrameLayout android:id="@+id/app_thumbnail" - android:layout_width="wrap_content" + <RelativeLayout android:id="@+id/recent_item" 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_bg" - android:foreground="@drawable/recents_thumbnail_overlay"> - <ImageView android:id="@+id/app_thumbnail_image" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="invisible" - /> - </FrameLayout> + android:layout_width="match_parent"> - <ImageView android:id="@+id/app_icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignLeft="@id/app_thumbnail" - android:layout_alignTop="@id/app_thumbnail" - android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin" - android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin" - android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width" - android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height" - android:adjustViewBounds="true" - /> + <FrameLayout android:id="@+id/app_thumbnail" + android:layout_width="wrap_content" + 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"> + <ImageView android:id="@+id/app_thumbnail_image" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:visibility="invisible" + /> + </FrameLayout> - <TextView android:id="@+id/app_label" - android:layout_width="@dimen/status_bar_recents_app_label_width" - android:layout_height="wrap_content" - android:textSize="@dimen/status_bar_recents_app_label_text_size" - android:fadingEdge="horizontal" - android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length" - android:scrollHorizontally="true" - android:layout_alignParentLeft="true" - android:layout_alignTop="@id/app_icon" - android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin" - android:singleLine="true" - android:ellipsize="marquee" - /> + <ImageView android:id="@+id/app_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignLeft="@id/app_thumbnail" + android:layout_alignTop="@id/app_thumbnail" + android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin" + android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin" + android:maxWidth="@dimen/status_bar_recents_app_icon_max_width" + android:maxHeight="@dimen/status_bar_recents_app_icon_max_height" + android:adjustViewBounds="true" + /> - <View android:id="@+id/recents_callout_line" - android:layout_width="@dimen/status_bar_recents_app_label_width" - android:layout_height="1dip" - android:layout_alignParentLeft="true" - android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin" - android:layout_toLeftOf="@id/app_thumbnail" - android:layout_below="@id/app_label" - android:layout_marginRight="3dip" - android:layout_marginTop="3dip" - android:background="@drawable/recents_callout_line" - /> + <TextView android:id="@+id/app_label" + android:layout_width="@dimen/status_bar_recents_app_label_width" + android:layout_height="wrap_content" + android:textSize="@dimen/status_bar_recents_app_label_text_size" + android:fadingEdge="horizontal" + android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length" + android:scrollHorizontally="true" + android:layout_alignParentLeft="true" + android:layout_alignTop="@id/app_icon" + android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin" + android:singleLine="true" + android:ellipsize="marquee" + /> - <TextView android:id="@+id/app_description" - android:layout_width="@dimen/status_bar_recents_app_label_width" - android:layout_height="wrap_content" - android:textSize="@dimen/status_bar_recents_app_description_text_size" - android:fadingEdge="horizontal" - android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length" - android:scrollHorizontally="true" - android:layout_alignParentLeft="true" - android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin" - android:layout_below="@id/recents_callout_line" - android:layout_marginTop="3dip" - android:singleLine="true" - android:ellipsize="marquee" - /> + <View android:id="@+id/recents_callout_line" + android:layout_width="@dimen/status_bar_recents_app_label_width" + android:layout_height="1dip" + android:layout_alignParentLeft="true" + android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin" + android:layout_toLeftOf="@id/app_thumbnail" + android:layout_below="@id/app_label" + android:layout_marginRight="3dip" + android:layout_marginTop="3dip" + android:background="@drawable/recents_callout_line" + /> + + <TextView android:id="@+id/app_description" + android:layout_width="@dimen/status_bar_recents_app_label_width" + android:layout_height="wrap_content" + android:textSize="@dimen/status_bar_recents_app_description_text_size" + android:fadingEdge="horizontal" + android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length" + android:scrollHorizontally="true" + android:layout_alignParentLeft="true" + android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin" + android:layout_below="@id/recents_callout_line" + android:layout_marginTop="3dip" + android:singleLine="true" + android:ellipsize="marquee" + /> -</RelativeLayout> + </RelativeLayout> +</FrameLayout> 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 c680b8e..dd25cf9 100644 --- a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml +++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml @@ -40,7 +40,7 @@ android:layout_marginTop="@*android:dimen/status_bar_height"> <com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container" - android:layout_width="@dimen/status_bar_recents_width" + android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginRight="0dp" android:divider="@null" @@ -53,7 +53,7 @@ android:clipChildren="false"> <LinearLayout android:id="@+id/recents_linear_layout" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:clipToPadding="false" 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 5306508..cab90fd 100644 --- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml +++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml @@ -19,21 +19,20 @@ --> <!-- android:background="@drawable/status_bar_closed_default_background" --> -<RelativeLayout +<RelativeLayout android:id="@+id/recent_item" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="wrap_content" - android:layout_width="@dimen/status_bar_recents_thumbnail_view_width"> + android:layout_width="wrap_content"> <FrameLayout android:id="@+id/app_thumbnail" android:layout_width="wrap_content" 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:clickable="true" - android:background="@drawable/recents_thumbnail_bg" - android:foreground="@drawable/recents_thumbnail_overlay"> + android:background="@drawable/recents_thumbnail_overlay"> <ImageView android:id="@+id/app_thumbnail_image" android:layout_width="match_parent" android:layout_height="match_parent" @@ -48,8 +47,8 @@ android:layout_alignTop="@id/app_thumbnail" android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin" android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin" - android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width" - android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height" + android:maxWidth="@dimen/status_bar_recents_app_icon_max_width" + android:maxHeight="@dimen/status_bar_recents_app_icon_max_height" android:adjustViewBounds="true" /> diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml index 2c9a152..4ef602e 100644 --- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml +++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml @@ -47,7 +47,7 @@ android:clipChildren="false" > <com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container" - android:layout_width="@dimen/status_bar_recents_width" + android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin" android:divider="@null" diff --git a/packages/SystemUI/res/values-hdpi/dimens.xml b/packages/SystemUI/res/values-hdpi/dimens.xml index 287e0d1..6b6fd4d 100644 --- a/packages/SystemUI/res/values-hdpi/dimens.xml +++ b/packages/SystemUI/res/values-hdpi/dimens.xml @@ -16,12 +16,6 @@ */ --> <resources> - <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg --> - <dimen name="recents_thumbnail_bg_padding_left">6px</dimen> - <dimen name="recents_thumbnail_bg_padding_top">7px</dimen> - <dimen name="recents_thumbnail_bg_padding_right">6px</dimen> - <dimen name="recents_thumbnail_bg_padding_bottom">6px</dimen> - <!-- thickness (height) of each notification row, including any separators or padding --> <!-- Note: this is 64dip + 1px divider = 97px. --> <dimen name="notification_height">97px</dimen> diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml index 3919685..ca74b8b 100644 --- a/packages/SystemUI/res/values-land/dimens.xml +++ b/packages/SystemUI/res/values-land/dimens.xml @@ -20,18 +20,14 @@ <dimen name="navigation_bar_size">@*android:dimen/navigation_bar_width</dimen> <!-- Recent Applications parameters --> - <!-- Width of a recent app view, including all content --> - <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen> <!-- How far the thumbnail for a recent app appears from left edge --> <dimen name="status_bar_recents_thumbnail_left_margin">8dp</dimen> <!-- How far the thumbnail for a recent app appears from top edge --> <dimen name="status_bar_recents_thumbnail_top_margin">12dp</dimen> - <!-- Width of scrollable area in recents --> - <dimen name="status_bar_recents_width">128dp</dimen> <!-- Padding for text descriptions --> <dimen name="status_bar_recents_text_description_padding">8dp</dimen> <!-- Width of application label text --> - <dimen name="status_bar_recents_app_label_width">97dip</dimen> + <dimen name="status_bar_recents_app_label_width">156dip</dimen> <!-- Left margin of application label text --> <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen> <!-- Margin between recents container and glow on the right --> diff --git a/packages/SystemUI/res/values-mdpi/dimens.xml b/packages/SystemUI/res/values-mdpi/dimens.xml deleted file mode 100644 index 741b75a..0000000 --- a/packages/SystemUI/res/values-mdpi/dimens.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - * Copyright (c) 2011, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ ---> -<resources> - <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg --> - <dimen name="recents_thumbnail_bg_padding_left">6px</dimen> - <dimen name="recents_thumbnail_bg_padding_top">7px</dimen> - <dimen name="recents_thumbnail_bg_padding_right">6px</dimen> - <dimen name="recents_thumbnail_bg_padding_bottom">6px</dimen> -</resources> diff --git a/packages/SystemUI/res/values-port/dimens.xml b/packages/SystemUI/res/values-port/dimens.xml index 54c25fa..b89a610 100644 --- a/packages/SystemUI/res/values-port/dimens.xml +++ b/packages/SystemUI/res/values-port/dimens.xml @@ -17,18 +17,14 @@ --> <resources> <!-- Recent Applications parameters --> - <!-- Width of a recent app view, including all content --> - <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen> <!-- How far the thumbnail for a recent app appears from left edge --> <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen> - <!-- Width of scrollable area in recents --> - <dimen name="status_bar_recents_width">356dp</dimen> <!-- Padding for text descriptions --> <dimen name="status_bar_recents_text_description_padding">8dp</dimen> <!-- Width of application label text --> <dimen name="status_bar_recents_app_label_width">97dip</dimen> <!-- Left margin of application label text --> - <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen> + <dimen name="status_bar_recents_app_label_left_margin">8dip</dimen> <!-- Margin between recents container and glow on the right --> <dimen name="status_bar_recents_right_glow_margin">100dip</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml new file mode 100644 index 0000000..3e2ec59 --- /dev/null +++ b/packages/SystemUI/res/values-sw600dp/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2011, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources> + + <!-- Whether we're using the tablet-optimized recents interface (we use this + value at runtime for some things) --> + <bool name="config_recents_interface_for_tablets">true</bool> +</resources> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index a5bea5c..fe9245d 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -30,16 +30,19 @@ <dimen name="panel_float">56dp</dimen> <!-- Recent Applications parameters --> - <!-- Width of a recent app view, including all content --> - <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen> <!-- How far the thumbnail for a recent app appears from left edge --> - <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen> + <dimen name="status_bar_recents_thumbnail_left_margin">121dp</dimen> <!-- Upper width limit for application icon --> - <dimen name="status_bar_recents_thumbnail_max_width">64dp</dimen> + <dimen name="status_bar_recents_app_icon_max_width">64dp</dimen> <!-- Upper height limit for application icon --> - <dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen> - <!-- Width of scrollable area in recents --> - <dimen name="status_bar_recents_width">356dp</dimen> + <dimen name="status_bar_recents_app_icon_max_height">64dp</dimen> + + <!-- Size of application icon --> + <dimen name="status_bar_recents_thumbnail_width">245dp</dimen> + <dimen name="status_bar_recents_thumbnail_height">144dp</dimen> + + <!-- Width of recents panel --> + <dimen name="status_bar_recents_width">600dp</dimen> <!-- Padding for text descriptions --> <dimen name="status_bar_recents_text_description_padding">8dp</dimen> <!-- Size of application label text --> @@ -55,12 +58,6 @@ <!-- Margin between recents container and glow on the right --> <dimen name="status_bar_recents_right_glow_margin">100dip</dimen> - <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg --> - <dimen name="recents_thumbnail_bg_padding_left">15px</dimen> - <dimen name="recents_thumbnail_bg_padding_top">8px</dimen> - <dimen name="recents_thumbnail_bg_padding_right">12px</dimen> - <dimen name="recents_thumbnail_bg_padding_bottom">8px</dimen> - <!-- Where to place the app icon over the thumbnail --> <dimen name="status_bar_recents_app_icon_left_margin">13dp</dimen> <dimen name="status_bar_recents_app_icon_top_margin">13dp</dimen> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 5d14fa8..4c222f9 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -22,5 +22,6 @@ <drawable name="ticker_background_color">#ff1d1d1d</drawable> <drawable name="status_bar_background">#ff000000</drawable> <drawable name="status_bar_recents_background">#b3000000</drawable> + <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable> <drawable name="status_bar_notification_row_background_color">#ff000000</drawable> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index d7d7817..4ac89b2 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -21,6 +21,10 @@ for different hardware and product builds. --> <resources> + <!-- Whether we're using the tablet-optimized recents interface (we use this + value at runtime for some things) --> + <bool name="config_recents_interface_for_tablets">false</bool> + <!-- Control whether status bar should distinguish HSPA data icon form UMTS data icon on devices --> <bool name="config_hspa_data_distinguishable">false</bool> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index f633825..d0ece6c 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -21,17 +21,21 @@ <!-- Recent Applications parameters --> <!-- Upper width limit for application icon --> - <dimen name="status_bar_recents_thumbnail_max_width">64dp</dimen> + <dimen name="status_bar_recents_app_icon_max_width">64dp</dimen> <!-- Upper height limit for application icon --> - <dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen> + <dimen name="status_bar_recents_app_icon_max_height">64dp</dimen> <!-- Where to place the app icon over the thumbnail --> <dimen name="status_bar_recents_app_icon_left_margin">13dp</dimen> <dimen name="status_bar_recents_app_icon_top_margin">13dp</dimen> + <!-- Size of application thumbnail --> + <dimen name="status_bar_recents_thumbnail_width">164dp</dimen> + <dimen name="status_bar_recents_thumbnail_height">164dp</dimen> + <!-- Size of application label text --> - <dimen name="status_bar_recents_app_label_text_size">18dip</dimen> + <dimen name="status_bar_recents_app_label_text_size">16dip</dimen> <!-- Size of application description text --> - <dimen name="status_bar_recents_app_description_text_size">18dip</dimen> + <dimen name="status_bar_recents_app_description_text_size">16dip</dimen> <!-- Size of fading edge for scroll effect --> <dimen name="status_bar_recents_fading_edge_length">20dip</dimen> <!-- Margin between recents container and glow on the right --> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 7779703..bad7e1f 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -36,10 +36,10 @@ <string name="status_bar_please_disturb_button">Show notifications</string> <!-- Title shown in recents popup for removing an application from the list --> - <string name="status_bar_recent_remove_item_title">Remove</string> + <string name="status_bar_recent_remove_item_title">Remove from list</string> <!-- Title shown in recents popup for inspecting an application's properties --> - <string name="status_bar_recent_inspect_item_title">Inspect</string> + <string name="status_bar_recent_inspect_item_title">App info</string> <!-- The label in the bar at the top of the status bar when there are no notifications showing. [CHAR LIMIT=40]--> diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index e7ed052..14743f4 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -33,20 +33,19 @@ public class SwipeHelper { private static final boolean DEBUG = false; private static final boolean DEBUG_INVALIDATE = false; private static final boolean SLOW_ANIMATIONS = false; // DEBUG; + private static final boolean CONSTRAIN_SWIPE = true; + private static final boolean FADE_OUT_DURING_SWIPE = true; + private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true; public static final int X = 0; public static final int Y = 1; - private boolean CONSTRAIN_SWIPE = true; - private boolean FADE_OUT_DURING_SWIPE = true; - private boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true; - private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec private int MAX_ESCAPE_ANIMATION_DURATION = 500; // ms private int MAX_DISMISS_VELOCITY = 1000; // dp/sec private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250; // ms - public static float ALPHA_FADE_START = 0.8f; // fraction of thumbnail width + public static float ALPHA_FADE_START = 0f; // fraction of thumbnail width // where fade starts static final float ALPHA_FADE_END = 0.5f; // fraction of thumbnail width // beyond which alpha->0 @@ -59,6 +58,8 @@ public class SwipeHelper { private float mInitialTouchPos; private boolean mDragging; private View mCurrView; + private View mCurrAnimView; + private boolean mCanCurrViewBeDimissed; private float mDensityScale; public SwipeHelper(int swipeDirection, Callback callback, float densityScale, @@ -82,8 +83,8 @@ public class SwipeHelper { return mSwipeDirection == X ? ev.getX() : ev.getY(); } - private float getPos(View v) { - return mSwipeDirection == X ? v.getX() : v.getY(); + private float getTranslation(View v) { + return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY(); } private float getVelocity(VelocityTracker vt) { @@ -115,19 +116,15 @@ public class SwipeHelper { v.getMeasuredHeight(); } - private float getContentSize(View v) { - View content = mCallback.getChildContentView(v); - return getSize(content); - } - - private float getAlphaForOffset(View view, float thumbSize) { - final float fadeSize = ALPHA_FADE_END * thumbSize; + private float getAlphaForOffset(View view) { + float viewSize = getSize(view); + final float fadeSize = ALPHA_FADE_END * viewSize; float result = 1.0f; - float pos = getPos(view); - if (pos >= thumbSize * ALPHA_FADE_START) { - result = 1.0f - (pos - thumbSize * ALPHA_FADE_START) / fadeSize; - } else if (pos < thumbSize * (1.0f - ALPHA_FADE_START)) { - result = 1.0f + (thumbSize * ALPHA_FADE_START + pos) / fadeSize; + float pos = getTranslation(view); + if (pos >= viewSize * ALPHA_FADE_START) { + result = 1.0f - (pos - viewSize * ALPHA_FADE_START) / fadeSize; + } else if (pos < viewSize * (1.0f - ALPHA_FADE_START)) { + result = 1.0f + (viewSize * ALPHA_FADE_START + pos) / fadeSize; } return result; } @@ -168,6 +165,8 @@ public class SwipeHelper { case MotionEvent.ACTION_DOWN: mDragging = false; mCurrView = mCallback.getChildAtPosition(ev); + mCurrAnimView = mCallback.getChildContentView(mCurrView); + mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView); mVelocityTracker.clear(); mVelocityTracker.addMovement(ev); mInitialTouchPos = getPos(ev); @@ -180,21 +179,24 @@ public class SwipeHelper { if (Math.abs(delta) > mPagingTouchSlop) { mCallback.onBeginDrag(mCurrView); mDragging = true; - mInitialTouchPos = getPos(ev) - getPos(mCurrView); + mInitialTouchPos = getPos(ev) - getTranslation(mCurrAnimView); } } break; case MotionEvent.ACTION_UP: mDragging = false; mCurrView = null; + mCurrAnimView = null; break; } return mDragging; } - public void dismissChild(final View animView, float velocity) { + public void dismissChild(final View view, float velocity) { + final View animView = mCallback.getChildContentView(view); + final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view); float newPos; - if (velocity < 0 || (velocity == 0 && getPos(animView) < 0)) { + if (velocity < 0 || (velocity == 0 && getTranslation(animView) < 0)) { newPos = -getSize(animView); } else { newPos = getSize(animView); @@ -202,7 +204,7 @@ public class SwipeHelper { int duration = MAX_ESCAPE_ANIMATION_DURATION; if (velocity != 0) { duration = Math.min(duration, - (int) (Math.abs(newPos - getPos(animView)) * 1000f / Math + (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math .abs(velocity))); } ObjectAnimator anim = createTranslationAnimation(animView, newPos); @@ -216,17 +218,17 @@ public class SwipeHelper { } public void onAnimationEnd(Animator animation) { - mCallback.onChildDismissed(animView); + mCallback.onChildDismissed(view); } public void onAnimationCancel(Animator animation) { - mCallback.onChildDismissed(animView); + mCallback.onChildDismissed(view); } }); anim.addUpdateListener(new AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { - if (FADE_OUT_DURING_SWIPE) { - animView.setAlpha(getAlphaForOffset(animView, getContentSize(animView))); + if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) { + animView.setAlpha(getAlphaForOffset(animView)); } invalidateGlobalRegion(animView); } @@ -234,14 +236,16 @@ public class SwipeHelper { anim.start(); } - public void snapChild(final View animView, float velocity) { + public void snapChild(final View view, float velocity) { + final View animView = mCallback.getChildContentView(view); + final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(animView); ObjectAnimator anim = createTranslationAnimation(animView, 0); int duration = SNAP_ANIM_LEN; anim.setDuration(duration); anim.addUpdateListener(new AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { - if (FADE_OUT_DURING_SWIPE) { - animView.setAlpha(getAlphaForOffset(animView, getContentSize(animView))); + if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) { + animView.setAlpha(getAlphaForOffset(animView)); } invalidateGlobalRegion(animView); } @@ -264,7 +268,7 @@ public class SwipeHelper { // don't let items that can't be dismissed be dragged more than // maxScrollDistance if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) { - float size = getSize(mCurrView); + float size = getSize(mCurrAnimView); float maxScrollDistance = 0.15f * size; if (Math.abs(delta) >= size) { delta = delta > 0 ? maxScrollDistance : -maxScrollDistance; @@ -272,9 +276,9 @@ public class SwipeHelper { delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2)); } } - setTranslation(mCurrView, delta); - if (FADE_OUT_DURING_SWIPE) { - mCurrView.setAlpha(getAlphaForOffset(mCurrView, getContentSize(mCurrView))); + setTranslation(mCurrAnimView, delta); + if (FADE_OUT_DURING_SWIPE && mCanCurrViewBeDimissed) { + mCurrAnimView.setAlpha(getAlphaForOffset(mCurrAnimView)); } invalidateGlobalRegion(mCurrView); } @@ -290,10 +294,10 @@ public class SwipeHelper { // Decide whether to dismiss the current view boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH && - Math.abs(getPos(mCurrView)) > 0.4 * getSize(mCurrView); + Math.abs(getTranslation(mCurrAnimView)) > 0.4 * getSize(mCurrAnimView); boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) && (Math.abs(velocity) > Math.abs(perpendicularVelocity)) && - (velocity > 0) == (getPos(mCurrView) > 0); + (velocity > 0) == (getTranslation(mCurrAnimView) > 0); boolean dismissChild = mCallback.canChildBeDismissed(mCurrView) && (childSwipedFastEnough || childSwipedFarEnough); @@ -303,6 +307,7 @@ public class SwipeHelper { dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f); } else { // snappity + mCallback.onDragCancelled(mCurrView); snapChild(mCurrView, velocity); } } @@ -321,5 +326,7 @@ public class SwipeHelper { void onBeginDrag(View v); void onChildDismissed(View v); + + void onDragCancelled(View v); } } diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java index 5609ead..2de4185 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java @@ -27,4 +27,8 @@ public interface RecentsCallback { void handleOnClick(View selectedView); void handleSwipe(View selectedView); void handleLongPress(View selectedView, View anchorView); + void handleShowBackground(boolean show); + + // TODO: find another way to get this info from RecentsPanelView + boolean isRecentsVisible(); } diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java index 8da2db6..85cde7c 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java @@ -20,6 +20,7 @@ import android.animation.LayoutTransition; import android.content.Context; import android.content.res.Configuration; import android.database.DataSetObserver; +import android.graphics.Canvas; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; @@ -41,6 +42,8 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView private RecentsCallback mCallback; protected int mLastScrollPosition; private SwipeHelper mSwipeHelper; + private RecentsScrollViewPerformanceHelper mPerformanceHelper; + private OnLongClickListener mOnLongClick = new OnLongClickListener() { public boolean onLongClick(View v) { final View anchorView = v.findViewById(R.id.app_description); @@ -49,15 +52,12 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView } }; - public RecentsHorizontalScrollView(Context context) { - this(context, null); - } - public RecentsHorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs, 0); float densityScale = getResources().getDisplayMetrics().density; float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop(); mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop); + mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, false); } private int scrollPositionOfMostRecent() { @@ -71,7 +71,11 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView view.setLongClickable(true); view.setOnLongClickListener(mOnLongClick); - final View thumbnail = getChildContentView(view); + if (mPerformanceHelper != null) { + mPerformanceHelper.addViewCallback(view); + } + + final View thumbnail = view.findViewById(R.id.app_thumbnail); // thumbnail is set to clickable in the layout file thumbnail.setOnClickListener(new OnClickListener() { public void onClick(View v) { @@ -123,6 +127,11 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView // We do this so the underlying ScrollView knows that it won't get // the chance to intercept events anymore requestDisallowInterceptTouchEvent(true); + v.setActivated(true); + } + + public void onDragCancelled(View v) { + v.setActivated(false); } public View getChildAtPosition(MotionEvent ev) { @@ -139,7 +148,60 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView } public View getChildContentView(View v) { - return v.findViewById(R.id.app_thumbnail); + return v.findViewById(R.id.recent_item); + } + + @Override + protected void onLayout (boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (mPerformanceHelper != null) { + mPerformanceHelper.onLayoutCallback(); + } + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + if (mPerformanceHelper != null) { + int paddingLeft = mPaddingLeft; + final boolean offsetRequired = isPaddingOffsetRequired(); + if (offsetRequired) { + paddingLeft += getLeftPaddingOffset(); + } + + int left = mScrollX + paddingLeft; + int right = left + mRight - mLeft - mPaddingRight - paddingLeft; + int top = mScrollY + getFadeTop(offsetRequired); + int bottom = top + getFadeHeight(offsetRequired); + + if (offsetRequired) { + right += getRightPaddingOffset(); + bottom += getBottomPaddingOffset(); + } + mPerformanceHelper.drawCallback(canvas, + left, right, top, bottom, mScrollX, mScrollY, + 0, 0, + getLeftFadingEdgeStrength(), getRightFadingEdgeStrength()); + } + } + + @Override + public int getVerticalFadingEdgeLength() { + if (mPerformanceHelper != null) { + return mPerformanceHelper.getVerticalFadingEdgeLengthCallback(); + } else { + return super.getVerticalFadingEdgeLength(); + } + } + + @Override + public int getHorizontalFadingEdgeLength() { + if (mPerformanceHelper != null) { + return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback(); + } else { + return super.getHorizontalFadingEdgeLength(); + } } @Override @@ -153,6 +215,14 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView } @Override + public void onAttachedToWindow() { + if (mPerformanceHelper != null) { + mPerformanceHelper.onAttachedToWindowCallback( + mCallback, mLinearLayout, isHardwareAccelerated()); + } + } + + @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); float densityScale = getResources().getDisplayMetrics().density; @@ -192,6 +262,12 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView }); } + public void onRecentsVisibilityChanged() { + if (mPerformanceHelper != null) { + mPerformanceHelper.updateShowBackground(); + } + } + @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); @@ -220,6 +296,9 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView @Override public void setLayoutTransition(LayoutTransition transition) { + if (mPerformanceHelper != null) { + mPerformanceHelper.setLayoutTransitionCallback(transition); + } // The layout transition applies to our embedded LinearLayout mLinearLayout.setLayoutTransition(transition); } diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java deleted file mode 100644 index d8b086b..0000000 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.recent; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ListView; - -import com.android.systemui.R; - -public class RecentsListView extends ListView { - private int mLastVisiblePosition; - private RecentsCallback mCallback; - - public RecentsListView(Context context) { - this(context, null); - } - - public RecentsListView(Context context, AttributeSet attrs) { - super(context, attrs, 0); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - LayoutInflater inflater = (LayoutInflater) - mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - View footer = inflater.inflate(R.layout.status_bar_recent_panel_footer, this, false); - setScrollbarFadingEnabled(true); - addFooterView(footer, null, false); - final int leftPadding = mContext.getResources() - .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin); - setOverScrollEffectPadding(leftPadding, 0); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - // Keep track of the last visible item in the list so we can restore it - // to the bottom when the orientation changes. - final int childCount = getChildCount(); - if (childCount > 0) { - mLastVisiblePosition = getFirstVisiblePosition() + childCount - 1; - View view = getChildAt(childCount - 1); - final int distanceFromBottom = getHeight() - view.getTop(); - - // This has to happen post-layout, so run it "in the future" - post(new Runnable() { - public void run() { - setSelectionFromTop(mLastVisiblePosition, getHeight() - distanceFromBottom); - } - }); - } - } - - @Override - protected void onVisibilityChanged(View changedView, int visibility) { - super.onVisibilityChanged(changedView, visibility); - // scroll to bottom after reloading - int count = getAdapter().getCount(); - mLastVisiblePosition = count - 1; - if (visibility == View.VISIBLE && changedView == this) { - post(new Runnable() { - public void run() { - setSelection(mLastVisiblePosition); - } - }); - } - } - - public void setCallback(RecentsCallback callback) { - mCallback = callback; - } - -} diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java index 9cc2c29..e59c109 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java @@ -56,7 +56,6 @@ import android.view.View; import android.view.ViewGroup; import android.view.animation.AnimationUtils; import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.HorizontalScrollView; import android.widget.ImageView; @@ -64,6 +63,7 @@ import android.widget.PopupMenu; import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.TextView; +import android.widget.AdapterView.OnItemClickListener; import com.android.systemui.R; import com.android.systemui.statusbar.StatusBar; @@ -73,7 +73,7 @@ import com.android.systemui.statusbar.tablet.TabletStatusBar; public class RecentsPanelView extends RelativeLayout implements OnItemClickListener, RecentsCallback, StatusBarPanel, Animator.AnimatorListener { - static final String TAG = "RecentsListView"; + static final String TAG = "RecentsPanelView"; static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false; private static final int DISPLAY_TASKS = 20; private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps @@ -84,12 +84,8 @@ public class RecentsPanelView extends RelativeLayout private View mRecentsScrim; private View mRecentsGlowView; private ViewGroup mRecentsContainer; - private Bitmap mGlowBitmap; - // TODO: add these widgets attributes to the layout file - private int mGlowBitmapPaddingLeftPx; - private int mGlowBitmapPaddingTopPx; - private int mGlowBitmapPaddingRightPx; - private int mGlowBitmapPaddingBottomPx; + private Bitmap mAppThumbnailBackground; + private boolean mShowing; private Choreographer mChoreo; private View mRecentsDismissButton; @@ -129,7 +125,7 @@ public class RecentsPanelView extends RelativeLayout } public void setThumbnail(Bitmap thumbnail) { - mThumbnail = compositeBitmap(mGlowBitmap, thumbnail); + mThumbnail = compositeBitmap(mAppThumbnailBackground, thumbnail); } public Bitmap getThumbnail() { @@ -178,7 +174,7 @@ public class RecentsPanelView extends RelativeLayout public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { - convertView = mInflater.inflate(R.layout.status_bar_recent_item, null); + convertView = mInflater.inflate(R.layout.status_bar_recent_item, parent, false); holder = new ViewHolder(); holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail); holder.thumbnailViewImage = (ImageView) convertView.findViewById( @@ -247,6 +243,28 @@ public class RecentsPanelView extends RelativeLayout } } + public void hide(boolean animate) { + mShowing = false; + if (!animate) { + setVisibility(View.GONE); + } + if (mBar != null) { + mBar.animateCollapse(); + } + } + + public void handleShowBackground(boolean show) { + if (show) { + mRecentsScrim.setBackgroundResource(R.drawable.status_bar_recents_background); + } else { + mRecentsScrim.setBackgroundDrawable(null); + } + } + + public boolean isRecentsVisible() { + return getVisibility() == VISIBLE; + } + public void onAnimationCancel(Animator animation) { } @@ -315,15 +333,12 @@ public class RecentsPanelView extends RelativeLayout mIconDpi = xlarge ? DisplayMetrics.DENSITY_HIGH : res.getDisplayMetrics().densityDpi; - mGlowBitmap = BitmapFactory.decodeResource(res, R.drawable.recents_thumbnail_bg); - mGlowBitmapPaddingLeftPx = - res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_left); - mGlowBitmapPaddingTopPx = - res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_top); - mGlowBitmapPaddingRightPx = - res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_right); - mGlowBitmapPaddingBottomPx = - res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_bottom); + int width = (int) res.getDimension(R.dimen.status_bar_recents_thumbnail_width); + int height = (int) res.getDimension(R.dimen.status_bar_recents_thumbnail_height); + int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background); + mAppThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(mAppThumbnailBackground); + c.drawColor(color); } @Override @@ -332,12 +347,7 @@ public class RecentsPanelView extends RelativeLayout mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container); mListAdapter = new ActivityDescriptionAdapter(mContext); - if (mRecentsContainer instanceof RecentsListView) { - RecentsListView listView = (RecentsListView) mRecentsContainer; - listView.setAdapter(mListAdapter); - listView.setOnItemClickListener(this); - listView.setCallback(this); - } else if (mRecentsContainer instanceof RecentsHorizontalScrollView){ + if (mRecentsContainer instanceof RecentsHorizontalScrollView){ RecentsHorizontalScrollView scrollView = (RecentsHorizontalScrollView) mRecentsContainer; scrollView.setAdapter(mListAdapter); @@ -349,7 +359,7 @@ public class RecentsPanelView extends RelativeLayout scrollView.setCallback(this); } else { - throw new IllegalArgumentException("missing RecentsListView/RecentsScrollView"); + throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView"); } @@ -382,6 +392,14 @@ public class RecentsPanelView extends RelativeLayout if (visibility == View.VISIBLE && changedView == this) { refreshApplicationList(); } + + if (mRecentsContainer instanceof RecentsHorizontalScrollView) { + ((RecentsHorizontalScrollView) mRecentsContainer).onRecentsVisibilityChanged(); + } else if (mRecentsContainer instanceof RecentsVerticalScrollView) { + ((RecentsVerticalScrollView) mRecentsContainer).onRecentsVisibilityChanged(); + } else { + throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView"); + } } Drawable getFullResDefaultActivityIcon() { @@ -555,6 +573,9 @@ public class RecentsPanelView extends RelativeLayout mThumbnailLoader = null; } mActivityDescriptions = getRecentTasks(); + for (ActivityDescription ad : mActivityDescriptions) { + ad.setThumbnail(mAppThumbnailBackground); + } mListAdapter.notifyDataSetInvalidated(); if (mActivityDescriptions.size() > 0) { if (DEBUG) Log.v(TAG, "Showing " + mActivityDescriptions.size() + " apps"); @@ -629,14 +650,8 @@ public class RecentsPanelView extends RelativeLayout paint.setAntiAlias(true); paint.setFilterBitmap(true); paint.setAlpha(255); - final int srcWidth = thumbnail.getWidth(); - final int srcHeight = thumbnail.getHeight(); - if (DEBUG) Log.v(TAG, "Source thumb: " + srcWidth + "x" + srcHeight); - canvas.drawBitmap(thumbnail, - new Rect(0, 0, srcWidth-1, srcHeight-1), - new RectF(mGlowBitmapPaddingLeftPx, mGlowBitmapPaddingTopPx, - outBitmap.getWidth() - mGlowBitmapPaddingRightPx, - outBitmap.getHeight() - mGlowBitmapPaddingBottomPx), paint); + canvas.drawBitmap(thumbnail, null, + new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint); canvas.setBitmap(null); } return outBitmap; @@ -649,15 +664,6 @@ public class RecentsPanelView extends RelativeLayout mRecentsGlowView.setVisibility(items > 0 ? View.VISIBLE : View.GONE); } - public void hide(boolean animate) { - if (!animate) { - setVisibility(View.GONE); - } - if (mBar != null) { - mBar.animateCollapse(); - } - } - public void handleOnClick(View view) { ActivityDescription ad = ((ViewHolder) view.getTag()).activityDescription; final Context context = view.getContext(); diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java new file mode 100644 index 0000000..b7e656e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.recent; + +import android.animation.LayoutTransition; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +import com.android.systemui.R; + +public class RecentsScrollViewPerformanceHelper { + public static final boolean OPTIMIZE_SW_RENDERED_RECENTS = true; + public static final boolean USE_DARK_FADE_IN_HW_ACCELERATED_MODE = true; + private View mScrollView; + private LinearLayout mLinearLayout; + private RecentsCallback mCallback; + + private boolean mShowBackground = false; + private int mFadingEdgeLength; + private Drawable.ConstantState mBackgroundDrawable; + private Context mContext; + private boolean mIsVertical; + private boolean mFirstTime = true; + private boolean mSoftwareRendered = false; + private boolean mAttachedToWindow = false; + + public static RecentsScrollViewPerformanceHelper create(Context context, + AttributeSet attrs, View scrollView, boolean isVertical) { + boolean isTablet = context.getResources(). + getBoolean(R.bool.config_recents_interface_for_tablets); + if (!isTablet && (OPTIMIZE_SW_RENDERED_RECENTS || USE_DARK_FADE_IN_HW_ACCELERATED_MODE)) { + return new RecentsScrollViewPerformanceHelper(context, attrs, scrollView, isVertical); + } else { + return null; + } + } + + public RecentsScrollViewPerformanceHelper(Context context, + AttributeSet attrs, View scrollView, boolean isVertical) { + mScrollView = scrollView; + mContext = context; + TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View); + mFadingEdgeLength = a.getDimensionPixelSize(android.R.styleable.View_fadingEdgeLength, + ViewConfiguration.get(context).getScaledFadingEdgeLength()); + mIsVertical = isVertical; + } + + public void onAttachedToWindowCallback( + RecentsCallback callback, LinearLayout layout, boolean hardwareAccelerated) { + mSoftwareRendered = !hardwareAccelerated; + if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) + || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) { + mScrollView.setVerticalFadingEdgeEnabled(false); + mScrollView.setHorizontalFadingEdgeEnabled(false); + } + if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) { + mCallback = callback; + mLinearLayout = layout; + mAttachedToWindow = true; + mBackgroundDrawable = mContext.getResources() + .getDrawable(R.drawable.status_bar_recents_background).getConstantState(); + updateShowBackground(); + } + + } + + public void addViewCallback(View newLinearLayoutChild) { + if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) { + final View view = newLinearLayoutChild; + if (mShowBackground) { + view.setBackgroundDrawable(mBackgroundDrawable.newDrawable()); + view.setDrawingCacheEnabled(true); + view.buildDrawingCache(); + } else { + view.setBackgroundDrawable(null); + view.setDrawingCacheEnabled(false); + view.destroyDrawingCache(); + } + } + } + + public void onLayoutCallback() { + if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) { + mScrollView.post(new Runnable() { + public void run() { + updateShowBackground(); + } + }); + } + } + + public void drawCallback(Canvas canvas, + int left, int right, int top, int bottom, int scrollX, int scrollY, + float topFadingEdgeStrength, float bottomFadingEdgeStrength, + float leftFadingEdgeStrength, float rightFadingEdgeStrength) { + if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) { + if (mIsVertical) { + if (scrollY < 0) { + Drawable d = mBackgroundDrawable.newDrawable().getCurrent(); + d.setBounds(0, scrollY, mScrollView.getWidth(), 0); + d.draw(canvas); + } else { + final int childHeight = mLinearLayout.getHeight(); + if (scrollY + mScrollView.getHeight() > childHeight) { + Drawable d = mBackgroundDrawable.newDrawable().getCurrent(); + d.setBounds(0, childHeight, mScrollView.getWidth(), + scrollY + mScrollView.getHeight()); + d.draw(canvas); + } + } + } else { + if (scrollX < 0) { + Drawable d = mBackgroundDrawable.newDrawable().getCurrent(); + d.setBounds(scrollX, 0, 0, mScrollView.getHeight()); + d.draw(canvas); + } else { + final int childWidth = mLinearLayout.getWidth(); + if (scrollX + mScrollView.getWidth() > childWidth) { + Drawable d = mBackgroundDrawable.newDrawable().getCurrent(); + d.setBounds(childWidth, 0, + scrollX + mScrollView.getWidth(), mScrollView.getHeight()); + d.draw(canvas); + } + } + } + } + + if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) + || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) { + Paint p = new Paint(); + Matrix matrix = new Matrix(); + // use use a height of 1, and then wack the matrix each time we + // actually use it. + Shader fade = new LinearGradient(0, 0, 0, 1, 0xCC000000, 0, Shader.TileMode.CLAMP); + // PULL OUT THIS CONSTANT + + p.setShader(fade); + + // draw the fade effect + boolean drawTop = false; + boolean drawBottom = false; + boolean drawLeft = false; + boolean drawRight = false; + + float topFadeStrength = 0.0f; + float bottomFadeStrength = 0.0f; + float leftFadeStrength = 0.0f; + float rightFadeStrength = 0.0f; + + final float fadeHeight = mFadingEdgeLength; + int length = (int) fadeHeight; + + // clip the fade length if top and bottom fades overlap + // overlapping fades produce odd-looking artifacts + if (mIsVertical && (top + length > bottom - length)) { + length = (bottom - top) / 2; + } + + // also clip horizontal fades if necessary + if (!mIsVertical && (left + length > right - length)) { + length = (right - left) / 2; + } + + if (mIsVertical) { + topFadeStrength = Math.max(0.0f, Math.min(1.0f, topFadingEdgeStrength)); + drawTop = topFadeStrength * fadeHeight > 1.0f; + bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, bottomFadingEdgeStrength)); + drawBottom = bottomFadeStrength * fadeHeight > 1.0f; + } + + if (!mIsVertical) { + leftFadeStrength = Math.max(0.0f, Math.min(1.0f, leftFadingEdgeStrength)); + drawLeft = leftFadeStrength * fadeHeight > 1.0f; + rightFadeStrength = Math.max(0.0f, Math.min(1.0f, rightFadingEdgeStrength)); + drawRight = rightFadeStrength * fadeHeight > 1.0f; + } + + if (drawTop) { + matrix.setScale(1, fadeHeight * topFadeStrength); + matrix.postTranslate(left, top); + fade.setLocalMatrix(matrix); + canvas.drawRect(left, top, right, top + length, p); + } + + if (drawBottom) { + matrix.setScale(1, fadeHeight * bottomFadeStrength); + matrix.postRotate(180); + matrix.postTranslate(left, bottom); + fade.setLocalMatrix(matrix); + canvas.drawRect(left, bottom - length, right, bottom, p); + } + + if (drawLeft) { + matrix.setScale(1, fadeHeight * leftFadeStrength); + matrix.postRotate(-90); + matrix.postTranslate(left, top); + fade.setLocalMatrix(matrix); + canvas.drawRect(left, top, left + length, bottom, p); + } + + if (drawRight) { + matrix.setScale(1, fadeHeight * rightFadeStrength); + matrix.postRotate(90); + matrix.postTranslate(right, top); + fade.setLocalMatrix(matrix); + canvas.drawRect(right - length, top, right, bottom, p); + } + } + } + + public int getVerticalFadingEdgeLengthCallback() { + return mFadingEdgeLength; + } + + public int getHorizontalFadingEdgeLengthCallback() { + return mFadingEdgeLength; + } + + public void setLayoutTransitionCallback(LayoutTransition transition) { + if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) { + if (transition != null) { + transition.addTransitionListener(new LayoutTransition.TransitionListener() { + @Override + public void startTransition(LayoutTransition transition, + ViewGroup container, View view, int transitionType) { + updateShowBackground(); + } + + @Override + public void endTransition(LayoutTransition transition, + ViewGroup container, View view, int transitionType) { + updateShowBackground(); + } + }); + } + } + } + + // Turn on/off drawing the background in our ancestor, and turn on/off drawing + // in the items in LinearLayout contained by this scrollview. + // Moving the background drawing to our children, and turning on a drawing cache + // for each of them, gives us a ~20fps gain when Recents is rendered in software + public void updateShowBackground() { + if (!mAttachedToWindow) { + // We haven't been initialized yet-- we'll get called again when we are + return; + } + if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) { + LayoutTransition transition = mLinearLayout.getLayoutTransition(); + int linearLayoutSize = + mIsVertical ? mLinearLayout.getHeight() : mLinearLayout.getWidth(); + int scrollViewSize = + mIsVertical ? mScrollView.getHeight() : mScrollView.getWidth(); + boolean show = !mScrollView.isHardwareAccelerated() && + (linearLayoutSize > scrollViewSize) && + !(transition != null && transition.isRunning()) && + mCallback.isRecentsVisible(); + + if (!mFirstTime && show == mShowBackground) return; + mShowBackground = show; + mFirstTime = false; + + mCallback.handleShowBackground(!show); + for (int i = 0; i < mLinearLayout.getChildCount(); i++) { + View v = mLinearLayout.getChildAt(i); + if (show) { + v.setBackgroundDrawable(mBackgroundDrawable.newDrawable()); + v.setDrawingCacheEnabled(true); + v.buildDrawingCache(); + } else { + v.setDrawingCacheEnabled(false); + v.destroyDrawingCache(); + v.setBackgroundDrawable(null); + } + } + } + } + +} diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java index b1a30d9..3acef08 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java @@ -20,6 +20,7 @@ import android.animation.LayoutTransition; import android.content.Context; import android.content.res.Configuration; import android.database.DataSetObserver; +import android.graphics.Canvas; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; @@ -40,6 +41,7 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper private RecentsCallback mCallback; protected int mLastScrollPosition; private SwipeHelper mSwipeHelper; + private RecentsScrollViewPerformanceHelper mPerformanceHelper; private OnLongClickListener mOnLongClick = new OnLongClickListener() { public boolean onLongClick(View v) { @@ -49,15 +51,13 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper } }; - public RecentsVerticalScrollView(Context context) { - this(context, null); - } - public RecentsVerticalScrollView(Context context, AttributeSet attrs) { super(context, attrs, 0); float densityScale = getResources().getDisplayMetrics().density; float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop(); mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop); + + mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, true); } private int scrollPositionOfMostRecent() { @@ -77,11 +77,15 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper } final View view = mAdapter.getView(i, old, mLinearLayout); + if (mPerformanceHelper != null) { + mPerformanceHelper.addViewCallback(view); + } + if (old == null) { view.setClickable(true); view.setOnLongClickListener(mOnLongClick); - final View thumbnail = getChildContentView(view); + final View thumbnail = view.findViewById(R.id.app_thumbnail); // thumbnail is set to clickable in the layout file thumbnail.setOnClickListener(new OnClickListener() { public void onClick(View v) { @@ -138,6 +142,11 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper // We do this so the underlying ScrollView knows that it won't get // the chance to intercept events anymore requestDisallowInterceptTouchEvent(true); + v.setActivated(true); + } + + public void onDragCancelled(View v) { + v.setActivated(false); } public View getChildAtPosition(MotionEvent ev) { @@ -155,7 +164,60 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper } public View getChildContentView(View v) { - return v.findViewById(R.id.app_thumbnail); + return v.findViewById(R.id.recent_item); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (mPerformanceHelper != null) { + mPerformanceHelper.onLayoutCallback(); + } + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + if (mPerformanceHelper != null) { + int paddingLeft = mPaddingLeft; + final boolean offsetRequired = isPaddingOffsetRequired(); + if (offsetRequired) { + paddingLeft += getLeftPaddingOffset(); + } + + int left = mScrollX + paddingLeft; + int right = left + mRight - mLeft - mPaddingRight - paddingLeft; + int top = mScrollY + getFadeTop(offsetRequired); + int bottom = top + getFadeHeight(offsetRequired); + + if (offsetRequired) { + right += getRightPaddingOffset(); + bottom += getBottomPaddingOffset(); + } + mPerformanceHelper.drawCallback(canvas, + left, right, top, bottom, mScrollX, mScrollY, + getTopFadingEdgeStrength(), getBottomFadingEdgeStrength(), + 0, 0); + } + } + + @Override + public int getVerticalFadingEdgeLength() { + if (mPerformanceHelper != null) { + return mPerformanceHelper.getVerticalFadingEdgeLengthCallback(); + } else { + return super.getVerticalFadingEdgeLength(); + } + } + + @Override + public int getHorizontalFadingEdgeLength() { + if (mPerformanceHelper != null) { + return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback(); + } else { + return super.getHorizontalFadingEdgeLength(); + } } @Override @@ -169,6 +231,14 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper } @Override + public void onAttachedToWindow() { + if (mPerformanceHelper != null) { + mPerformanceHelper.onAttachedToWindowCallback( + mCallback, mLinearLayout, isHardwareAccelerated()); + } + } + + @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); float densityScale = getResources().getDisplayMetrics().density; @@ -208,6 +278,12 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper }); } + public void onRecentsVisibilityChanged() { + if (mPerformanceHelper != null) { + mPerformanceHelper.updateShowBackground(); + } + } + @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); @@ -236,6 +312,9 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper @Override public void setLayoutTransition(LayoutTransition transition) { + if (mPerformanceHelper != null) { + mPerformanceHelper.setLayoutTransitionCallback(transition); + } // The layout transition applies to our embedded LinearLayout mLinearLayout.setLayoutTransition(transition); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index e6c0b96..98dca92 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -70,6 +70,14 @@ public class NavigationBarView extends LinearLayout { return mCurrentView.findViewById(R.id.menu); } + public View getBackButton() { + return mCurrentView.findViewById(R.id.back); + } + + public View getHomeButton() { + return mCurrentView.findViewById(R.id.home); + } + public NavigationBarView(Context context, AttributeSet attrs) { super(context, attrs); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index e3ea0de..3d23abe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -380,7 +380,7 @@ public class PhoneStatusBar extends StatusBar { } protected WindowManager.LayoutParams getRecentsLayoutParams(LayoutParams layoutParams) { - boolean translucent = false; + boolean opaque = false; WindowManager.LayoutParams lp = new WindowManager.LayoutParams( layoutParams.width, layoutParams.height, @@ -388,7 +388,7 @@ public class PhoneStatusBar extends StatusBar { WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, - (translucent ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT)); + (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT)); if (ActivityManager.isHighEndGfx(mDisplay)) { lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } @@ -404,7 +404,7 @@ public class PhoneStatusBar extends StatusBar { // Recents Panel boolean visible = false; if (mRecentsPanel != null) { - visible = mRecentsPanel.getVisibility() == View.VISIBLE; + visible = mRecentsPanel.isShowing(); WindowManagerImpl.getDefault().removeView(mRecentsPanel); } @@ -1091,18 +1091,9 @@ public class PhoneStatusBar extends StatusBar { } } - if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) { - if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) { - Slog.d(TAG, "DISABLE_NAVIGATION: yes"); - - // close recents if it's visible - mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL); - mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL); - } - - if (mNavigationBarView != null) { - mNavigationBarView.setEnabled((state & StatusBarManager.DISABLE_NAVIGATION) == 0); - } + if ((diff & (StatusBarManager.DISABLE_NAVIGATION | StatusBarManager.DISABLE_BACK)) != 0) { + setNavigationVisibility(state & + (StatusBarManager.DISABLE_NAVIGATION | StatusBarManager.DISABLE_BACK)); } if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { @@ -1127,6 +1118,32 @@ public class PhoneStatusBar extends StatusBar { } } + private void setNavigationVisibility(int visibility) { + boolean disableNavigation = ((visibility & StatusBarManager.DISABLE_NAVIGATION) != 0); + boolean disableBack = ((visibility & StatusBarManager.DISABLE_BACK) != 0); + + Slog.i(TAG, "DISABLE_BACK: " + (disableBack ? "yes" : "no")); + Slog.i(TAG, "DISABLE_NAVIGATION: " + (disableNavigation ? "yes" : "no")); + + if (mNavigationBarView != null) { + if (disableNavigation && disableBack) { + mNavigationBarView.setEnabled(false); + } else { + mNavigationBarView.getBackButton().setEnabled(!disableBack); + mNavigationBarView.getHomeButton().setEnabled(!disableNavigation); + mNavigationBarView.getRecentsButton().setEnabled(!disableNavigation); + + mNavigationBarView.setEnabled(true); + } + } + + if (disableNavigation) { + // close recents if it's visible + mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL); + mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL); + } + } + /** * All changes to the status bar and notifications funnel through here and are batched. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index 60dfdac..3c85814 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -130,6 +130,8 @@ public class NetworkController extends BroadcastReceiver { int mLastDataTypeIconId = -1; String mLastLabel = ""; + private boolean mHasMobileDataFeature; + boolean mDataAndWifiStacked = false; // yuck -- stop doing this here and put it in the framework @@ -147,6 +149,10 @@ public class NetworkController extends BroadcastReceiver { public NetworkController(Context context) { mContext = context; + ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( + Context.CONNECTIVITY_SERVICE); + mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); + // set up the default wifi icon, used when no radios have ever appeared updateWifiIcons(); @@ -229,7 +235,7 @@ public class NetworkController extends BroadcastReceiver { mWifiIconId, mWifiActivityIconId); cluster.setMobileDataIndicators( - hasMobileDataFeature(), + mHasMobileDataFeature, mPhoneSignalIconId, mMobileActivityIconId, mDataTypeIconId); @@ -376,12 +382,6 @@ public class NetworkController extends BroadcastReceiver { } } - private boolean hasMobileDataFeature() { - // XXX: HAX: replace when a more reliable method is available - return (! "wifi-only".equals(SystemProperties.get("ro.carrier"))); - } - - private void updateAirplaneMode() { mAirplaneMode = (Settings.System.getInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) == 1); @@ -828,8 +828,8 @@ public class NetworkController extends BroadcastReceiver { label = context.getString(R.string.status_bar_settings_signal_meter_disconnected); // On devices without mobile radios, we want to show the wifi icon combinedSignalIconId = - hasMobileDataFeature() ? mDataSignalIconId : mWifiIconId; - mContentDescriptionCombinedSignal = hasMobileDataFeature() + mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId; + mContentDescriptionCombinedSignal = mHasMobileDataFeature ? mContentDescriptionDataType : mContentDescriptionWifi; mDataTypeIconId = 0; } @@ -866,7 +866,7 @@ public class NetworkController extends BroadcastReceiver { mWifiIconId, mWifiActivityIconId); cluster.setMobileDataIndicators( - hasMobileDataFeature(), + mHasMobileDataFeature, mPhoneSignalIconId, mMobileActivityIconId, mDataTypeIconId); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java index 469b462..e287b7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java @@ -124,6 +124,9 @@ public class NotificationRowLayout extends ViewGroup implements SwipeHelper.Call requestDisallowInterceptTouchEvent(true); } + public void onDragCancelled(View v) { + } + public View getChildAtPosition(MotionEvent ev) { // find the view under the pointer, accounting for GONE views final int count = getChildCount(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index 2ab667d..cc73d7b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -306,7 +306,7 @@ public class TabletStatusBar extends StatusBar implements mStatusBarView.setIgnoreChildren(2, mRecentButton, mRecentsPanel); lp = new WindowManager.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, + (int) res.getDimension(R.dimen.status_bar_recents_width), ViewGroup.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN @@ -949,29 +949,34 @@ public class TabletStatusBar extends StatusBar implements mTicker.halt(); } } - if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) { - if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) { - Slog.i(TAG, "DISABLE_NAVIGATION: yes"); - mNavigationArea.setVisibility(View.INVISIBLE); - mInputMethodSwitchButton.setScreenLocked(true); - } else { - Slog.i(TAG, "DISABLE_NAVIGATION: no"); - mNavigationArea.setVisibility(View.VISIBLE); - mInputMethodSwitchButton.setScreenLocked(false); - } + if ((diff & (StatusBarManager.DISABLE_NAVIGATION | StatusBarManager.DISABLE_BACK)) != 0) { + setNavigationVisibility(state & + (StatusBarManager.DISABLE_NAVIGATION | StatusBarManager.DISABLE_BACK)); } - if ((diff & StatusBarManager.DISABLE_BACK) != 0) { - if ((state & StatusBarManager.DISABLE_BACK) != 0) { - Slog.i(TAG, "DISABLE_BACK: yes"); - mBackButton.setEnabled(false); - mInputMethodSwitchButton.setScreenLocked(true); - } else { - Slog.i(TAG, "DISABLE_BACK: no"); - mBackButton.setEnabled(true); - mInputMethodSwitchButton.setScreenLocked(false); - } + } + + private void setNavigationVisibility(int visibility) { + boolean disableNavigation = ((visibility & StatusBarManager.DISABLE_NAVIGATION) != 0); + boolean disableBack = ((visibility & StatusBarManager.DISABLE_BACK) != 0); + + Slog.i(TAG, "DISABLE_BACK: " + (disableBack ? "yes" : "no")); + Slog.i(TAG, "DISABLE_NAVIGATION: " + (disableNavigation ? "yes" : "no")); + + if (disableNavigation && disableBack) { + mNavigationArea.setVisibility(View.INVISIBLE); + } else { + int backVisiblity = (disableBack ? View.INVISIBLE : View.VISIBLE); + int navVisibility = (disableNavigation ? View.INVISIBLE : View.VISIBLE); + + mBackButton.setVisibility(backVisiblity); + mHomeButton.setVisibility(navVisibility); + mRecentButton.setVisibility(navVisibility); + // don't change menu button visibility here + + mNavigationArea.setVisibility(View.VISIBLE); } + mInputMethodSwitchButton.setScreenLocked(disableNavigation); } private boolean hasTicker(Notification n) { diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java index 162381d..a544167 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -1185,15 +1185,19 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } int flags = StatusBarManager.DISABLE_NONE; - if (mShowing && !mHidden) { - // showing lockscreen exclusively; disable various extra - // statusbar components. + if (mShowing) { + // disable navigation status bar components if lock screen is up flags |= StatusBarManager.DISABLE_NAVIGATION; - flags |= StatusBarManager.DISABLE_CLOCK; - } - if (mShowing && (isSecure() || !ENABLE_INSECURE_STATUS_BAR_EXPAND)) { - // showing secure lockscreen; disable expanding. - flags |= StatusBarManager.DISABLE_EXPAND; + if (!mHidden) { + // showing lockscreen exclusively (no activities in front of it) + // disable clock and back button too + flags |= StatusBarManager.DISABLE_BACK; + flags |= StatusBarManager.DISABLE_CLOCK; + } + if (isSecure() || !ENABLE_INSECURE_STATUS_BAR_EXPAND) { + // showing secure lockscreen; disable expanding. + flags |= StatusBarManager.DISABLE_EXPAND; + } } if (DEBUG) { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 8b450f6..2f5deba 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -267,6 +267,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mLidOpen = LID_ABSENT; boolean mSystemReady; + boolean mSystemBooted; boolean mHdmiPlugged; int mUiMode = Configuration.UI_MODE_TYPE_NORMAL; int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED; @@ -2497,6 +2498,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardMediator.isShowingAndNotHidden() : mKeyguardMediator.isShowing()); + if (!mSystemBooted) { + // If we have not yet booted, don't let key events do anything. + return 0; + } + if (false) { Log.d(TAG, "interceptKeyTq keycode=" + keyCode + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive); @@ -3100,6 +3106,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + /** {@inheritDoc} */ + public void systemBooted() { + synchronized (mLock) { + mSystemBooted = true; + } + } + ProgressDialog mBootMsgDialog = null; /** {@inheritDoc} */ @@ -3492,7 +3505,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) { pw.print(prefix); pw.print("mSafeMode="); pw.print(mSafeMode); - pw.print(" mSystemRead="); pw.println(mSystemReady); + pw.print(" mSystemReady="); pw.print(mSystemReady); + pw.print(" mSystemBooted="); pw.println(mSystemBooted); pw.print(prefix); pw.print("mLidOpen="); pw.print(mLidOpen); pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation); pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged); diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index e193be0..b178fd9 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -769,11 +769,6 @@ status_t CameraService::Client::takePicture(int msgType) { status_t result = checkPidAndHardware(); if (result != NO_ERROR) return result; - if (mHardware->recordingEnabled()) { - LOGE("Cannot take picture during recording."); - return INVALID_OPERATION; - } - if ((msgType & CAMERA_MSG_RAW_IMAGE) && (msgType & CAMERA_MSG_RAW_IMAGE_NOTIFY)) { LOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY" diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3815c3b..2348d76 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -703,6 +703,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { return result.toArray(new NetworkInfo[result.size()]); } + @Override + public boolean isNetworkSupported(int networkType) { + enforceAccessPermission(); + return (isNetworkTypeValid(networkType) && (mNetTrackers[networkType] != null)); + } + /** * Return LinkProperties for the active (i.e., connected) default * network interface. It is assumed that at most one default network 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 @@ option java_package com.android.server # [ 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } finally { Binder.restoreCallingIdentity(ident); } - return true; + return; } } } } - return false; + return; } private void setInputMethodWithSubtypeId(IBinder token, String id, int subtypeId) { @@ -1903,6 +1903,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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 @@ public class NetworkManagementService extends INetworkManagementService.Stub 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 @@ public class NetworkManagementService extends INetworkManagementService.Stub 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 @@ public class NetworkManagementService extends INetworkManagementService.Stub 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 @@ public class PowerManagerService extends IPowerManager.Stub 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/SystemServer.java b/services/java/com/android/server/SystemServer.java index d0e8b5e..2714fc5 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -350,7 +350,6 @@ class ServerThread extends Thread { Slog.i(TAG, "Wi-Fi Service"); wifi = new WifiService(context); ServiceManager.addService(Context.WIFI_SERVICE, wifi); - wifi.checkAndStartWifi(); } catch (Throwable e) { reportWtf("starting Wi-Fi Service", e); } @@ -361,6 +360,7 @@ class ServerThread extends Thread { ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity); networkStats.bindConnectivityManager(connectivity); networkPolicy.bindConnectivityManager(connectivity); + wifi.checkAndStartWifi(); wifiP2p.connectivityServiceReady(); } catch (Throwable e) { reportWtf("starting Connectivity Service", e); 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_DEFAULT; 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.RemoteException; 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 android.util.TrustedTime; 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** + * 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; + 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/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index b8797d1..bfb244b 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -78,8 +78,6 @@ import android.os.Bundle; import android.os.Environment; import android.os.FileObserver; import android.os.FileUtils; -import android.os.FileUtils.FileStatus; -import android.os.Debug; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -706,6 +704,7 @@ public class PackageManagerService extends IPackageManager.Stub { Runtime.getRuntime().gc(); } if (msg.obj != null) { + @SuppressWarnings("unchecked") Set<SdInstallArgs> args = (Set<SdInstallArgs>) msg.obj; if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers"); // Unload containers @@ -3039,10 +3038,6 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } mScanningPath = scanFile; - if (pkg == null) { - mLastScanError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; - return null; - } if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index f5a5e2e..755a268 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -2498,6 +2498,10 @@ public class WindowManagerService extends IWindowManager.Stub int attrChanges = 0; int flagChanges = 0; if (attrs != null) { + if (win.mAttrs.type != attrs.type) { + throw new IllegalArgumentException( + "Window type can not be changed after the window is added."); + } flagChanges = win.mAttrs.flags ^= attrs.flags; attrChanges = win.mAttrs.copyFrom(attrs); } @@ -4703,6 +4707,8 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendMessageDelayed(msg, 30*1000); } + mPolicy.systemBooted(); + performEnableScreen(); } @@ -7921,13 +7927,13 @@ public class WindowManagerService extends IWindowManager.Stub if (mWindowDetachedWallpaper != windowDetachedWallpaper) { if (DEBUG_WALLPAPER) Slog.v(TAG, "Detached wallpaper changed from " + mWindowDetachedWallpaper - + windowDetachedWallpaper); + + " to " + windowDetachedWallpaper); mWindowDetachedWallpaper = windowDetachedWallpaper; wallpaperMayChange = true; } if (windowAnimationBackgroundColor != 0) { - // If this window that wants black is the current wallpaper + // If the window that wants black is the current wallpaper // target, then the black goes *below* the wallpaper so we // don't cause the wallpaper to suddenly disappear. WindowState target = windowAnimationBackground; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 598220f..b4c5dec 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -817,6 +817,20 @@ void SurfaceFlinger::handleWorkList() mHwWorkListDirty = false; HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer()); if (hwc.initCheck() == NO_ERROR) { + + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + uint32_t flags = hw.getFlags(); + if ((flags & DisplayHardware::SWAP_RECTANGLE) || + (flags & DisplayHardware::BUFFER_PRESERVED)) + { + // we need to redraw everything (the whole screen) + // NOTE: we could be more subtle here and redraw only + // the area which will end-up in an overlay. But since this + // shouldn't happen often, we invalidate everything. + mDirtyRegion.set(hw.bounds()); + mInvalidRegion = mDirtyRegion; + } + const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ); const size_t count = currentLayers.size(); hwc.createWorkList(count); 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 class NetworkManagementServiceTest extends AndroidTestCase { 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 class NetworkManagementServiceTest extends AndroidTestCase { 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 @@ public class NetworkManagementServiceTest extends AndroidTestCase { 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/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index 3e13a86..bd35058 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -29,6 +29,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.ConnectivityManager; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.AsyncResult; @@ -230,8 +231,6 @@ public final class RIL extends BaseCommands implements CommandsInterface { Object mLastNITZTimeInfo; - private static final String WIFI_ONLY_CARRIER = "wifi-only"; - //***** Events static final int EVENT_SEND = 1; @@ -626,10 +625,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { Looper looper = mSenderThread.getLooper(); mSender = new RILSender(looper); - // TODO: Provide a common API for determining if a - // device is wifi-only. bug: 3480713 - String carrier = SystemProperties.get("ro.carrier"); - if (WIFI_ONLY_CARRIER.equals(carrier)) { + ConnectivityManager cm = (ConnectivityManager)context.getSystemService( + Context.CONNECTIVITY_SERVICE); + if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { riljLog("Not starting RILReceiver: wifi-only"); } else { riljLog("Starting RILReceiver"); diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp index 92f5b64..fb4067a 100644 --- a/tools/aidl/aidl.cpp +++ b/tools/aidl/aidl.cpp @@ -575,12 +575,19 @@ exactly_one_interface(const char* filename, const document_item_type* items, con // ========================================================== void -generate_dep_file(const Options& options) +generate_dep_file(const Options& options, const document_item_type* items) { - /* we open the file in binary mode to ensure that the same output is - * generated on all platforms !! - */ - FILE* to = fopen(options.depFileName.c_str(), "wb"); + /* we open the file in binary mode to ensure that the same output is + * generated on all platforms !! + */ + FILE* to = NULL; + if (options.autoDepFile) { + string fileName = options.outputFileName + ".d"; + to = fopen(fileName.c_str(), "wb"); + } else { + to = fopen(options.depFileName.c_str(), "wb"); + } + if (to == NULL) { return; } @@ -591,7 +598,12 @@ generate_dep_file(const Options& options) slash = ""; } - fprintf(to, "%s: \\\n", options.outputFileName.c_str()); + if (items->item_type == INTERFACE_TYPE) { + fprintf(to, "%s: \\\n", options.outputFileName.c_str()); + } else { + // parcelable: there's no output file. + fprintf(to, " : \\\n"); + } fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash); while (import) { @@ -611,44 +623,60 @@ generate_dep_file(const Options& options) // ========================================================== static string -generate_outputFileName(const Options& options, const document_item_type* items) +generate_outputFileName2(const Options& options, const buffer_type& name, const char* package) { string result; - // items has already been checked to have only one interface. - if (items->item_type == INTERFACE_TYPE) { - interface_type* type = (interface_type*)items; - - // create the path to the destination folder based on the - // interface package name - result = options.outputBaseFolder; - result += OS_PATH_SEPARATOR; + // create the path to the destination folder based on the + // interface package name + result = options.outputBaseFolder; + result += OS_PATH_SEPARATOR; - string package = type->package; - size_t len = package.length(); - for (size_t i=0; i<len; i++) { - if (package[i] == '.') { - package[i] = OS_PATH_SEPARATOR; - } + string packageStr = package; + size_t len = packageStr.length(); + for (size_t i=0; i<len; i++) { + if (packageStr[i] == '.') { + packageStr[i] = OS_PATH_SEPARATOR; } + } - result += package; - - // add the filename by replacing the .aidl extension to .java - const char* p = strchr(type->name.data, '.'); - len = p ? p-type->name.data : strlen(type->name.data); + result += packageStr; + + // add the filename by replacing the .aidl extension to .java + const char* p = strchr(name.data, '.'); + len = p ? p-name.data : strlen(name.data); + + result += OS_PATH_SEPARATOR; + result.append(name.data, len); + result += ".java"; - result += OS_PATH_SEPARATOR; - result.append(type->name.data, len); - result += ".java"; + return result; +} + +// ========================================================== +static string +generate_outputFileName(const Options& options, const document_item_type* items) +{ + // items has already been checked to have only one interface. + if (items->item_type == INTERFACE_TYPE) { + interface_type* type = (interface_type*)items; + + return generate_outputFileName2(options, type->name, type->package); + } else if (items->item_type == PARCELABLE_TYPE) { + parcelable_type* type = (parcelable_type*)items; + return generate_outputFileName2(options, type->name, type->package); } + // I don't think we can come here, but safer than returning NULL. + string result; return result; } + + // ========================================================== static void -check_outputFileName(const string& path) { +check_outputFilePath(const string& path) { size_t len = path.length(); for (size_t i=0; i<len ; i++) { if (path[i] == OS_PATH_SEPARATOR) { @@ -756,7 +784,7 @@ parse_preprocessed_file(const string& filename) // ========================================================== static int -compile_aidl(const Options& options) +compile_aidl(Options& options) { int err = 0, N; @@ -850,27 +878,30 @@ compile_aidl(const Options& options) return 1; } - // they didn't ask to fail on parcelables, so just exit quietly. - if (onlyParcelable && !options.failOnParcelable) { - return 0; + // if needed, generate the outputFileName from the outputBaseFolder + if (options.outputFileName.length() == 0 && + options.outputBaseFolder.length() > 0) { + options.outputFileName = generate_outputFileName(options, mainDoc); } // if we were asked to, generate a make dependency file - if (options.depFileName != "") { - generate_dep_file(options); + // unless it's a parcelable *and* it's supposed to fail on parcelable + if ((options.autoDepFile || options.depFileName != "") && + !(onlyParcelable && options.failOnParcelable)) { + // make sure the folders of the output file all exists + check_outputFilePath(options.outputFileName); + generate_dep_file(options, mainDoc); } - // if needed, generate the outputFileName from the outputBaseFolder - string outputFileName = options.outputFileName; - if (outputFileName.length() == 0 && - options.outputBaseFolder.length() > 0) { - outputFileName = generate_outputFileName(options, mainDoc); + // they didn't ask to fail on parcelables, so just exit quietly. + if (onlyParcelable && !options.failOnParcelable) { + return 0; } - + // make sure the folders of the output file all exists - check_outputFileName(outputFileName); + check_outputFilePath(options.outputFileName); - err = generate_java(outputFileName, options.inputFileName.c_str(), + err = generate_java(options.outputFileName, options.inputFileName.c_str(), (interface_type*)mainDoc); return err; diff --git a/tools/aidl/options.cpp b/tools/aidl/options.cpp index 0aa7db2..7b2daeb 100644 --- a/tools/aidl/options.cpp +++ b/tools/aidl/options.cpp @@ -15,6 +15,7 @@ usage() "OPTIONS:\n" " -I<DIR> search path for import statements.\n" " -d<FILE> generate dependency file.\n" + " -a generate dependency file next to the output file with the name based on the input file.\n" " -p<FILE> file created by --preprocess to import.\n" " -o<FOLDER> base output folder for generated files.\n" " -b fail when trying to compile a parcelable.\n" @@ -49,6 +50,7 @@ parse_options(int argc, const char* const* argv, Options *options) options->task = COMPILE_AIDL; options->failOnParcelable = false; + options->autoDepFile = false; // OPTIONS while (i < argc) { @@ -73,6 +75,9 @@ parse_options(int argc, const char* const* argv, Options *options) return usage(); } } + else if (s[1] == 'a') { + options->autoDepFile = true; + } else if (s[1] == 'p') { if (len > 2) { options->preprocessedFiles.push_back(s+2); diff --git a/tools/aidl/options.h b/tools/aidl/options.h index d88d988..387e37d 100644 --- a/tools/aidl/options.h +++ b/tools/aidl/options.h @@ -23,6 +23,7 @@ struct Options string outputFileName; string outputBaseFolder; string depFileName; + bool autoDepFile; vector<string> filesToPreprocess; }; 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 class BridgeIInputMethodManager implements IInputMethodManager { } - 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 @@ public class BridgeIInputMethodManager implements IInputMethodManager { // 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/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java index 274edae..c52142d 100644 --- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java +++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java @@ -36,6 +36,7 @@ import android.os.SystemProperties; import android.provider.Settings; import android.provider.Settings.Secure; import android.util.Slog; +import android.util.Log; import com.android.internal.util.Protocol; import com.android.internal.util.State; @@ -174,7 +175,7 @@ public class WifiWatchdogStateMachine extends StateMachine { * It triggers a disableNetwork call if a DNS check fails. */ public boolean mDisableAPNextFailure = false; - private ConnectivityManager mConnectivityManager; + private static boolean sWifiOnly = false; private boolean mNotificationShown; public boolean mHasConnectedWifiManager = false; @@ -219,9 +220,14 @@ public class WifiWatchdogStateMachine extends StateMachine { public static WifiWatchdogStateMachine makeWifiWatchdogStateMachine(Context context) { ContentResolver contentResolver = context.getContentResolver(); + + ConnectivityManager cm = (ConnectivityManager) context.getSystemService( + Context.CONNECTIVITY_SERVICE); + sWifiOnly = (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false); + // Disable for wifi only devices. if (Settings.Secure.getString(contentResolver, Settings.Secure.WIFI_WATCHDOG_ON) == null && - "wifi-only".equals(SystemProperties.get("ro.carrier"))) { + sWifiOnly) { putSettingsBoolean(contentResolver, Settings.Secure.WIFI_WATCHDOG_ON, false); } WifiWatchdogStateMachine wwsm = new WifiWatchdogStateMachine(context); @@ -508,22 +514,6 @@ public class WifiWatchdogStateMachine extends StateMachine { } } - /** - * @return true if there is definitely no mobile data (we'll be less aggressive) - */ - private boolean hasNoMobileData() { - if (mConnectivityManager == null) { - mConnectivityManager = (ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE); - } - NetworkInfo mobileNetInfo = mConnectivityManager.getNetworkInfo( - ConnectivityManager.TYPE_MOBILE); - if (mobileNetInfo == null || !mobileNetInfo.isAvailable()) { - return true; - } - return false; - } - class DefaultState extends State { @Override public boolean processMessage(Message msg) { @@ -941,7 +931,7 @@ public class WifiWatchdogStateMachine extends StateMachine { if (mDisableAPNextFailure || mNumCheckFailures >= mBssids.size() || mNumCheckFailures >= mMaxSsidBlacklists) { - if (hasNoMobileData()) { + if (sWifiOnly) { Slog.w(WWSM_TAG, "Would disable bad network, but device has no mobile data!" + " Going idle..."); // This state should be called idle -- will be changing flow. 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 class WpsConfiguration implements Parcelable { 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 @@ public class WpsConfiguration implements Parcelable { 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 @@ import android.os.Parcel; public class WifiP2pConfig implements Parcelable { /** - * Device name - */ - public String deviceName; - - /** * Device address */ public String deviceAddress; @@ -53,6 +48,7 @@ public class WifiP2pConfig implements Parcelable { /** * Indicates whether the configuration is saved + * @hide */ public enum Persist { SYSTEM_DEFAULT, @@ -60,6 +56,7 @@ public class WifiP2pConfig implements Parcelable { NO } + /** @hide */ public Persist persist = Persist.SYSTEM_DEFAULT; public WifiP2pConfig() { @@ -110,7 +107,6 @@ public class WifiP2pConfig implements Parcelable { 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 @@ public class WifiP2pConfig implements Parcelable { /** 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 @@ public class WifiP2pConfig implements Parcelable { 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 @@ public class WifiP2pGroup implements Parcelable { } /** - * @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 class WifiP2pInfo implements Parcelable { 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.AsyncChannel; 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 @@ public class WifiP2pManager { * 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 @@ public class WifiP2pManager { * 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 class WifiP2pManager { 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 @@ public class WifiP2pManager { * 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 @@ public class WifiP2pManager { 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; + /** + * 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; - /* arg1 values on response messages from the framework */ - public static final int P2P_UNSUPPORTED = 1; + /** @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 @@ public class WifiP2pManager { /** * 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 @@ public class WifiP2pManager { /** * 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 @@ public class WifiP2pManager { } } + /** @hide */ public boolean isP2pSupported() { try { return mService.isP2pSupported(); @@ -240,6 +413,7 @@ public class WifiP2pManager { /** * 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 @@ public class WifiP2pManager { /** * 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 @@ public class WifiP2pManager { } /** - * 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 @@ public class WifiP2pManager { } /** - * Start a p2p connection + * Start a p2p connection to a device with the specified configuration. + * + * <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}. * - * @param peer Configuration described in a {@link WifiP2pConfig} object. + * <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 @@ public class WifiP2pManager { } /** - * 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 @@ public class WifiP2pManager { } /** - * 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 @@ public class WifiP2pManager { } /** - * 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 @@ public class WifiP2pManager { } /** - * 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 @@ public class WifiP2pManager { } /** - * 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 @@ public class WifiP2pManager { } } - /** * Setup DNS connectivity on the current process to the connected Wi-Fi p2p peers * |
