summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/stagefright/Android.mk24
-rw-r--r--cmds/stagefright/stream.cpp168
-rw-r--r--core/java/android/view/Surface.java13
-rw-r--r--core/java/android/view/WindowManager.java10
-rw-r--r--core/jni/android_view_Surface.cpp62
-rw-r--r--core/res/res/values/config.xml4
-rw-r--r--include/media/IMediaPlayerService.h6
-rw-r--r--include/media/IStreamSource.h66
-rw-r--r--include/media/MediaPlayerInterface.h5
-rw-r--r--include/ui/InputDispatcher.h4
-rw-r--r--media/libmedia/Android.mk1
-rw-r--r--media/libmedia/IMediaPlayerService.cpp38
-rw-r--r--media/libmedia/IStreamSource.cpp168
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp44
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h8
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.cpp4
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.h3
-rw-r--r--media/libstagefright/AwesomePlayer.cpp227
-rw-r--r--media/libstagefright/include/AwesomePlayer.h2
-rw-r--r--packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml18
-rw-r--r--packages/SystemUI/res/values-xlarge/dimens.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java1
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java121
-rw-r--r--services/java/com/android/server/ScreenRotationAnimation.java152
-rw-r--r--services/java/com/android/server/WindowManagerService.java39
26 files changed, 1129 insertions, 67 deletions
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 93baefd..f8650eb 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -98,3 +98,27 @@ LOCAL_MODULE_TAGS := debug
LOCAL_MODULE:= audioloop
include $(BUILD_EXECUTABLE)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ stream.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright liblog libutils libbinder libsurfaceflinger_client \
+ libstagefright_foundation libmedia
+
+LOCAL_C_INCLUDES:= \
+ $(JNI_H_INCLUDE) \
+ frameworks/base/media/libstagefright \
+ $(TOP)/frameworks/base/include/media/stagefright/openmax
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE:= stream
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
new file mode 100644
index 0000000..f2b5638
--- /dev/null
+++ b/cmds/stagefright/stream.cpp
@@ -0,0 +1,168 @@
+#include <binder/ProcessState.h>
+
+#include <media/IStreamSource.h>
+#include <media/mediaplayer.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <binder/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include <fcntl.h>
+
+using namespace android;
+
+struct MyStreamSource : public BnStreamSource {
+ // Caller retains ownership of fd.
+ MyStreamSource(int fd);
+
+ virtual void setListener(const sp<IStreamListener> &listener);
+ virtual void setBuffers(const Vector<sp<IMemory> > &buffers);
+
+ virtual void onBufferAvailable(size_t index);
+
+protected:
+ virtual ~MyStreamSource();
+
+private:
+ int mFd;
+
+ sp<IStreamListener> mListener;
+ Vector<sp<IMemory> > mBuffers;
+
+ DISALLOW_EVIL_CONSTRUCTORS(MyStreamSource);
+};
+
+MyStreamSource::MyStreamSource(int fd)
+ : mFd(fd) {
+ CHECK_GE(fd, 0);
+}
+
+MyStreamSource::~MyStreamSource() {
+}
+
+void MyStreamSource::setListener(const sp<IStreamListener> &listener) {
+ mListener = listener;
+}
+
+void MyStreamSource::setBuffers(const Vector<sp<IMemory> > &buffers) {
+ mBuffers = buffers;
+}
+
+void MyStreamSource::onBufferAvailable(size_t index) {
+ CHECK_LT(index, mBuffers.size());
+ sp<IMemory> mem = mBuffers.itemAt(index);
+
+ ssize_t n = read(mFd, mem->pointer(), mem->size());
+ if (n <= 0) {
+ mListener->queueCommand(IStreamListener::EOS);
+ } else {
+ mListener->queueBuffer(index, n);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct MyClient : public BnMediaPlayerClient {
+ MyClient()
+ : mEOS(false) {
+ }
+
+ virtual void notify(int msg, int ext1, int ext2) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (msg == MEDIA_ERROR || msg == MEDIA_PLAYBACK_COMPLETE) {
+ mEOS = true;
+ mCondition.signal();
+ }
+ }
+
+ void waitForEOS() {
+ Mutex::Autolock autoLock(mLock);
+ while (!mEOS) {
+ mCondition.wait(mLock);
+ }
+ }
+
+protected:
+ virtual ~MyClient() {
+ }
+
+private:
+ Mutex mLock;
+ Condition mCondition;
+
+ bool mEOS;
+
+ DISALLOW_EVIL_CONSTRUCTORS(MyClient);
+};
+
+int main(int argc, char **argv) {
+ android::ProcessState::self()->startThreadPool();
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s filename\n", argv[0]);
+ return 1;
+ }
+
+ sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
+ CHECK_EQ(composerClient->initCheck(), (status_t)OK);
+
+ sp<SurfaceControl> control =
+ composerClient->createSurface(
+ getpid(),
+ String8("A Surface"),
+ 0,
+ 1280,
+ 800,
+ PIXEL_FORMAT_RGB_565,
+ 0);
+
+ CHECK(control != NULL);
+ CHECK(control->isValid());
+
+ CHECK_EQ(composerClient->openTransaction(), (status_t)OK);
+ CHECK_EQ(control->setLayer(30000), (status_t)OK);
+ CHECK_EQ(control->show(), (status_t)OK);
+ CHECK_EQ(composerClient->closeTransaction(), (status_t)OK);
+
+ sp<Surface> surface = control->getSurface();
+ CHECK(surface != NULL);
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+
+ CHECK(service.get() != NULL);
+
+ int fd = open(argv[1], O_RDONLY);
+
+ if (fd < 0) {
+ fprintf(stderr, "Failed to open file '%s'.", argv[1]);
+ return 1;
+ }
+
+ sp<MyClient> client = new MyClient;
+
+ sp<IMediaPlayer> player =
+ service->create(getpid(), client, new MyStreamSource(fd), 0);
+
+ if (player != NULL) {
+ player->setVideoSurface(surface);
+ player->start();
+
+ client->waitForEOS();
+
+ player->stop();
+ } else {
+ fprintf(stderr, "failed to instantiate player.\n");
+ }
+
+ close(fd);
+ fd = -1;
+
+ composerClient->dispose();
+
+ return 0;
+}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index d596a7f..e967522 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -374,6 +374,19 @@ public class Surface implements Parcelable {
}
/**
+ * Copy the current screen contents into a bitmap and return it.
+ *
+ * @param width The desired width of the returned bitmap; the raw
+ * screen will be scaled down to this size.
+ * @param height The desired height of the returned bitmap; the raw
+ * screen will be scaled down to this size.
+ * @return Returns a Bitmap containing the screen contents.
+ *
+ * @hide
+ */
+ public static native Bitmap screenshot(int width, int height);
+
+ /**
* set surface parameters.
* needs to be inside open/closeTransaction block
*/
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 784951f..51016f5 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -171,6 +171,7 @@ public interface WindowManager extends ViewManager {
@ViewDebug.IntToString(from = TYPE_SYSTEM_OVERLAY, to = "TYPE_SYSTEM_OVERLAY"),
@ViewDebug.IntToString(from = TYPE_PRIORITY_PHONE, to = "TYPE_PRIORITY_PHONE"),
@ViewDebug.IntToString(from = TYPE_STATUS_BAR_PANEL, to = "TYPE_STATUS_BAR_PANEL"),
+ @ViewDebug.IntToString(from = TYPE_STATUS_BAR_SUB_PANEL, to = "TYPE_STATUS_BAR_SUB_PANEL"),
@ViewDebug.IntToString(from = TYPE_SYSTEM_DIALOG, to = "TYPE_SYSTEM_DIALOG"),
@ViewDebug.IntToString(from = TYPE_KEYGUARD_DIALOG, to = "TYPE_KEYGUARD_DIALOG"),
@ViewDebug.IntToString(from = TYPE_SYSTEM_ERROR, to = "TYPE_SYSTEM_ERROR"),
@@ -351,7 +352,7 @@ public interface WindowManager extends ViewManager {
public static final int TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13;
/**
- * Window type: panel that slides out from the status bar
+ * Window type: panel that slides out from over the status bar
*/
public static final int TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14;
@@ -375,6 +376,13 @@ public interface WindowManager extends ViewManager {
public static final int TYPE_DRAG = FIRST_SYSTEM_WINDOW+16;
/**
+ * Window type: panel that slides out from under the status bar
+ * @hide
+ */
+ public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;
+
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index c4d6d1b..9a85edc 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -19,7 +19,9 @@
#include <stdio.h>
#include "android_util_Binder.h"
+#include "android/graphics/GraphicsJNI.h"
+#include <binder/IMemory.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <surfaceflinger/Surface.h>
#include <ui/Region.h>
@@ -91,15 +93,6 @@ struct no_t {
static no_t no;
-static __attribute__((noinline))
-void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
-{
- if (!env->ExceptionOccurred()) {
- jclass npeClazz = env->FindClass(exc);
- env->ThrowNew(npeClazz, msg);
- }
-}
-
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
@@ -444,6 +437,56 @@ static void Surface_unfreezeDisplay(
}
}
+class ScreenshotBitmap : public SkBitmap {
+public:
+ ScreenshotBitmap() {
+ }
+
+ status_t update(int width, int height) {
+ status_t res = (width > 0 && height > 0)
+ ? mScreenshot.update(width, height)
+ : mScreenshot.update();
+ if (res != NO_ERROR) {
+ return res;
+ }
+
+ void const* base = mScreenshot.getPixels();
+ uint32_t w = mScreenshot.getWidth();
+ uint32_t h = mScreenshot.getHeight();
+ uint32_t s = mScreenshot.getStride();
+ uint32_t f = mScreenshot.getFormat();
+
+ ssize_t bpr = s * android::bytesPerPixel(f);
+ setConfig(convertPixelFormat(f), w, h, bpr);
+ if (f == PIXEL_FORMAT_RGBX_8888) {
+ setIsOpaque(true);
+ }
+ if (w > 0 && h > 0) {
+ setPixels((void*)base);
+ } else {
+ // be safe with an empty bitmap.
+ setPixels(NULL);
+ }
+
+ return NO_ERROR;
+ }
+
+private:
+ ScreenshotClient mScreenshot;
+};
+
+static jobject Surface_screenshot(JNIEnv* env, jobject clazz, jint width, jint height)
+{
+ ScreenshotBitmap* bitmap = new ScreenshotBitmap();
+
+ if (bitmap->update(width, height) != NO_ERROR) {
+ delete bitmap;
+ return 0;
+ }
+
+ return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
+}
+
static void Surface_setLayer(
JNIEnv* env, jobject clazz, jint zorder)
{
@@ -669,6 +712,7 @@ static JNINativeMethod gSurfaceMethods[] = {
{"setOrientation", "(III)V", (void*)Surface_setOrientation },
{"freezeDisplay", "(I)V", (void*)Surface_freezeDisplay },
{"unfreezeDisplay", "(I)V", (void*)Surface_unfreezeDisplay },
+ {"screenshot", "(II)Landroid/graphics/Bitmap;", (void*)Surface_screenshot },
{"setLayer", "(I)V", (void*)Surface_setLayer },
{"setPosition", "(II)V",(void*)Surface_setPosition },
{"setSize", "(II)V",(void*)Surface_setSize },
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 15b5db4..61223b3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -195,6 +195,10 @@
<!-- XXXXXX END OF RESOURCES USING WRONG NAMING CONVENTION -->
+ <!-- If true, the screen can be rotated via the accelerometer in all 4
+ rotations as the default behavior. -->
+ <bool name="config_allowAllRotations">true</bool>
+
<!-- The number of degrees to rotate the display when the keyboard is open. -->
<integer name="config_lidOpenRotation">90</integer>
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index 9416ca1..0bfb166 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -32,6 +32,7 @@ namespace android {
class IMediaRecorder;
class IOMX;
+struct IStreamSource;
class IMediaPlayerService: public IInterface
{
@@ -45,6 +46,11 @@ public:
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<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;
virtual sp<IOMX> getOMX() = 0;
diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h
new file mode 100644
index 0000000..6291124
--- /dev/null
+++ b/include/media/IStreamSource.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_ISTREAMSOURCE_H_
+
+#define ANDROID_ISTREAMSOURCE_H_
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+struct IMemory;
+struct IStreamListener;
+
+struct IStreamSource : public IInterface {
+ DECLARE_META_INTERFACE(StreamSource);
+
+ virtual void setListener(const sp<IStreamListener> &listener) = 0;
+ virtual void setBuffers(const Vector<sp<IMemory> > &buffers) = 0;
+
+ virtual void onBufferAvailable(size_t index) = 0;
+};
+
+struct IStreamListener : public IInterface {
+ DECLARE_META_INTERFACE(StreamListener);
+
+ enum Command {
+ FLUSH,
+ DISCONTINUITY,
+ EOS
+ };
+
+ virtual void queueBuffer(size_t index, size_t size) = 0;
+ virtual void queueCommand(Command cmd) = 0;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct BnStreamSource : public BnInterface<IStreamSource> {
+ virtual status_t onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply,
+ uint32_t flags = 0);
+};
+
+struct BnStreamListener : public BnInterface<IStreamListener> {
+ virtual status_t onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply,
+ uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // ANDROID_ISTREAMSOURCE_H_
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 672931e..e7f1d6d 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -106,6 +106,11 @@ public:
const KeyedVector<String8, String8> *headers = NULL) = 0;
virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0;
+
+ virtual status_t setDataSource(const sp<IStreamSource> &source) {
+ return INVALID_OPERATION;
+ }
+
virtual status_t setVideoSurface(const sp<Surface>& surface) = 0;
virtual status_t prepare() = 0;
virtual status_t prepareAsync() = 0;
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index 15a3925..d0812de 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -179,8 +179,10 @@ struct InputWindow {
TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11,
TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12,
TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13,
- TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14,
+ TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+14,
TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15,
+ TYPE_DRAG = FIRST_SYSTEM_WINDOW+16,
+ TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+17,
LAST_SYSTEM_WINDOW = 2999,
};
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 2e5cbe3..731c09d 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -15,6 +15,7 @@ LOCAL_SRC_FILES:= \
IMediaRecorderClient.cpp \
IMediaPlayer.cpp \
IMediaRecorder.cpp \
+ IStreamSource.cpp \
Metadata.cpp \
mediarecorder.cpp \
IMediaMetadataRetriever.cpp \
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 4abfa75..77199e1 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -23,6 +23,7 @@
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
#include <media/IOMX.h>
+#include <media/IStreamSource.h>
#include <utils/Errors.h> // for status_t
@@ -31,6 +32,7 @@ namespace android {
enum {
CREATE_URL = IBinder::FIRST_CALL_TRANSACTION,
CREATE_FD,
+ CREATE_STREAM,
DECODE_URL,
DECODE_FD,
CREATE_MEDIA_RECORDER,
@@ -107,6 +109,21 @@ public:
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;
@@ -184,6 +201,27 @@ status_t BnMediaPlayerService::onTransact(
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/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp
new file mode 100644
index 0000000..89f2b44
--- /dev/null
+++ b/media/libmedia/IStreamSource.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IStreamSource"
+#include <utils/Log.h>
+
+#include <media/IStreamSource.h>
+
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+enum {
+ // IStreamSource
+ SET_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
+ SET_BUFFERS,
+ ON_BUFFER_AVAILABLE,
+
+ // IStreamListener
+ QUEUE_BUFFER,
+ QUEUE_COMMAND,
+};
+
+struct BpStreamSource : public BpInterface<IStreamSource> {
+ BpStreamSource(const sp<IBinder> &impl)
+ : BpInterface<IStreamSource>(impl) {
+ }
+
+ virtual void setListener(const sp<IStreamListener> &listener) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IStreamSource::getInterfaceDescriptor());
+ data.writeStrongBinder(listener->asBinder());
+ remote()->transact(SET_LISTENER, data, &reply);
+ }
+
+ virtual void setBuffers(const Vector<sp<IMemory> > &buffers) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IStreamSource::getInterfaceDescriptor());
+ data.writeInt32(static_cast<int32_t>(buffers.size()));
+ for (size_t i = 0; i < buffers.size(); ++i) {
+ data.writeStrongBinder(buffers.itemAt(i)->asBinder());
+ }
+ remote()->transact(SET_BUFFERS, data, &reply);
+ }
+
+ virtual void onBufferAvailable(size_t index) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IStreamSource::getInterfaceDescriptor());
+ data.writeInt32(static_cast<int32_t>(index));
+ remote()->transact(
+ ON_BUFFER_AVAILABLE, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(StreamSource, "android.hardware.IStreamSource");
+
+status_t BnStreamSource::onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+ switch (code) {
+ case SET_LISTENER:
+ {
+ CHECK_INTERFACE(IStreamSource, data, reply);
+ setListener(
+ interface_cast<IStreamListener>(data.readStrongBinder()));
+ break;
+ }
+
+ case SET_BUFFERS:
+ {
+ CHECK_INTERFACE(IStreamSource, data, reply);
+ size_t n = static_cast<size_t>(data.readInt32());
+ Vector<sp<IMemory> > buffers;
+ for (size_t i = 0; i < n; ++i) {
+ sp<IMemory> mem =
+ interface_cast<IMemory>(data.readStrongBinder());
+
+ buffers.push(mem);
+ }
+ setBuffers(buffers);
+ break;
+ }
+
+ case ON_BUFFER_AVAILABLE:
+ {
+ CHECK_INTERFACE(IStreamSource, data, reply);
+ onBufferAvailable(static_cast<size_t>(data.readInt32()));
+ break;
+ }
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+
+ return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct BpStreamListener : public BpInterface<IStreamListener> {
+ BpStreamListener(const sp<IBinder> &impl)
+ : BpInterface<IStreamListener>(impl) {
+ }
+
+ virtual void queueBuffer(size_t index, size_t size) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IStreamListener::getInterfaceDescriptor());
+ data.writeInt32(static_cast<int32_t>(index));
+ data.writeInt32(static_cast<int32_t>(size));
+
+ remote()->transact(QUEUE_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ virtual void queueCommand(Command cmd) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IStreamListener::getInterfaceDescriptor());
+ data.writeInt32(static_cast<int32_t>(cmd));
+
+ remote()->transact(QUEUE_COMMAND, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(StreamListener, "android.hardware.IStreamListener");
+
+status_t BnStreamListener::onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+ switch (code) {
+ case QUEUE_BUFFER:
+ {
+ CHECK_INTERFACE(IStreamListener, data, reply);
+ size_t index = static_cast<size_t>(data.readInt32());
+ size_t size = static_cast<size_t>(data.readInt32());
+
+ queueBuffer(index, size);
+ break;
+ }
+
+ case QUEUE_COMMAND:
+ {
+ CHECK_INTERFACE(IStreamListener, data, reply);
+ Command cmd = static_cast<Command>(data.readInt32());
+
+ queueCommand(cmd);
+ break;
+ }
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 00e510b..63d09d6 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -278,6 +278,26 @@ sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClie
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);
+
+ LOGV("Create new client(%d) from pid %d, audioSessionId=%d",
+ connId, pid, audioSessionId);
+
+ if (OK != c->setDataSource(source)) {
+ c.clear();
+ } else {
+ wp<Client> w = c;
+ Mutex::Autolock lock(mLock);
+ mClients.add(w);
+ }
+
+ return c;
+}
+
sp<IOMX> MediaPlayerService::getOMX() {
Mutex::Autolock autoLock(mLock);
@@ -864,6 +884,30 @@ status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64
return mStatus;
}
+status_t MediaPlayerService::Client::setDataSource(
+ const sp<IStreamSource> &source) {
+ // create the right type of player
+ sp<MediaPlayerBase> p = createPlayer(STAGEFRIGHT_PLAYER);
+
+ if (p == NULL) {
+ return NO_INIT;
+ }
+
+ if (!p->hardwareOutput()) {
+ mAudioOutput = new AudioOutput(mAudioSessionId);
+ static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
+ }
+
+ // now set data source
+ mStatus = p->setDataSource(source);
+
+ if (mStatus == OK) {
+ mPlayer = p;
+ }
+
+ return mStatus;
+}
+
status_t MediaPlayerService::Client::setVideoSurface(const sp<Surface>& surface)
{
LOGV("[%d] setVideoSurface(%p)", mConnId, surface.get());
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 184324c..62f8ed6 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -191,6 +191,11 @@ public:
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<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);
virtual sp<IOMX> getOMX();
@@ -234,6 +239,9 @@ private:
const KeyedVector<String8, String8> *headers);
status_t setDataSource(int fd, int64_t offset, int64_t length);
+
+ status_t setDataSource(const sp<IStreamSource> &source);
+
static void notify(void* cookie, int msg, int ext1, int ext2);
pid_t pid() const { return mPid; }
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 58ef99b..da564dc 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -44,6 +44,10 @@ status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length
return mPlayer->setDataSource(dup(fd), offset, length);
}
+status_t StagefrightPlayer::setDataSource(const sp<IStreamSource> &source) {
+ return mPlayer->setDataSource(source);
+}
+
status_t StagefrightPlayer::setVideoSurface(const sp<Surface> &surface) {
LOGV("setVideoSurface");
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index c4a2588..fc72bfb 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -35,6 +35,9 @@ public:
const char *url, const KeyedVector<String8, String8> *headers);
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
+
+ virtual status_t setDataSource(const sp<IStreamSource> &source);
+
virtual status_t setVideoSurface(const sp<Surface> &surface);
virtual status_t prepare();
virtual status_t prepareAsync();
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index ec58919..a804866 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -34,13 +34,16 @@
#include "UDPPusher.h"
#include <binder/IPCThreadState.h>
+#include <binder/MemoryDealer.h>
+#include <media/IStreamSource.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXCodec.h>
@@ -155,6 +158,201 @@ private:
const AwesomeNativeWindowRenderer &);
};
+////////////////////////////////////////////////////////////////////////////////
+
+struct QueueDataSource;
+
+struct QueueListener : public BnStreamListener {
+ QueueListener(QueueDataSource *owner)
+ : mOwner(owner) {
+ }
+
+ void clearOwner();
+
+ virtual void queueBuffer(size_t index, size_t size);
+ virtual void queueCommand(Command cmd);
+
+private:
+ Mutex mLock;
+
+ QueueDataSource *mOwner;
+
+ DISALLOW_EVIL_CONSTRUCTORS(QueueListener);
+};
+
+struct QueueDataSource : public DataSource {
+ QueueDataSource(const sp<IStreamSource> &source);
+
+ virtual status_t initCheck() const;
+
+ virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+ virtual void queueBuffer(size_t index, size_t size);
+ virtual void queueCommand(IStreamListener::Command cmd);
+
+protected:
+ virtual ~QueueDataSource();
+
+private:
+ enum {
+ kNumBuffers = 16
+ };
+
+ struct BufferInfo {
+ size_t mIndex;
+ size_t mOffset;
+ size_t mSize;
+ };
+
+ Mutex mLock;
+ Condition mCondition;
+
+ sp<IStreamSource> mSource;
+ sp<QueueListener> mListener;
+ sp<MemoryDealer> mDealer;
+ Vector<sp<IMemory> > mBuffers;
+
+ List<BufferInfo> mFilledBuffers;
+
+ off64_t mPosition;
+ bool mEOS;
+
+ DISALLOW_EVIL_CONSTRUCTORS(QueueDataSource);
+};
+
+QueueDataSource::QueueDataSource(const sp<IStreamSource> &source)
+ : mSource(source),
+ mPosition(0),
+ mEOS(false) {
+ mListener = new QueueListener(this);
+ mSource->setListener(mListener);
+
+ static const size_t kBufferSize = 8192;
+
+ mDealer = new MemoryDealer(kNumBuffers * kBufferSize);
+ for (size_t i = 0; i < kNumBuffers; ++i) {
+ sp<IMemory> mem = mDealer->allocate(kBufferSize);
+ CHECK(mem != NULL);
+
+ mBuffers.push(mem);
+ }
+ mSource->setBuffers(mBuffers);
+
+ for (size_t i = 0; i < kNumBuffers; ++i) {
+ mSource->onBufferAvailable(i);
+ }
+}
+
+QueueDataSource::~QueueDataSource() {
+ Mutex::Autolock autoLock(mLock);
+
+ while (mFilledBuffers.size() < kNumBuffers && !mEOS) {
+ mCondition.wait(mLock);
+ }
+
+ mListener->clearOwner();
+}
+
+status_t QueueDataSource::initCheck() const {
+ return OK;
+}
+
+ssize_t QueueDataSource::readAt(off64_t offset, void *data, size_t size) {
+ if (offset != mPosition) {
+ return -EPIPE;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+
+ size_t sizeDone = 0;
+
+ while (sizeDone < size) {
+ while (mFilledBuffers.empty() && !mEOS) {
+ mCondition.wait(mLock);
+ }
+
+ if (mFilledBuffers.empty()) {
+ if (sizeDone > 0) {
+ mPosition += sizeDone;
+ return sizeDone;
+ }
+ return ERROR_END_OF_STREAM;
+ }
+
+ BufferInfo &info = *mFilledBuffers.begin();
+
+ size_t copy = size - sizeDone;
+ if (copy > info.mSize) {
+ copy = info.mSize;
+ }
+
+ memcpy((uint8_t *)data + sizeDone,
+ (const uint8_t *)mBuffers.itemAt(info.mIndex)->pointer()
+ + info.mOffset,
+ copy);
+
+ info.mSize -= copy;
+ info.mOffset += copy;
+ sizeDone += copy;
+
+ if (info.mSize == 0) {
+ mSource->onBufferAvailable(info.mIndex);
+ mFilledBuffers.erase(mFilledBuffers.begin());
+ }
+ }
+
+ mPosition += sizeDone;
+
+ return sizeDone;
+}
+
+void QueueDataSource::queueBuffer(size_t index, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ CHECK_LT(index, mBuffers.size());
+ CHECK_LE(size, mBuffers.itemAt(index)->size());
+
+ BufferInfo info;
+ info.mIndex = index;
+ info.mSize = size;
+ info.mOffset = 0;
+
+ mFilledBuffers.push_back(info);
+ mCondition.signal();
+}
+
+void QueueDataSource::queueCommand(IStreamListener::Command cmd) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (cmd == IStreamListener::EOS) {
+ mEOS = true;
+ mCondition.signal();
+ }
+}
+
+void QueueListener::clearOwner() {
+ Mutex::Autolock autoLock(mLock);
+ mOwner = NULL;
+}
+
+void QueueListener::queueBuffer(size_t index, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+ if (mOwner == NULL) {
+ return;
+ }
+ mOwner->queueBuffer(index, size);
+}
+
+void QueueListener::queueCommand(Command cmd) {
+ Mutex::Autolock autoLock(mLock);
+ if (mOwner == NULL) {
+ return;
+ }
+ mOwner->queueCommand(cmd);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
AwesomePlayer::AwesomePlayer()
: mQueueStarted(false),
mTimeSource(NULL),
@@ -164,7 +362,7 @@ AwesomePlayer::AwesomePlayer()
mExtractorFlags(0),
mVideoBuffer(NULL),
mDecryptHandle(NULL) {
- CHECK_EQ(mClient.connect(), OK);
+ CHECK_EQ(mClient.connect(), (status_t)OK);
DataSource::RegisterDefaultSniffers();
@@ -264,6 +462,26 @@ status_t AwesomePlayer::setDataSource(
return setDataSource_l(dataSource);
}
+status_t AwesomePlayer::setDataSource(const sp<IStreamSource> &source) {
+ Mutex::Autolock autoLock(mLock);
+
+ reset_l();
+
+ sp<DataSource> dataSource = new QueueDataSource(source);
+
+#if 0
+ sp<MediaExtractor> extractor =
+ MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
+
+ return setDataSource_l(extractor);
+#else
+ sp<NuCachedSource2> cached = new NuCachedSource2(dataSource);
+ dataSource = cached;
+
+ return setDataSource_l(dataSource);
+#endif
+}
+
status_t AwesomePlayer::setDataSource_l(
const sp<DataSource> &dataSource) {
sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
@@ -619,7 +837,8 @@ void AwesomePlayer::partial_reset_l() {
IPCThreadState::self()->flushCommands();
}
- CHECK_EQ(OK, initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
+ CHECK_EQ((status_t)OK,
+ initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
}
void AwesomePlayer::onStreamDone() {
@@ -1171,7 +1390,7 @@ void AwesomePlayer::onVideoEvent() {
options.clearSeekTo();
if (err != OK) {
- CHECK_EQ(mVideoBuffer, NULL);
+ CHECK(mVideoBuffer == NULL);
if (err == INFO_FORMAT_CHANGED) {
LOGV("VideoSource signalled format change.");
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index e33f467..46f4a35 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -67,6 +67,8 @@ struct AwesomePlayer {
status_t setDataSource(int fd, int64_t offset, int64_t length);
+ status_t setDataSource(const sp<IStreamSource> &source);
+
void reset();
status_t prepare();
diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml
index 5fa8b3b..fb4cf3f 100644
--- a/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml
+++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml
@@ -20,9 +20,8 @@
android:layout_height="match_parent"
android:layout_width="match_parent"
android:animateLayoutChanges="true"
- android:background="@drawable/bg_scrim_notification"
android:paddingTop="32dp"
- android:paddingBottom="32dp"
+ android:paddingBottom="@dimen/status_bar_panel_bottom_offset"
android:orientation="vertical"
android:gravity="right"
>
@@ -66,6 +65,7 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_below="@id/clock"
+ android:layout_marginTop="4dp"
android:layout_marginRight="48dp"
android:gravity="right"
/>
@@ -76,9 +76,10 @@
android:layout_width="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/date"
- android:layout_marginTop="16dp"
android:layout_marginLeft="48dp"
- android:baseline="17dp"
+ android:layout_marginTop="18dp"
+ android:layout_marginRight="8dp"
+ android:baseline="15dp"
/>
<TextView
@@ -97,7 +98,8 @@
android:layout_width="wrap_content"
android:layout_toRightOf="@id/battery_text"
android:layout_alignBaseline="@id/battery"
- android:baseline="21dp"
+ android:layout_marginRight="8dp"
+ android:baseline="15dp"
/>
<TextView
@@ -114,11 +116,11 @@
android:id="@+id/settings_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
android:layout_alignBaseline="@id/battery"
+ android:layout_alignParentRight="true"
android:paddingRight="16dp"
android:src="@drawable/ic_notification_open"
- android:baseline="17dp"
+ android:baseline="21dp"
/>
<ImageView
@@ -130,7 +132,7 @@
android:paddingRight="16dp"
android:visibility="invisible"
android:src="@drawable/status_bar_veto"
- android:baseline="17dp"
+ android:baseline="21dp"
/>
</com.android.systemui.statusbar.tablet.NotificationTitleArea>
diff --git a/packages/SystemUI/res/values-xlarge/dimens.xml b/packages/SystemUI/res/values-xlarge/dimens.xml
index 009b7a8..5ae3982 100644
--- a/packages/SystemUI/res/values-xlarge/dimens.xml
+++ b/packages/SystemUI/res/values-xlarge/dimens.xml
@@ -22,6 +22,8 @@
<dimen name="notification_large_icon_height">60dp</dimen>
<!-- The width of the ticker, including the icon -->
<dimen name="notification_ticker_width">360dp</dimen>
+ <!-- Status bar panel bottom offset (height of status bar - overlap) -->
+ <dimen name="status_bar_panel_bottom_offset">36dp</dimen>
</resources>
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 2dad81c..915fa2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -294,7 +294,7 @@ public class PhoneStatusBar extends StatusBar {
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
@@ -1254,7 +1254,7 @@ public class PhoneStatusBar extends StatusBar {
lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
@@ -1282,7 +1282,7 @@ public class PhoneStatusBar extends StatusBar {
lp.height = getExpandedHeight();
lp.x = 0;
mTrackingPosition = lp.y = -disph; // sufficiently large negative
- lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+ lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
index 7f743b2..b05fe1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -163,6 +163,7 @@ public class TabletTicker extends Handler {
WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 1c1a46e..f892e9e 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -103,6 +103,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
@@ -148,31 +149,32 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static final int APPLICATION_LAYER = 2;
static final int PHONE_LAYER = 3;
static final int SEARCH_BAR_LAYER = 4;
- static final int STATUS_BAR_PANEL_LAYER = 5;
+ static final int STATUS_BAR_SUB_PANEL_LAYER = 5;
static final int SYSTEM_DIALOG_LAYER = 6;
// toasts and the plugged-in battery thing
static final int TOAST_LAYER = 7;
static final int STATUS_BAR_LAYER = 8;
+ static final int STATUS_BAR_PANEL_LAYER = 9;
// SIM errors and unlock. Not sure if this really should be in a high layer.
- static final int PRIORITY_PHONE_LAYER = 9;
+ static final int PRIORITY_PHONE_LAYER = 10;
// like the ANR / app crashed dialogs
- static final int SYSTEM_ALERT_LAYER = 10;
+ static final int SYSTEM_ALERT_LAYER = 11;
// system-level error dialogs
- static final int SYSTEM_ERROR_LAYER = 11;
+ static final int SYSTEM_ERROR_LAYER = 12;
// on-screen keyboards and other such input method user interfaces go here.
- static final int INPUT_METHOD_LAYER = 12;
+ static final int INPUT_METHOD_LAYER = 13;
// on-screen keyboards and other such input method user interfaces go here.
- static final int INPUT_METHOD_DIALOG_LAYER = 13;
+ static final int INPUT_METHOD_DIALOG_LAYER = 14;
// the keyguard; nothing on top of these can take focus, since they are
// responsible for power management when displayed.
- static final int KEYGUARD_LAYER = 14;
- static final int KEYGUARD_DIALOG_LAYER = 15;
+ static final int KEYGUARD_LAYER = 15;
+ static final int KEYGUARD_DIALOG_LAYER = 16;
// the drag layer: input for drag-and-drop is associated with this window,
// which sits above all other focusable windows
- static final int DRAG_LAYER = 16;
+ static final int DRAG_LAYER = 17;
// things in here CAN NOT take focus, but are shown on top of everything else.
- static final int SYSTEM_OVERLAY_LAYER = 17;
- static final int SECURE_SYSTEM_OVERLAY_LAYER = 18;
+ static final int SYSTEM_OVERLAY_LAYER = 18;
+ static final int SECURE_SYSTEM_OVERLAY_LAYER = 19;
static final int APPLICATION_MEDIA_SUBLAYER = -2;
static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
@@ -239,6 +241,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
int mUserRotation = Surface.ROTATION_0;
+ boolean mAllowAllRotations;
boolean mCarDockEnablesAccelerometer;
boolean mDeskDockEnablesAccelerometer;
int mLidKeyboardAccessibility;
@@ -274,10 +277,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
};
+ // The current size of the screen; really; (ir)regardless of whether the status
+ // bar can be hidden or not
+ int mUnrestrictedScreenLeft, mUnrestrictedScreenTop;
+ int mUnrestrictedScreenWidth, mUnrestrictedScreenHeight;
// The current size of the screen; these may be different than (0,0)-(dw,dh)
// if the status bar can't be hidden; in that case it effectively carves out
// that area of the display from all other windows.
- int mScreenLeft, mScreenTop, mScreenWidth, mScreenHeight;
+ int mRestrictedScreenLeft, mRestrictedScreenTop;
+ int mRestrictedScreenWidth, mRestrictedScreenHeight;
// During layout, the current screen borders with all outer decoration
// (status bar, input method dock) accounted for.
int mCurLeft, mCurTop, mCurRight, mCurBottom;
@@ -650,6 +658,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
com.android.internal.R.integer.config_carDockRotation);
mDeskDockRotation = readRotation(
com.android.internal.R.integer.config_deskDockRotation);
+ mAllowAllRotations = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_allowAllRotations);
mCarDockEnablesAccelerometer = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_carDockEnablesAccelerometer);
mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean(
@@ -906,6 +916,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return STATUS_BAR_LAYER;
case TYPE_STATUS_BAR_PANEL:
return STATUS_BAR_PANEL_LAYER;
+ case TYPE_STATUS_BAR_SUB_PANEL:
+ return STATUS_BAR_SUB_PANEL_LAYER;
case TYPE_SYSTEM_DIALOG:
return SYSTEM_DIALOG_LAYER;
case TYPE_SEARCH_BAR:
@@ -1126,6 +1138,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
"PhoneWindowManager");
mStatusBarPanels.add(win);
break;
+ case TYPE_STATUS_BAR_SUB_PANEL:
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.STATUS_BAR_SERVICE,
+ "PhoneWindowManager");
+ mStatusBarPanels.add(win);
+ break;
case TYPE_KEYGUARD:
if (mKeyguard != null) {
return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
@@ -1401,8 +1419,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
== (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
contentInset.set(mCurLeft, mCurTop,
- (mScreenLeft+mScreenWidth) - mCurRight,
- (mScreenTop+mScreenHeight) - mCurBottom);
+ (mRestrictedScreenLeft+mRestrictedScreenWidth) - mCurRight,
+ (mRestrictedScreenTop+mRestrictedScreenHeight) - mCurBottom);
} else {
contentInset.setEmpty();
}
@@ -1410,9 +1428,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
public void beginLayoutLw(int displayWidth, int displayHeight) {
- mScreenLeft = mScreenTop = 0;
- mScreenWidth = displayWidth;
- mScreenHeight = displayHeight;
+ mUnrestrictedScreenLeft = mUnrestrictedScreenTop = 0;
+ mUnrestrictedScreenWidth = displayWidth;
+ mUnrestrictedScreenHeight = displayHeight;
+ mRestrictedScreenLeft = mRestrictedScreenTop = 0;
+ mRestrictedScreenWidth = displayWidth;
+ mRestrictedScreenHeight = displayHeight;
mDockLeft = mContentLeft = mCurLeft = 0;
mDockTop = mContentTop = mCurTop = 0;
mDockRight = mContentRight = mCurRight = displayWidth;
@@ -1451,16 +1472,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else {
// Status bar can't go away; the part of the screen it
// covers does not exist for anything behind it.
- if (mScreenTop == r.top) {
- mScreenTop = r.bottom;
- mScreenHeight -= (r.bottom-r.top);
- } else if ((mScreenHeight-mScreenTop) == r.bottom) {
- mScreenHeight -= (r.bottom-r.top);
+ if (mRestrictedScreenTop == r.top) {
+ mRestrictedScreenTop = r.bottom;
+ mRestrictedScreenHeight -= (r.bottom-r.top);
+ } else if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) {
+ mRestrictedScreenHeight -= (r.bottom-r.top);
}
- mContentTop = mCurTop = mDockTop = mScreenTop;
- mContentBottom = mCurBottom = mDockBottom = mScreenTop+mScreenHeight;
- if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mScreenTop=" + mScreenTop
- + " mScreenHeight=" + mScreenHeight);
+ mContentTop = mCurTop = mDockTop = mRestrictedScreenTop;
+ mContentBottom = mCurBottom = mDockBottom
+ = mRestrictedScreenTop + mRestrictedScreenHeight;
+ if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mRestrictedScreenTop="
+ + mRestrictedScreenTop
+ + " mRestrictedScreenHeight=" + mRestrictedScreenHeight);
}
}
}
@@ -1552,10 +1575,21 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// frame is the same as the one we are attached to.
setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf);
} else {
- pf.left = df.left = mScreenLeft;
- pf.top = df.top = mScreenTop;
- pf.right = df.right = mScreenLeft+mScreenWidth;
- pf.bottom = df.bottom = mScreenTop+mScreenHeight;
+ if (attrs.type == TYPE_STATUS_BAR_PANEL) {
+ // Status bar panels are the only windows who can go on top of
+ // the status bar. They are protected by the STATUS_BAR_SERVICE
+ // permission, so they have the same privileges as the status
+ // bar itself.
+ pf.left = df.left = mUnrestrictedScreenLeft;
+ pf.top = df.top = mUnrestrictedScreenTop;
+ pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ } else {
+ pf.left = df.left = mRestrictedScreenLeft;
+ pf.top = df.top = mRestrictedScreenTop;
+ pf.right = df.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
+ pf.bottom = df.bottom = mRestrictedScreenTop+mRestrictedScreenHeight;
+ }
if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
cf.left = mDockLeft;
cf.top = mDockTop;
@@ -1579,10 +1613,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
// A window that has requested to fill the entire screen just
// gets everything, period.
- pf.left = df.left = cf.left = mScreenLeft;
- pf.top = df.top = cf.top = mScreenTop;
- pf.right = df.right = cf.right = mScreenLeft+mScreenWidth;
- pf.bottom = df.bottom = cf.bottom = mScreenTop+mScreenHeight;
+ if (attrs.type == TYPE_STATUS_BAR_PANEL) {
+ pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
+ pf.top = df.top = cf.top = mUnrestrictedScreenTop;
+ pf.right = df.right = cf.right
+ = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ pf.bottom = df.bottom = cf.bottom
+ = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ } else {
+ pf.left = df.left = cf.left = mRestrictedScreenLeft;
+ pf.top = df.top = cf.top = mRestrictedScreenTop;
+ pf.right = df.right = cf.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
+ pf.bottom = df.bottom = cf.bottom
+ = mRestrictedScreenTop+mRestrictedScreenHeight;
+ }
if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
vf.left = mCurLeft;
vf.top = mCurTop;
@@ -1841,9 +1885,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
rect.union(w.getShownFrameLw());
}
}
- final int insetw = mScreenWidth/10;
- final int inseth = mScreenHeight/10;
- if (rect.contains(insetw, inseth, mScreenWidth-insetw, mScreenHeight-inseth)) {
+ final int insetw = mRestrictedScreenWidth/10;
+ final int inseth = mRestrictedScreenHeight/10;
+ if (rect.contains(insetw, inseth, mRestrictedScreenWidth-insetw,
+ mRestrictedScreenHeight-inseth)) {
// All of the status bar windows put together cover the
// screen, so the app can't be seen. (Note this test doesn't
// work if the rects of these windows are at off offsets or
@@ -2302,7 +2347,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return getCurrentPortraitRotation(lastRotation);
}
- mOrientationListener.setAllow180Rotation(
+ mOrientationListener.setAllow180Rotation(mAllowAllRotations ||
orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
// case for nosensor meaning ignore sensor and consider only lid
diff --git a/services/java/com/android/server/ScreenRotationAnimation.java b/services/java/com/android/server/ScreenRotationAnimation.java
new file mode 100644
index 0000000..299567a
--- /dev/null
+++ b/services/java/com/android/server/ScreenRotationAnimation.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2010 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.server; // TODO: use com.android.server.wm, once things move there
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+import android.view.Display;
+import android.view.Surface;
+import android.view.SurfaceSession;
+
+class ScreenRotationAnimation {
+ private static final String TAG = "ScreenRotationAnimation";
+
+ Surface mSurface;
+ int mWidth, mHeight;
+
+ int mBaseRotation;
+ int mCurRotation;
+ int mDeltaRotation;
+
+ final Matrix mMatrix = new Matrix();
+ final float[] mTmpFloats = new float[9];
+
+ public ScreenRotationAnimation(Display display, SurfaceSession session) {
+ final DisplayMetrics dm = new DisplayMetrics();
+ display.getMetrics(dm);
+
+ Bitmap screenshot = Surface.screenshot(0, 0);
+
+ if (screenshot != null) {
+ // Screenshot does NOT include rotation!
+ mBaseRotation = 0;
+ mWidth = screenshot.getWidth();
+ mHeight = screenshot.getHeight();
+ } else {
+ // Just in case.
+ mBaseRotation = display.getRotation();
+ mWidth = dm.widthPixels;
+ mHeight = dm.heightPixels;
+ }
+
+ Surface.openTransaction();
+ if (mSurface != null) {
+ mSurface.destroy();
+ mSurface = null;
+ }
+ try {
+ mSurface = new Surface(session, 0, "FreezeSurface",
+ -1, mWidth, mHeight, PixelFormat.OPAQUE, 0);
+ } catch (Surface.OutOfResourcesException e) {
+ Slog.w(TAG, "Unable to allocate freeze surface", e);
+ }
+ mSurface.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER * 200);
+ setRotation(display.getRotation());
+
+ Rect dirty = new Rect(0, 0, mWidth, mHeight);
+ Canvas c = null;
+ try {
+ c = mSurface.lockCanvas(dirty);
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Unable to lock surface", e);
+ return;
+ } catch (Surface.OutOfResourcesException e) {
+ Slog.w(TAG, "Unable to lock surface", e);
+ return;
+ }
+ if (c == null) {
+ Slog.w(TAG, "Null surface");
+ return;
+ }
+
+ if (screenshot != null) {
+ c.drawBitmap(screenshot, 0, 0, new Paint(0));
+ } else {
+ c.drawColor(Color.GREEN);
+ }
+
+ mSurface.unlockCanvasAndPost(c);
+ Surface.closeTransaction();
+
+ screenshot.recycle();
+ }
+
+ // Must be called while in a transaction.
+ public void setRotation(int rotation) {
+ mCurRotation = rotation;
+ int delta = mCurRotation - mBaseRotation;
+ if (delta < 0) delta += 4;
+ mDeltaRotation = delta;
+
+ switch (delta) {
+ case Surface.ROTATION_0:
+ mMatrix.reset();
+ break;
+ case Surface.ROTATION_90:
+ mMatrix.setRotate(90, 0, 0);
+ mMatrix.postTranslate(0, mWidth);
+ break;
+ case Surface.ROTATION_180:
+ mMatrix.setRotate(180, 0, 0);
+ mMatrix.postTranslate(mWidth, mHeight);
+ break;
+ case Surface.ROTATION_270:
+ mMatrix.setRotate(270, 0, 0);
+ mMatrix.postTranslate(mHeight, 0);
+ break;
+ }
+
+ mMatrix.getValues(mTmpFloats);
+ mSurface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
+ (int)mTmpFloats[Matrix.MTRANS_Y]);
+ mSurface.setMatrix(
+ mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_X],
+ mTmpFloats[Matrix.MSKEW_Y], mTmpFloats[Matrix.MSCALE_Y]);
+
+ if (false) {
+ float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
+ float[] dstPnts = new float[8];
+ mMatrix.mapPoints(dstPnts, srcPnts);
+ Slog.i(TAG, "**** ROTATION: " + delta);
+ Slog.i(TAG, "Original : (" + srcPnts[0] + "," + srcPnts[1]
+ + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")");
+ Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1]
+ + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")");
+ }
+ }
+
+ public void dismiss() {
+ mSurface.destroy();
+ }
+}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index b3ea836..5c32c38 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -201,6 +201,12 @@ public class WindowManagerService extends IWindowManager.Stub
*/
static final int DEFAULT_FADE_IN_OUT_DURATION = 400;
+ /**
+ * If true, the window manager will do its own custom freezing and general
+ * management of the screen during rotation.
+ */
+ static final boolean CUSTOM_SCREEN_ROTATION = true;
+
// Maximum number of milliseconds to wait for input event injection.
// FIXME is this value reasonable?
private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
@@ -374,6 +380,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mBlurShown;
Watermark mWatermark;
StrictModeFlash mStrictModeFlash;
+ ScreenRotationAnimation mScreenRotationAnimation;
int mTransactionSequence = 0;
@@ -4998,7 +5005,18 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
mInputManager.setDisplayOrientation(0, rotation);
if (mDisplayEnabled) {
- Surface.setOrientation(0, rotation, animFlags);
+ if (CUSTOM_SCREEN_ROTATION) {
+ Surface.freezeDisplay(0);
+ Surface.openTransaction();
+ if (mScreenRotationAnimation != null) {
+ mScreenRotationAnimation.setRotation(rotation);
+ }
+ Surface.closeTransaction();
+ Surface.setOrientation(0, rotation, animFlags);
+ Surface.unfreezeDisplay(0);
+ } else {
+ Surface.setOrientation(0, rotation, animFlags);
+ }
}
for (int i=mWindows.size()-1; i>=0; i--) {
WindowState w = mWindows.get(i);
@@ -10817,7 +10835,14 @@ public class WindowManagerService extends IWindowManager.Stub
File file = new File("/data/system/frozen");
Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
}
- Surface.freezeDisplay(0);
+
+ if (CUSTOM_SCREEN_ROTATION) {
+ if (mScreenRotationAnimation == null) {
+ mScreenRotationAnimation = new ScreenRotationAnimation(mDisplay, mFxSession);
+ }
+ } else {
+ Surface.freezeDisplay(0);
+ }
}
private void stopFreezingDisplayLocked() {
@@ -10834,7 +10859,15 @@ public class WindowManagerService extends IWindowManager.Stub
if (PROFILE_ORIENTATION) {
Debug.stopMethodTracing();
}
- Surface.unfreezeDisplay(0);
+
+ if (CUSTOM_SCREEN_ROTATION) {
+ if (mScreenRotationAnimation != null) {
+ mScreenRotationAnimation.dismiss();
+ mScreenRotationAnimation = null;
+ }
+ } else {
+ Surface.unfreezeDisplay(0);
+ }
mInputMonitor.thawInputDispatchingLw();