diff options
20 files changed, 339 insertions, 96 deletions
diff --git a/api/current.xml b/api/current.xml index ded1d1b..58aa1fd 100644 --- a/api/current.xml +++ b/api/current.xml @@ -15703,6 +15703,17 @@ visibility="public" > </field> +<field name="Theme_Holo_Light_NoActionBar" + type="int" + transient="false" + volatile="false" + value="16974064" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="Theme_Holo_Light_Panel" type="int" transient="false" @@ -259887,7 +259898,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="appWidgetId" type="int"> @@ -259897,6 +259908,21 @@ <parameter name="intent" type="android.content.Intent"> </parameter> </method> +<method name="setRemoteAdapter" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="viewId" type="int"> +</parameter> +<parameter name="intent" type="android.content.Intent"> +</parameter> +</method> <method name="setScrollPosition" return="void" abstract="false" diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3e5b21f..cb07135 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -916,7 +916,7 @@ public final class ActivityThread { public static final int HIDE_WINDOW = 106; public static final int RESUME_ACTIVITY = 107; public static final int SEND_RESULT = 108; - public static final int DESTROY_ACTIVITY = 109; + public static final int DESTROY_ACTIVITY = 109; public static final int BIND_APPLICATION = 110; public static final int EXIT_APPLICATION = 111; public static final int NEW_INTENT = 112; @@ -1130,8 +1130,8 @@ public final class ActivityThread { if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what); } - void maybeSnapshot() { - if (mBoundApplication != null) { + private void maybeSnapshot() { + if (mBoundApplication != null && SamplingProfilerIntegration.isEnabled()) { // convert the *private* ActivityThread.PackageInfo to *public* known // android.content.pm.PackageInfo String packageName = mBoundApplication.info.mPackageName; @@ -3396,8 +3396,7 @@ public final class ActivityThread { } final void handleLowMemory() { - ArrayList<ComponentCallbacks> callbacks - = new ArrayList<ComponentCallbacks>(); + ArrayList<ComponentCallbacks> callbacks; synchronized (mPackages) { callbacks = collectComponentCallbacksLocked(true, null); diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index c854fac..9cf2718 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -125,7 +125,7 @@ public class RemoteViews implements Parcelable, Filter { * SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!! */ private abstract static class Action implements Parcelable { - public abstract void apply(View root) throws ActionException; + public abstract void apply(View root, ViewGroup rootParent) throws ActionException; public int describeContents() { return 0; @@ -183,7 +183,7 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root) { + public void apply(View root, ViewGroup rootParent) { final View view = root.findViewById(viewId); if (!(view instanceof AdapterView<?>)) return; @@ -214,7 +214,7 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root) { + public void apply(View root, ViewGroup rootParent) { final View target = root.findViewById(viewId); if (target == null) return; @@ -295,7 +295,7 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root) { + public void apply(View root, ViewGroup rootParent) { final View target = root.findViewById(viewId); if (target == null) return; @@ -360,6 +360,60 @@ public class RemoteViews implements Parcelable, Filter { public final static int TAG = 8; } + private class SetRemoteViewsAdapterIntent extends Action { + public SetRemoteViewsAdapterIntent(int id, Intent intent) { + this.viewId = id; + this.intent = intent; + } + + public SetRemoteViewsAdapterIntent(Parcel parcel) { + viewId = parcel.readInt(); + intent = Intent.CREATOR.createFromParcel(parcel); + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(TAG); + dest.writeInt(viewId); + intent.writeToParcel(dest, flags); + } + + @Override + public void apply(View root, ViewGroup rootParent) { + final View target = root.findViewById(viewId); + if (target == null) return; + + // Ensure that we are applying to an AppWidget root + if (!(rootParent instanceof AppWidgetHostView)) { + Log.e("RemoteViews", "SetRemoteViewsAdapterIntent action can only be used for " + + "AppWidgets (root id: " + viewId + ")"); + return; + } + // Ensure that we are calling setRemoteAdapter on an AdapterView that supports it + if (!(target instanceof AbsListView) && !(target instanceof AdapterViewAnimator)) { + Log.e("RemoteViews", "Cannot setRemoteViewsAdapter on a view which is not " + + "an AbsListView or AdapterViewAnimator (id: " + viewId + ")"); + return; + } + + // Embed the AppWidget Id for use in RemoteViewsAdapter when connecting to the intent + // RemoteViewsService + AppWidgetHostView host = (AppWidgetHostView) rootParent; + intent.putExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, host.getAppWidgetId()); + if (target instanceof AbsListView) { + AbsListView v = (AbsListView) target; + v.setRemoteViewsAdapter(intent); + } else if (target instanceof AdapterViewAnimator) { + AdapterViewAnimator v = (AdapterViewAnimator) target; + v.setRemoteViewsAdapter(intent); + } + } + + int viewId; + Intent intent; + + public final static int TAG = 10; + } + /** * Equivalent to calling * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)} @@ -383,7 +437,7 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root) { + public void apply(View root, ViewGroup rootParent) { final View target = root.findViewById(viewId); if (target == null) return; @@ -479,7 +533,7 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root) { + public void apply(View root, ViewGroup rootParent) { final View target = root.findViewById(viewId); if (target == null) return; @@ -539,7 +593,7 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root) { + public void apply(View root, ViewGroup rootParent) { final View view = root.findViewById(viewId); if (view == null) return; @@ -755,7 +809,7 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root) { + public void apply(View root, ViewGroup rootParent) { final View view = root.findViewById(viewId); if (view == null) return; @@ -850,7 +904,7 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root) { + public void apply(View root, ViewGroup rootParent) { final Context context = root.getContext(); final ViewGroup target = (ViewGroup) root.findViewById(viewId); if (target == null) return; @@ -952,6 +1006,9 @@ public class RemoteViews implements Parcelable, Filter { case SetOnClickFillInIntent.TAG: mActions.add(new SetOnClickFillInIntent(parcel)); break; + case SetRemoteViewsAdapterIntent.TAG: + mActions.add(new SetRemoteViewsAdapterIntent(parcel)); + break; default: throw new ActionException("Tag " + tag + " not found"); } @@ -1287,16 +1344,29 @@ public class RemoteViews implements Parcelable, Filter { /** * Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}. * - * @param appWidgetId The id of the app widget which contains the specified view + * @param appWidgetId The id of the app widget which contains the specified view. (This + * parameter is ignored in this deprecated method) * @param viewId The id of the view whose text should change * @param intent The intent of the service which will be * providing data to the RemoteViewsAdapter + * @deprecated This method has been deprecated. See + * {@link android.widget.RemoteViews#setRemoteAdapter(int, Intent)} */ + @Deprecated public void setRemoteAdapter(int appWidgetId, int viewId, Intent intent) { - // Embed the AppWidget Id for use in RemoteViewsAdapter when connecting to the intent - // RemoteViewsService - intent.putExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, appWidgetId); - setIntent(viewId, "setRemoteViewsAdapter", intent); + setRemoteAdapter(viewId, intent); + } + + /** + * Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}. + * Can only be used for App Widgets. + * + * @param viewId The id of the view whose text should change + * @param intent The intent of the service which will be + * providing data to the RemoteViewsAdapter + */ + public void setRemoteAdapter(int viewId, Intent intent) { + addAction(new SetRemoteViewsAdapterIntent(viewId, intent)); } /** @@ -1499,7 +1569,7 @@ public class RemoteViews implements Parcelable, Filter { result = inflater.inflate(mLayoutId, parent, false); - performApply(result); + performApply(result, parent); return result; } @@ -1514,15 +1584,15 @@ public class RemoteViews implements Parcelable, Filter { */ public void reapply(Context context, View v) { prepareContext(context); - performApply(v); + performApply(v, (ViewGroup) v.getParent()); } - private void performApply(View v) { + private void performApply(View v, ViewGroup parent) { if (mActions != null) { final int count = mActions.size(); for (int i = 0; i < count; i++) { Action a = mActions.get(i); - a.apply(v); + a.apply(v, parent); } } } diff --git a/core/java/com/android/internal/os/SamplingProfilerIntegration.java b/core/java/com/android/internal/os/SamplingProfilerIntegration.java index 268a9d4..df0fcd9 100644 --- a/core/java/com/android/internal/os/SamplingProfilerIntegration.java +++ b/core/java/com/android/internal/os/SamplingProfilerIntegration.java @@ -20,13 +20,15 @@ import android.content.pm.PackageInfo; import android.os.Build; import android.os.SystemProperties; import android.util.Log; -import dalvik.system.profiler.AsciiHprofWriter; +import dalvik.system.profiler.BinaryHprofWriter; import dalvik.system.profiler.SamplingProfiler; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.io.PrintStream; +import java.util.Date; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; @@ -81,7 +83,8 @@ public class SamplingProfilerIntegration { } } - private static SamplingProfiler INSTANCE; + private static SamplingProfiler samplingProfiler; + private static long startMillis; /** * Is profiling enabled? @@ -97,10 +100,16 @@ public class SamplingProfilerIntegration { if (!enabled) { return; } + if (samplingProfiler != null) { + Log.e(TAG, "SamplingProfilerIntegration already started at " + new Date(startMillis)); + return; + } + ThreadGroup group = Thread.currentThread().getThreadGroup(); SamplingProfiler.ThreadSet threadSet = SamplingProfiler.newThreadGroupTheadSet(group); - INSTANCE = new SamplingProfiler(samplingProfilerDepth, threadSet); - INSTANCE.start(samplingProfilerMilliseconds); + samplingProfiler = new SamplingProfiler(samplingProfilerDepth, threadSet); + samplingProfiler.start(samplingProfilerMilliseconds); + startMillis = System.currentTimeMillis(); } /** @@ -110,6 +119,10 @@ public class SamplingProfilerIntegration { if (!enabled) { return; } + if (samplingProfiler == null) { + Log.e(TAG, "SamplingProfilerIntegration is not started"); + return; + } /* * If we're already writing a snapshot, don't bother enqueueing another @@ -138,8 +151,9 @@ public class SamplingProfilerIntegration { return; } writeSnapshotFile("zygote", null); - INSTANCE.shutdown(); - INSTANCE = null; + samplingProfiler.shutdown(); + samplingProfiler = null; + startMillis = 0; } /** @@ -149,40 +163,44 @@ public class SamplingProfilerIntegration { if (!enabled) { return; } - INSTANCE.stop(); + samplingProfiler.stop(); /* - * We use the current time as a unique ID. We can't use a counter - * because processes restart. This could result in some overlap if - * we capture two snapshots in rapid succession. + * We use the global start time combined with the process name + * as a unique ID. We can't use a counter because processes + * restart. This could result in some overlap if we capture + * two snapshots in rapid succession. */ - long start = System.currentTimeMillis(); String name = processName.replaceAll(":", "."); - String path = SNAPSHOT_DIR + "/" + name + "-" +System.currentTimeMillis() + ".snapshot"; - PrintStream out = null; + String path = SNAPSHOT_DIR + "/" + name + "-" + startMillis + ".snapshot"; + long start = System.currentTimeMillis(); + OutputStream outputStream = null; try { - out = new PrintStream(new BufferedOutputStream(new FileOutputStream(path))); + outputStream = new BufferedOutputStream(new FileOutputStream(path)); + PrintStream out = new PrintStream(outputStream); generateSnapshotHeader(name, packageInfo, out); - new AsciiHprofWriter(INSTANCE.getHprofData(), out).write(); if (out.checkError()) { throw new IOException(); } + BinaryHprofWriter.write(samplingProfiler.getHprofData(), outputStream); } catch (IOException e) { Log.e(TAG, "Error writing snapshot to " + path, e); return; } finally { - IoUtils.closeQuietly(out); + IoUtils.closeQuietly(outputStream); } // set file readable to the world so that SamplingProfilerService // can put it to dropbox new File(path).setReadable(true, false); long elapsed = System.currentTimeMillis() - start; - Log.i(TAG, "Wrote snapshot for " + name + " in " + elapsed + "ms."); + Log.i(TAG, "Wrote snapshot " + path + " in " + elapsed + "ms."); + samplingProfiler.start(samplingProfilerMilliseconds); } /** - * generate header for snapshots, with the following format (like http header): + * generate header for snapshots, with the following format + * (like an HTTP header but without the \r): * * Version: <version number of profiler>\n * Process: <process name>\n @@ -195,7 +213,7 @@ public class SamplingProfilerIntegration { private static void generateSnapshotHeader(String processName, PackageInfo packageInfo, PrintStream out) { // profiler version - out.println("Version: 2"); + out.println("Version: 3"); out.println("Process: " + processName); if (packageInfo != null) { out.println("Package: " + packageInfo.packageName); diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 0fefbf2..4109ae1 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1657,4 +1657,6 @@ <public type="attr" name="state_drag_can_accept" /> <public type="attr" name="state_drag_hovered" /> + <public type="style" name="Theme.Holo.Light.NoActionBar" /> + </resources> diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm index 51a8b27..ef0a4e6 100644 --- a/data/keyboards/Generic.kcm +++ b/data/keyboards/Generic.kcm @@ -287,8 +287,8 @@ key 9 { key SPACE { label: ' ' base: ' ' - ctrl, alt: none - meta: fallback SEARCH + ctrl: none + alt, meta: fallback SEARCH } key ENTER { @@ -300,8 +300,8 @@ key ENTER { key TAB { label: '\t' base: '\t' - ctrl, alt: none - meta: fallback APP_SWITCH + ctrl: none + alt, meta: fallback APP_SWITCH } key COMMA { @@ -542,8 +542,8 @@ key PLUS { key ESCAPE { base: fallback BACK - meta: fallback HOME - alt: fallback MENU + alt, meta: fallback HOME + ctrl: fallback MENU } ### Gamepad buttons ### diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h index d30e908..6b6fcdf 100644 --- a/include/media/stagefright/DataSource.h +++ b/include/media/stagefright/DataSource.h @@ -84,6 +84,8 @@ public: return String8(); } + virtual String8 getMIMEType() const; + protected: virtual ~DataSource() {} diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 7940de0..759bd86 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -1693,29 +1693,37 @@ status_t AwesomePlayer::finishSetDataSource_l() { dataSource = mCachedSource; - // We're going to prefill the cache before trying to instantiate - // the extractor below, as the latter is an operation that otherwise - // could block on the datasource for a significant amount of time. - // During that time we'd be unable to abort the preparation phase - // without this prefill. + String8 contentType = dataSource->getMIMEType(); - mLock.unlock(); + if (strncasecmp(contentType.string(), "audio/", 6)) { + // We're not doing this for streams that appear to be audio-only + // streams to ensure that even low bandwidth streams start + // playing back fairly instantly. - for (;;) { - status_t finalStatus; - size_t cachedDataRemaining = - mCachedSource->approxDataRemaining(&finalStatus); + // We're going to prefill the cache before trying to instantiate + // the extractor below, as the latter is an operation that otherwise + // could block on the datasource for a significant amount of time. + // During that time we'd be unable to abort the preparation phase + // without this prefill. + + mLock.unlock(); + + for (;;) { + status_t finalStatus; + size_t cachedDataRemaining = + mCachedSource->approxDataRemaining(&finalStatus); - if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes - || (mFlags & PREPARE_CANCELLED)) { - break; + if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes + || (mFlags & PREPARE_CANCELLED)) { + break; + } + + usleep(200000); } - usleep(200000); + mLock.lock(); } - mLock.lock(); - if (mFlags & PREPARE_CANCELLED) { LOGI("Prepare cancelled while waiting for initial cache fill."); return UNKNOWN_ERROR; diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index b5c51f4..7c2096e 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -144,4 +144,8 @@ sp<DataSource> DataSource::CreateFromURI( return source; } +String8 DataSource::getMIMEType() const { + return String8("application/octet-stream"); +} + } // namespace android diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index 3c99d1c..c1aa46e 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -493,4 +493,8 @@ String8 NuCachedSource2::getUri() { return mSource->getUri(); } +String8 NuCachedSource2::getMIMEType() const { + return mSource->getMIMEType(); +} + } // namespace android diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp index 73daf12..5c43a5b 100644 --- a/media/libstagefright/NuHTTPDataSource.cpp +++ b/media/libstagefright/NuHTTPDataSource.cpp @@ -136,6 +136,7 @@ status_t NuHTTPDataSource::connect( unsigned port; mUri = uri; + mContentType = String8("application/octet-stream"); bool https; if (!ParseURL(uri, &host, &port, &path, &https)) { @@ -265,6 +266,15 @@ status_t NuHTTPDataSource::connect( } } + { + AString value; + if (mHTTP.find_header_value("Content-Type", &value)) { + mContentType = String8(value.c_str()); + } else { + mContentType = String8("application/octet-stream"); + } + } + applyTimeoutResponse(); if (offset == 0) { @@ -564,4 +574,8 @@ String8 NuHTTPDataSource::getUri() { return mUri; } +String8 NuHTTPDataSource::getMIMEType() const { + return mContentType; +} + } // namespace android diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp index e9e5ef9..76f47f7 100644 --- a/media/libstagefright/WAVExtractor.cpp +++ b/media/libstagefright/WAVExtractor.cpp @@ -425,6 +425,11 @@ bool SniffWAV( return false; } + sp<MediaExtractor> extractor = new WAVExtractor(source); + if (extractor->countTracks() == 0) { + return false; + } + *mimeType = MEDIA_MIMETYPE_CONTAINER_WAV; *confidence = 0.3f; diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp index 949a5e4..1096717 100644 --- a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp +++ b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp @@ -79,6 +79,7 @@ status_t ChromiumHTTPDataSource::connect_l( } mURI = uri; + mContentType = String8("application/octet-stream"); if (headers != NULL) { mHeaders = *headers; @@ -99,10 +100,12 @@ status_t ChromiumHTTPDataSource::connect_l( return mState == CONNECTED ? OK : mIOResult; } -void ChromiumHTTPDataSource::onConnectionEstablished(int64_t contentSize) { +void ChromiumHTTPDataSource::onConnectionEstablished( + int64_t contentSize, const char *contentType) { Mutex::Autolock autoLock(mLock); mState = CONNECTED; mContentSize = (contentSize < 0) ? -1 : contentSize + mCurrentOffset; + mContentType = String8(contentType); mCondition.broadcast(); } @@ -314,6 +317,12 @@ String8 ChromiumHTTPDataSource::getUri() { return String8(mURI.c_str()); } +String8 ChromiumHTTPDataSource::getMIMEType() const { + Mutex::Autolock autoLock(mLock); + + return mContentType; +} + void ChromiumHTTPDataSource::clearDRMState_l() { if (mDecryptHandle != NULL) { // To release mDecryptHandle diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp index 7ac56e8..af2f6ac 100644 --- a/media/libstagefright/chromium_http/support.cpp +++ b/media/libstagefright/chromium_http/support.cpp @@ -253,7 +253,11 @@ void SfDelegate::OnResponseStarted(URLRequest *request) { MY_LOGV(StringPrintf("response headers: %s", headers.c_str()).c_str()); - mOwner->onConnectionEstablished(request->GetExpectedContentSize()); + std::string contentType; + request->GetResponseHeaderByName("Content-Type", &contentType); + + mOwner->onConnectionEstablished( + request->GetExpectedContentSize(), contentType.c_str()); } void SfDelegate::OnReadCompleted(URLRequest *request, int bytes_read) { diff --git a/media/libstagefright/include/ChromiumHTTPDataSource.h b/media/libstagefright/include/ChromiumHTTPDataSource.h index af49059..0e2927d 100644 --- a/media/libstagefright/include/ChromiumHTTPDataSource.h +++ b/media/libstagefright/include/ChromiumHTTPDataSource.h @@ -51,6 +51,8 @@ struct ChromiumHTTPDataSource : public HTTPBase { virtual String8 getUri(); + virtual String8 getMIMEType() const; + protected: virtual ~ChromiumHTTPDataSource(); @@ -90,6 +92,8 @@ private: int64_t mContentSize; + String8 mContentType; + List<BandwidthEntry> mBandwidthHistory; size_t mNumBandwidthHistoryItems; int64_t mTotalTransferTimeUs; @@ -110,7 +114,9 @@ private: void initiateRead(void *data, size_t size); - void onConnectionEstablished(int64_t contentSize); + void onConnectionEstablished( + int64_t contentSize, const char *contentType); + void onConnectionFailed(status_t err); void onReadCompleted(ssize_t size); void onDisconnectComplete(); diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h index 02d5817..2128682 100644 --- a/media/libstagefright/include/NuCachedSource2.h +++ b/media/libstagefright/include/NuCachedSource2.h @@ -40,6 +40,9 @@ struct NuCachedSource2 : public DataSource { virtual sp<DecryptHandle> DrmInitialization(); virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client); virtual String8 getUri(); + + virtual String8 getMIMEType() const; + //////////////////////////////////////////////////////////////////////////// size_t cachedSize(); diff --git a/media/libstagefright/include/NuHTTPDataSource.h b/media/libstagefright/include/NuHTTPDataSource.h index 7dd5d59..2ab1f19 100644 --- a/media/libstagefright/include/NuHTTPDataSource.h +++ b/media/libstagefright/include/NuHTTPDataSource.h @@ -51,6 +51,8 @@ struct NuHTTPDataSource : public HTTPBase { virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client); virtual String8 getUri(); + virtual String8 getMIMEType() const; + protected: virtual ~NuHTTPDataSource(); @@ -85,6 +87,8 @@ private: bool mContentLengthValid; bool mHasChunkedTransferEncoding; + String8 mContentType; + // The number of data bytes in the current chunk before any subsequent // chunk header (or -1 if no more chunks). ssize_t mChunkDataBytesLeft; diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 4fa5bcb..44f55b3 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -626,7 +626,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_DIALOG) { - showRecentAppsDialog(); + showRecentAppsDialog(0); } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_ACTIVITY) { try { Intent intent = new Intent(); @@ -645,12 +645,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** * Create (if necessary) and launch the recent apps dialog */ - void showRecentAppsDialog() { + void showRecentAppsDialog(final int initialModifiers) { mHandler.post(new Runnable() { @Override public void run() { if (mRecentAppsDialog == null) { - mRecentAppsDialog = new RecentApplicationsDialog(mContext); + mRecentAppsDialog = new RecentApplicationsDialog(mContext, initialModifiers); } mRecentAppsDialog.show(); } @@ -1392,7 +1392,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) { if (down && repeatCount == 0) { - showRecentAppsDialog(); + showRecentAppsDialog(event.getMetaState() & KeyEvent.getModifierMetaStateMask()); } return true; } diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java index db66346..c4b7822 100644 --- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java @@ -17,16 +17,13 @@ package com.android.internal.policy.impl; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.Dialog; -import android.app.IActivityManager; import android.app.StatusBarManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Resources; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -34,6 +31,8 @@ import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.util.Log; +import android.view.KeyEvent; +import android.view.SoundEffectConstants; import android.view.View; import android.view.Window; import android.view.WindowManager; @@ -72,13 +71,12 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener } }; - private int mIconSize; + private int mInitialModifiers; - public RecentApplicationsDialog(Context context) { + public RecentApplicationsDialog(Context context, int initialModifiers) { super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications); - final Resources resources = context.getResources(); - mIconSize = (int) resources.getDimension(android.R.dimen.app_icon_size); + mInitialModifiers = initialModifiers; } /** @@ -127,34 +125,102 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener } } + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_APP_SWITCH || keyCode == KeyEvent.KEYCODE_TAB) { + // Ignore all meta keys other than SHIFT. The app switch key could be a + // fallback action chorded with ALT, META or even CTRL depending on the key map. + // DPad navigation is handled by the ViewRoot elsewhere. + final boolean backward = event.isShiftPressed(); + final int numIcons = mIcons.length; + int numButtons = 0; + while (numButtons < numIcons && mIcons[numButtons].getVisibility() == View.VISIBLE) { + numButtons += 1; + } + if (numButtons != 0) { + int nextFocus = backward ? numButtons - 1 : 0; + for (int i = 0; i < numButtons; i++) { + if (mIcons[i].hasFocus()) { + if (backward) { + nextFocus = (i + numButtons - 1) % numButtons; + } else { + nextFocus = (i + 1) % numButtons; + } + break; + } + } + final int direction = backward ? View.FOCUS_BACKWARD : View.FOCUS_FORWARD; + if (mIcons[nextFocus].requestFocus(direction)) { + mIcons[nextFocus].playSoundEffect( + SoundEffectConstants.getContantForFocusDirection(direction)); + } + } + + // The dialog always handles the key to prevent the ViewRoot from + // performing the default navigation itself. + return true; + } + + return super.onKeyDown(keyCode, event); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (mInitialModifiers != 0 && event.hasNoModifiers()) { + final int numIcons = mIcons.length; + RecentTag tag = null; + for (int i = 0; i < numIcons; i++) { + if (mIcons[i].getVisibility() != View.VISIBLE) { + break; + } + if (i == 0 || mIcons[i].hasFocus()) { + tag = (RecentTag) mIcons[i].getTag(); + if (mIcons[i].hasFocus()) { + break; + } + } + } + if (tag != null) { + switchTo(tag); + } + dismiss(); + return true; + } + + return super.onKeyUp(keyCode, event); + } + /** * Handler for user clicks. If a button was clicked, launch the corresponding activity. */ public void onClick(View v) { - for (TextView b: mIcons) { if (b == v) { RecentTag tag = (RecentTag)b.getTag(); - if (tag.info.id >= 0) { - // This is an active task; it should just go to the foreground. - final ActivityManager am = (ActivityManager) - getContext().getSystemService(Context.ACTIVITY_SERVICE); - am.moveTaskToFront(tag.info.id, ActivityManager.MOVE_TASK_WITH_HOME); - } else if (tag.intent != null) { - tag.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY - | Intent.FLAG_ACTIVITY_TASK_ON_HOME); - try { - getContext().startActivity(tag.intent); - } catch (ActivityNotFoundException e) { - Log.w("Recent", "Unable to launch recent task", e); - } - } + switchTo(tag); break; } } dismiss(); } + private void switchTo(RecentTag tag) { + if (tag.info.id >= 0) { + // This is an active task; it should just go to the foreground. + final ActivityManager am = (ActivityManager) + getContext().getSystemService(Context.ACTIVITY_SERVICE); + am.moveTaskToFront(tag.info.id, ActivityManager.MOVE_TASK_WITH_HOME); + } else if (tag.intent != null) { + tag.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY + | Intent.FLAG_ACTIVITY_TASK_ON_HOME); + try { + getContext().startActivity(tag.intent); + } catch (ActivityNotFoundException e) { + Log.w("Recent", "Unable to launch recent task", e); + } + } + } + /** * Set up and show the recent activities dialog. */ diff --git a/services/java/com/android/server/LightsService.java b/services/java/com/android/server/LightsService.java index 21f2bcf..1e95f3e 100644 --- a/services/java/com/android/server/LightsService.java +++ b/services/java/com/android/server/LightsService.java @@ -148,7 +148,6 @@ public class LightsService { fis.close(); return (result != '0'); } catch (Exception e) { - Slog.e(TAG, "getFlashlightEnabled failed", e); return false; } } @@ -168,7 +167,7 @@ public class LightsService { fos.write(bytes); fos.close(); } catch (Exception e) { - Slog.e(TAG, "setFlashlightEnabled failed", e); + // fail silently } } }; |