diff options
Diffstat (limited to 'services')
5 files changed, 269 insertions, 45 deletions
diff --git a/services/audioflinger/A2dpAudioInterface.cpp b/services/audioflinger/A2dpAudioInterface.cpp index 995e31c..aee01ab 100644 --- a/services/audioflinger/A2dpAudioInterface.cpp +++ b/services/audioflinger/A2dpAudioInterface.cpp @@ -23,10 +23,13 @@ #include "A2dpAudioInterface.h" #include "audio/liba2dp.h" - +#include <hardware_legacy/power.h> namespace android { +static const char *sA2dpWakeLock = "A2dpOutputStream"; +#define MAX_WRITE_RETRIES 5 + // ---------------------------------------------------------------------------- //AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface() @@ -263,44 +266,55 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::set( A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut() { LOGV("A2dpAudioStreamOut destructor"); - standby(); close(); LOGV("A2dpAudioStreamOut destructor returning from close()"); } ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes) { - Mutex::Autolock lock(mLock); - - size_t remaining = bytes; status_t status = -1; + { + Mutex::Autolock lock(mLock); - if (!mBluetoothEnabled || mClosing || mSuspended) { - LOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \ - mBluetoothEnabled %d, mClosing %d, mSuspended %d", - mBluetoothEnabled, mClosing, mSuspended); - goto Error; - } - - status = init(); - if (status < 0) - goto Error; + size_t remaining = bytes; - while (remaining > 0) { - status = a2dp_write(mData, buffer, remaining); - if (status <= 0) { - LOGE("a2dp_write failed err: %d\n", status); + if (!mBluetoothEnabled || mClosing || mSuspended) { + LOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \ + mBluetoothEnabled %d, mClosing %d, mSuspended %d", + mBluetoothEnabled, mClosing, mSuspended); goto Error; } - remaining -= status; - buffer = ((char *)buffer) + status; - } - mStandby = false; + if (mStandby) { + acquire_wake_lock (PARTIAL_WAKE_LOCK, sA2dpWakeLock); + mStandby = false; + } + + status = init(); + if (status < 0) + goto Error; + + int retries = MAX_WRITE_RETRIES; + while (remaining > 0 && retries) { + status = a2dp_write(mData, buffer, remaining); + if (status < 0) { + LOGE("a2dp_write failed err: %d\n", status); + goto Error; + } + if (status == 0) { + retries--; + } + remaining -= status; + buffer = (char *)buffer + status; + } - return bytes; + return bytes; + } Error: + + standby(); + // Simulate audio output timing in case of error usleep(((bytes * 1000 )/ frameSize() / sampleRate()) * 1000); @@ -324,19 +338,22 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::init() status_t A2dpAudioInterface::A2dpAudioStreamOut::standby() { - int result = 0; - - if (mClosing) { - LOGV("Ignore standby, closing"); - return result; - } - Mutex::Autolock lock(mLock); + return standby_l(); +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::standby_l() +{ + int result = NO_ERROR; if (!mStandby) { - result = a2dp_stop(mData); - if (result == 0) - mStandby = true; + LOGV_IF(mClosing || !mBluetoothEnabled, "Standby skip stop: closing %d enabled %d", + mClosing, mBluetoothEnabled); + if (!mClosing && mBluetoothEnabled) { + result = a2dp_stop(mData); + } + release_wake_lock(sA2dpWakeLock); + mStandby = true; } return result; @@ -362,6 +379,9 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& ke key = String8("closing"); if (param.get(key, value) == NO_ERROR) { mClosing = (value == "true"); + if (mClosing) { + standby(); + } param.remove(key); } key = AudioParameter::keyRouting; @@ -444,6 +464,7 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::close() status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l() { + standby_l(); if (mData) { LOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)"); a2dp_cleanup(mData); diff --git a/services/audioflinger/A2dpAudioInterface.h b/services/audioflinger/A2dpAudioInterface.h index 48154f9..cef1926 100644 --- a/services/audioflinger/A2dpAudioInterface.h +++ b/services/audioflinger/A2dpAudioInterface.h @@ -103,6 +103,7 @@ private: status_t setAddress(const char* address); status_t setBluetoothEnabled(bool enabled); status_t setSuspended(bool onOff); + status_t standby_l(); private: int mFd; diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index eca37b7..723432d 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -1300,7 +1300,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } public void setInputMethod(IBinder token, String id) { - setInputMethodWithSubtype(token, id, NOT_A_SUBTYPE_ID); + setInputMethodWithSubtypeId(token, id, NOT_A_SUBTYPE_ID); + } + + public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) { + synchronized (mMethodMap) { + if (subtype != null) { + setInputMethodWithSubtypeId(token, id, getSubtypeIdFromHashCode( + mMethodMap.get(id), subtype.hashCode())); + } else { + setInputMethod(token, id); + } + } } public boolean switchToLastInputMethod(IBinder token) { @@ -1309,7 +1320,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (lastIme != null) { InputMethodInfo imi = mMethodMap.get(lastIme.first); if (imi != null) { - setInputMethodWithSubtype(token, lastIme.first, getSubtypeIdFromHashCode( + setInputMethodWithSubtypeId(token, lastIme.first, getSubtypeIdFromHashCode( imi, Integer.valueOf(lastIme.second))); return true; } @@ -1318,7 +1329,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - private void setInputMethodWithSubtype(IBinder token, String id, int subtypeId) { + private void setInputMethodWithSubtypeId(IBinder token, String id, int subtypeId) { synchronized (mMethodMap) { if (token == null) { if (mContext.checkCallingOrSelfPermission( @@ -1909,11 +1920,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } private int getSubtypeIdFromHashCode(InputMethodInfo imi, int subtypeHashCode) { - ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes(); - for (int i = 0; i < subtypes.size(); ++i) { - InputMethodSubtype ims = subtypes.get(i); - if (subtypeHashCode == ims.hashCode()) { - return i; + if (imi != null) { + ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes(); + for (int i = 0; i < subtypes.size(); ++i) { + InputMethodSubtype ims = subtypes.get(i); + if (subtypeHashCode == ims.hashCode()) { + return i; + } } } return NOT_A_SUBTYPE_ID; 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..89512ae 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; @@ -4911,6 +4918,10 @@ public class WindowManagerService extends IWindowManager.Stub } } + public void setStrictModeVisualIndicatorPreference(String value) { + SystemProperties.set(StrictMode.VISUAL_PROPERTY, value); + } + public void freezeRotation() { if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, "setRotation()")) { @@ -4998,7 +5009,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 +10839,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 +10863,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(); |