diff options
42 files changed, 1840 insertions, 540 deletions
diff --git a/build/phone-hdpi-512-dalvik-heap.mk b/build/phone-hdpi-512-dalvik-heap.mk index 788b68609604..16e05055e030 100644 --- a/build/phone-hdpi-512-dalvik-heap.mk +++ b/build/phone-hdpi-512-dalvik-heap.mk @@ -19,5 +19,5 @@ PRODUCT_PROPERTY_OVERRIDES += \ dalvik.vm.heapstartsize=5m \ - dalvik.vm.heapgrowthlimit=32m \ + dalvik.vm.heapgrowthlimit=48m \ dalvik.vm.heapsize=128m diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl index 2b9c082d5696..9bab797b4c54 100644 --- a/core/java/android/hardware/usb/IUsbManager.aidl +++ b/core/java/android/hardware/usb/IUsbManager.aidl @@ -82,11 +82,8 @@ interface IUsbManager /* Clears default preferences and permissions for the package */ void clearDefaults(String packageName); - /* Sets the current primary USB function. */ - void setPrimaryFunction(String functions); - - /* Sets the default primary USB function. */ - void setDefaultFunction(String functions); + /* Sets the current USB function. */ + void setCurrentFunction(String function, boolean makeDefault); /* Sets the file path for USB mass storage backing file. */ void setMassStorageBackingFile(String path); diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index a828a23b2f44..67d200cd40ff 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -408,32 +408,18 @@ public class UsbManager { } /** - * Sets the primary USB function. + * Sets the current USB function. * * @param function name of the USB function + * @param makeDefault true if this should be set as the default * * {@hide} */ - public void setPrimaryFunction(String function) { + public void setCurrentFunction(String function, boolean makeDefault) { try { - mService.setPrimaryFunction(function); + mService.setCurrentFunction(function, makeDefault); } catch (RemoteException e) { - Log.e(TAG, "RemoteException in setPrimaryFunction", e); - } - } - - /** - * Sets the default primary USB function. - * - * @param function name of the USB function - * - * {@hide} - */ - public void setDefaultFunction(String function) { - try { - mService.setDefaultFunction(function); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException in setDefaultFunction", e); + Log.e(TAG, "RemoteException in setCurrentFunction", e); } } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2242e9e8e178..ce6f697be6be 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -164,6 +164,12 @@ public class ConnectivityManager { public static final String EXTRA_ERRORED_TETHER = "erroredArray"; /** + * The absence of APN.. + * @hide + */ + public static final int TYPE_NONE = -1; + + /** * The Default Mobile data connection. When active, all data traffic * will use this connection by default. */ diff --git a/core/java/android/server/BluetoothBondState.java b/core/java/android/server/BluetoothBondState.java index 39c3c8854533..5fa8836c1d9c 100644 --- a/core/java/android/server/BluetoothBondState.java +++ b/core/java/android/server/BluetoothBondState.java @@ -79,7 +79,6 @@ class BluetoothBondState { mService = service; mBluetoothInputProfileHandler = BluetoothInputProfileHandler.getInstance(mContext, mService); - getProfileProxy(); } synchronized void setPendingOutgoingBonding(String address) { @@ -109,6 +108,7 @@ class BluetoothBondState { mState.put(mService.getAddressFromObjectPath(device).toUpperCase(), BluetoothDevice.BOND_BONDED); } + getProfileProxy(); } public synchronized void setBondState(String address, int state) { diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 042120587dea..2f598f46b756 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -96,12 +96,9 @@ public class TextureView extends View { private SurfaceTexture mSurface; private SurfaceTextureListener mListener; - private final Runnable mUpdateLayerAction = new Runnable() { - @Override - public void run() { - updateLayer(); - } - }; + private final Object[] mLock = new Object[0]; + private boolean mUpdateLayer; + private SurfaceTexture.OnFrameAvailableListener mUpdateListener; /** @@ -232,6 +229,8 @@ public class TextureView extends View { protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (mSurface != null) { + // No need to synchronize here, we set update layer to false only on the UI thread + mUpdateLayer = true; nSetDefaultBufferSize(mSurface, getWidth(), getHeight()); if (mListener != null) { mListener.onSurfaceTextureSizeChanged(mSurface, getWidth(), getHeight()); @@ -255,7 +254,10 @@ public class TextureView extends View { public void onFrameAvailable(SurfaceTexture surfaceTexture) { // Per SurfaceTexture's documentation, the callback may be invoked // from an arbitrary thread - post(mUpdateLayerAction); + synchronized (mLock) { + mUpdateLayer = true; + postInvalidate(); + } } }; mSurface.setOnFrameAvailableListener(mUpdateListener); @@ -265,6 +267,13 @@ public class TextureView extends View { } } + synchronized (mLock) { + if (mUpdateLayer) { + mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight()); + mUpdateLayer = false; + } + } + return mLayer; } @@ -278,23 +287,15 @@ public class TextureView extends View { // updates listener if (visibility == VISIBLE) { mSurface.setOnFrameAvailableListener(mUpdateListener); - updateLayer(); + // No need to synchronize here, we set update layer to false only on the UI thread + mUpdateLayer = true; + invalidate(); } else { mSurface.setOnFrameAvailableListener(null); } } } - private void updateLayer() { - if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) { - return; - } - - mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight()); - - invalidate(); - } - /** * <p>Returns a {@link android.graphics.Bitmap} representation of the content * of the associated surface texture. If the surface texture is not available, diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java index ca11c70b21c7..ad660c1e209d 100644 --- a/core/java/android/view/ViewAncestor.java +++ b/core/java/android/view/ViewAncestor.java @@ -1005,8 +1005,7 @@ public final class ViewAncestor extends Handler implements ViewParent, + "x" + desiredWindowHeight + "..."); boolean goodMeasure = false; - if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT - || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { + if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) { // On large screens, we don't want to allow dialogs to just // stretch to fill the entire width of the screen to display // one line of text. First try doing the layout at a smaller diff --git a/core/java/android/webkit/JniUtil.java b/core/java/android/webkit/JniUtil.java index b5d493368844..bb4d192516b9 100644 --- a/core/java/android/webkit/JniUtil.java +++ b/core/java/android/webkit/JniUtil.java @@ -23,6 +23,10 @@ import android.util.Log; import java.io.InputStream; class JniUtil { + + static { + System.loadLibrary("webcore"); + } private static final String LOGTAG = "webkit"; private JniUtil() {} // Utility class, do not instantiate. diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index 0e528693ec79..e88d257910ae 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -535,7 +535,7 @@ public class GridLayout extends ViewGroup { return result; } - private int getDefaultMargin(View c, boolean leading, boolean horizontal) { + private int getDefaultMargin(View c, boolean horizontal, boolean leading) { // In the absence of any other information, calculate a default gap such // that, in a grid of identical components, the heights and the vertical // gaps are in the proportion of the golden ratio. @@ -544,12 +544,12 @@ public class GridLayout extends ViewGroup { return (int) (c.getMeasuredHeight() / GOLDEN_RATIO / 2); } - private int getDefaultMargin(View c, boolean isAtEdge, boolean leading, boolean horizontal) { + private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) { // todo remove DEFAULT_CONTAINER_MARGIN. Use padding? Seek advice on Themes/Styles, etc. - return isAtEdge ? DEFAULT_CONTAINER_MARGIN : getDefaultMargin(c, leading, horizontal); + return isAtEdge ? DEFAULT_CONTAINER_MARGIN : getDefaultMargin(c, horizontal, leading); } - private int getDefaultMarginValue(View c, LayoutParams p, boolean leading, boolean horizontal) { + private int getDefaultMarginValue(View c, LayoutParams p, boolean horizontal, boolean leading) { if (!mUseDefaultMargins) { return 0; } @@ -558,15 +558,19 @@ public class GridLayout extends ViewGroup { Interval span = group.span; boolean isAtEdge = leading ? (span.min == 0) : (span.max == axis.getCount()); - return getDefaultMargin(c, isAtEdge, leading, horizontal); + return getDefaultMargin(c, isAtEdge, horizontal, leading); } - private int getMargin(View view, boolean leading, boolean horizontal) { + private int getMargin(View view, boolean horizontal, boolean leading) { LayoutParams lp = getLayoutParams(view); int margin = horizontal ? (leading ? lp.leftMargin : lp.rightMargin) : (leading ? lp.topMargin : lp.bottomMargin); - return margin == UNDEFINED ? getDefaultMarginValue(view, lp, leading, horizontal) : margin; + return margin == UNDEFINED ? getDefaultMarginValue(view, lp, horizontal, leading) : margin; + } + + private int getTotalMargin(View child, boolean horizontal) { + return getMargin(child, horizontal, true) + getMargin(child, horizontal, false); } private static int valueIfDefined(int value, int defaultValue) { @@ -749,8 +753,8 @@ public class GridLayout extends ViewGroup { View c = getChildAt(i); drawRectangle(canvas, c.getLeft() - getMargin(c, true, true), - c.getTop() - getMargin(c, true, false), - c.getRight() + getMargin(c, false, true), + c.getTop() - getMargin(c, false, true), + c.getRight() + getMargin(c, true, false), c.getBottom() + getMargin(c, false, false), paint); } } @@ -794,17 +798,12 @@ public class GridLayout extends ViewGroup { return c.getVisibility() == View.GONE; } - private void measureChildWithMargins(View child, - int parentWidthMeasureSpec, int parentHeightMeasureSpec) { - + private void measureChildWithMargins(View child, int widthMeasureSpec, int heightMeasureSpec) { LayoutParams lp = getLayoutParams(child); - int hMargins = getMargin(child, true, true) + getMargin(child, false, true); - int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, - mPaddingLeft + mPaddingRight + hMargins, lp.width); - int vMargins = getMargin(child, true, false) + getMargin(child, false, false); - int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, - mPaddingTop + mPaddingBottom + vMargins, lp.height); - + int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, + mPaddingLeft + mPaddingRight + getTotalMargin(child, true), lp.width); + int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, + mPaddingTop + mPaddingBottom + getTotalMargin(child, false), lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } @@ -842,9 +841,7 @@ public class GridLayout extends ViewGroup { private int getMeasurementIncludingMargin(View c, boolean horizontal, int measurementType) { int result = getMeasurement(c, horizontal, measurementType); if (mAlignmentMode == ALIGN_MARGINS) { - int leadingMargin = getMargin(c, true, horizontal); - int trailingMargin = getMargin(c, false, horizontal); - return result + leadingMargin + trailingMargin; + return result + getTotalMargin(c, horizontal); } return result; } @@ -919,8 +916,8 @@ public class GridLayout extends ViewGroup { if (mAlignmentMode == ALIGN_MARGINS) { int leftMargin = getMargin(c, true, true); - int topMargin = getMargin(c, true, false); - int rightMargin = getMargin(c, false, true); + int topMargin = getMargin(c, false, true); + int rightMargin = getMargin(c, true, false); int bottomMargin = getMargin(c, false, false); // Same calculation as getMeasurementIncludingMargin() @@ -1387,7 +1384,7 @@ public class GridLayout extends ViewGroup { Group g = horizontal ? lp.columnGroup : lp.rowGroup; Interval span = g.span; int index = leading ? span.min : span.max; - margins[index] = max(margins[index], getMargin(c, leading, horizontal)); + margins[index] = max(margins[index], getMargin(c, horizontal, leading)); } } @@ -1817,7 +1814,8 @@ public class GridLayout extends ViewGroup { } private int getDefaultWeight(int size) { - return (size == MATCH_PARENT) ? DEFAULT_WEIGHT_1 : DEFAULT_WEIGHT_0; + //return (size == MATCH_PARENT) ? DEFAULT_WEIGHT_1 : DEFAULT_WEIGHT_0; + return DEFAULT_WEIGHT_0; } private void init(Context context, AttributeSet attrs, int defaultGravity) { diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index cbb110a09120..0c0205ca5837 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -464,8 +464,7 @@ public class LockPatternView extends View { break; case MeasureSpec.EXACTLY: default: - // use the specified size, if non-zero - result = specSize != 0 ? specSize : desired; + result = specSize; } return result; } diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index e301e44c04bf..16992997cbf5 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -649,7 +649,9 @@ static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject cl float transform[16]; sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface)); - surfaceTexture->updateTexImage(); + while (surfaceTexture->getQueuedCount() > 0) { + surfaceTexture->updateTexImage(); + } surfaceTexture->getTransformMatrix(transform); GLenum renderTarget = surfaceTexture->getCurrentTextureTarget(); diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml index dd68d82f6269..03c6022eae78 100644 --- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml +++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml @@ -101,6 +101,10 @@ android:visibility="gone" /> + <!-- We need MATCH_PARENT here only to force the size of the parent to be passed to + the pattern view for it to compute its size. This is an unusual case, caused by + LockPatternView's requirement to maintain a square aspect ratio based on the width + of the screen. --> <com.android.internal.widget.LockPatternView android:id="@+id/lockPattern" android:layout_width="match_parent" @@ -109,6 +113,8 @@ android:layout_marginRight="8dip" android:layout_marginBottom="4dip" android:layout_marginLeft="8dip" + android:layout_gravity="center|bottom" + android:layout_rowWeight="1" /> <TextView @@ -123,8 +129,7 @@ <!-- Footer: an emergency call button and an initially hidden "Forgot pattern" button --> <LinearLayout android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_gravity="center"> + android:layout_gravity="fill_horizontal"> <Button android:id="@+id/emergencyCallButton" android:layout_width="wrap_content" diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 52b00c6af8eb..a8b7b75c7fa8 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -98,7 +98,7 @@ <!-- This string array should be overridden by the device to present a list of network attributes. This is used by the connectivity manager to decide which networks can coexist based on the hardware --> - <!-- An Array of "[Connection name],[ConnectivityManager connection type], + <!-- An Array of "[Connection name],[ConnectivityManager.TYPE_xxxx], [associated radio-type],[priority],[restoral-timer(ms)],[dependencyMet] --> <!-- the 5th element "resore-time" indicates the number of milliseconds to delay before automatically restore the default connection. Set -1 if the connection @@ -154,20 +154,16 @@ <string-array translatable="false" name="config_tether_dhcp_range"> </string-array> - <!-- Regex array of allowable upstream ifaces for tethering - for example if you want - tethering on a new interface called "foo2" add <item>"foo\\d"</item> to the array --> - <!-- Interfaces will be prioritized according to the order listed --> - <string-array translatable="false" name="config_tether_upstream_regexs"> - </string-array> - <!-- Regex of wired ethernet ifaces --> <string translatable="false" name="config_ethernet_iface_regex">eth\\d</string> - <!-- Boolean indicating if we require the use of DUN on mobile for tethering. - Note that this defaults to false so that if you move to a carrier that - hasn't configured anything tethering will still work. If you'd rather - make the device untetherable on unconfigured devices, set to true --> - <bool translatable="false" name="config_tether_dun_required">false</bool> + <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering --> + <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or + <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH --> + <integer-array translatable="false" name="config_tether_upstream_types"> + <item>1</item> + <item>4</item> + </integer-array> <!-- String containing the apn value for tethering. May be overriden by secure settings TETHER_DUN_APN. Value is a comma separated series of strings: diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index deade5ec5238..99b72ad86415 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -118,6 +118,9 @@ enum { // The language code for this media kKeyMediaLanguage = 'lang', // cstring + + // To store the timed text format data + kKeyTextFormatData = 'text', // raw data }; enum { diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index afab26a94fec..e43f6e55fb23 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -101,8 +101,14 @@ void DisplayList::clearResources() { } mBitmapResources.clear(); + for (size_t i = 0; i < mFilterResources.size(); i++) { + caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i)); + } + mFilterResources.clear(); + for (size_t i = 0; i < mShaders.size(); i++) { caches.resourceCache.decrementRefcount(mShaders.itemAt(i)); + caches.resourceCache.destructor(mShaders.itemAt(i)); } mShaders.clear(); @@ -151,11 +157,18 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde caches.resourceCache.incrementRefcount(resource); } + const Vector<SkiaColorFilter*> &filterResources = recorder.getFilterResources(); + for (size_t i = 0; i < filterResources.size(); i++) { + SkiaColorFilter* resource = filterResources.itemAt(i); + mFilterResources.add(resource); + caches.resourceCache.incrementRefcount(resource); + } + const Vector<SkiaShader*> &shaders = recorder.getShaders(); for (size_t i = 0; i < shaders.size(); i++) { - SkiaShader* shader = shaders.itemAt(i); - mShaders.add(shader); - caches.resourceCache.incrementRefcount(shader); + SkiaShader* resource = shaders.itemAt(i); + mShaders.add(resource); + caches.resourceCache.incrementRefcount(resource); } const Vector<SkPaint*> &paints = recorder.getPaints(); @@ -873,21 +886,27 @@ void DisplayListRenderer::reset() { Caches& caches = Caches::getInstance(); for (size_t i = 0; i < mBitmapResources.size(); i++) { - SkBitmap* resource = mBitmapResources.itemAt(i); - caches.resourceCache.decrementRefcount(resource); + caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i)); } mBitmapResources.clear(); + for (size_t i = 0; i < mFilterResources.size(); i++) { + caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i)); + } + mFilterResources.clear(); + for (size_t i = 0; i < mShaders.size(); i++) { - caches.resourceCache.decrementRefcount(mShaders.itemAt(i)); + caches.resourceCache.decrementRefcount(mShaders.itemAt(i)); } mShaders.clear(); mShaderMap.clear(); mPaints.clear(); mPaintMap.clear(); + mPaths.clear(); mPathMap.clear(); + mMatrices.clear(); } diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index dcf2cf2ddb39..b83259f82450 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -292,6 +292,10 @@ public: return mBitmapResources; } + const Vector<SkiaColorFilter*>& getFilterResources() const { + return mFilterResources; + } + const Vector<SkiaShader*>& getShaders() const { return mShaders; } @@ -308,10 +312,6 @@ public: return mMatrices; } - const Vector<SkiaColorFilter*>& getFilterResources() const { - return mFilterResources; - } - private: void insertRestoreToCount() { if (mRestoreSaveCount >= 0) { @@ -419,7 +419,9 @@ private: inline void addMatrix(SkMatrix* matrix) { // Copying the matrix is cheap and prevents against the user changing the original // matrix before the operation that uses it - addInt((int) new SkMatrix(*matrix)); + SkMatrix* copy = new SkMatrix(*matrix); + addInt((int) copy); + mMatrices.add(copy); } inline void addBitmap(SkBitmap* bitmap) { @@ -429,8 +431,7 @@ private: // which doesn't seem worth the extra cycles for this unlikely case. addInt((int) bitmap); mBitmapResources.add(bitmap); - Caches& caches = Caches::getInstance(); - caches.resourceCache.incrementRefcount(bitmap); + Caches::getInstance().resourceCache.incrementRefcount(bitmap); } inline void addShader(SkiaShader* shader) { @@ -454,8 +455,7 @@ private: inline void addColorFilter(SkiaColorFilter* colorFilter) { addInt((int) colorFilter); mFilterResources.add(colorFilter); - Caches& caches = Caches::getInstance(); - caches.resourceCache.incrementRefcount(colorFilter); + Caches::getInstance().resourceCache.incrementRefcount(colorFilter); } Vector<SkBitmap*> mBitmapResources; diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp index 9aade5175c56..cd2c40506869 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -48,9 +48,6 @@ ResourceCache::~ResourceCache() { void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) { Mutex::Autolock _l(mLock); - for (size_t i = 0; i < mCache->size(); ++i) { - void* ref = mCache->valueAt(i); - } ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; if (ref == NULL || mCache->size() == 0) { ref = new ResourceReference(resourceType); @@ -144,7 +141,6 @@ void ResourceCache::destructor(SkPath* resource) { ref->destroyed = true; if (ref->refCount == 0) { deleteResourceReference(resource, ref); - return; } } @@ -162,7 +158,6 @@ void ResourceCache::destructor(SkBitmap* resource) { ref->destroyed = true; if (ref->refCount == 0) { deleteResourceReference(resource, ref); - return; } } @@ -180,7 +175,6 @@ void ResourceCache::destructor(SkiaShader* resource) { ref->destroyed = true; if (ref->refCount == 0) { deleteResourceReference(resource, ref); - return; } } @@ -195,7 +189,6 @@ void ResourceCache::destructor(SkiaColorFilter* resource) { ref->destroyed = true; if (ref->refCount == 0) { deleteResourceReference(resource, ref); - return; } } @@ -209,36 +202,32 @@ void ResourceCache::deleteResourceReference(void* resource, ResourceReference* r } if (ref->destroyed) { switch (ref->resourceType) { - case kBitmap: - { - SkBitmap* bitmap = (SkBitmap*)resource; + case kBitmap: { + SkBitmap* bitmap = (SkBitmap*) resource; if (Caches::hasInstance()) { Caches::getInstance().textureCache.removeDeferred(bitmap); } delete bitmap; } break; - case kPath: - { - SkPath* path = (SkPath*)resource; + case kPath: { + SkPath* path = (SkPath*) resource; if (Caches::hasInstance()) { Caches::getInstance().pathCache.removeDeferred(path); } delete path; } break; - case kShader: - { - SkiaShader* shader = (SkiaShader*)resource; + case kShader: { + SkiaShader* shader = (SkiaShader*) resource; if (Caches::hasInstance()) { Caches::getInstance().gradientCache.removeDeferred(shader->getSkShader()); } delete shader; } break; - case kColorFilter: - { - SkiaColorFilter* filter = (SkiaColorFilter*)resource; + case kColorFilter: { + SkiaColorFilter* filter = (SkiaColorFilter*) resource; delete filter; } break; diff --git a/libs/hwui/SkiaColorFilter.h b/libs/hwui/SkiaColorFilter.h index bf45e13bc0f2..1bf475c2268e 100644 --- a/libs/hwui/SkiaColorFilter.h +++ b/libs/hwui/SkiaColorFilter.h @@ -59,7 +59,7 @@ struct SkiaColorFilter { return mType; } - SkColorFilter *getSkColorFilter() { + SkColorFilter* getSkColorFilter() { return mSkFilter; } diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 255773067919..33312d195656 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1568,7 +1568,14 @@ public class MediaPlayer return; case MEDIA_TIMED_TEXT: if (mOnTimedTextListener != null) { - mOnTimedTextListener.onTimedText(mMediaPlayer, (String)msg.obj); + if (msg.obj == null) { + mOnTimedTextListener.onTimedText(mMediaPlayer, null); + } else { + if (msg.obj instanceof byte[]) { + TimedText text = new TimedText((byte[])(msg.obj)); + mOnTimedTextListener.onTimedText(mMediaPlayer, text); + } + } } return; @@ -1755,14 +1762,14 @@ public class MediaPlayer public interface OnTimedTextListener { /** - * Called to indicate the video size + * Called to indicate an avaliable timed text * * @param mp the MediaPlayer associated with this callback - * @param text the timed text sample which contains the - * text needed to be displayed. + * @param text the timed text sample which contains the text + * needed to be displayed and the display format. * {@hide} */ - public void onTimedText(MediaPlayer mp, String text); + public void onTimedText(MediaPlayer mp, TimedText text); } /** diff --git a/media/java/android/media/TimedText.java b/media/java/android/media/TimedText.java new file mode 100644 index 000000000000..a055c8bac874 --- /dev/null +++ b/media/java/android/media/TimedText.java @@ -0,0 +1,655 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.os.Parcel; +import android.util.Log; +import java.util.HashMap; +import java.util.Set; +import java.util.List; +import java.util.ArrayList; + +/** + * Class to hold the timed text's metadata. + * + * {@hide} + */ +public class TimedText +{ + private static final int FIRST_PUBLIC_KEY = 1; + + // These keys must be in sync with the keys in TextDescription.h + public static final int KEY_DISPLAY_FLAGS = 1; // int + public static final int KEY_STYLE_FLAGS = 2; // int + public static final int KEY_BACKGROUND_COLOR_RGBA = 3; // int + public static final int KEY_HIGHLIGHT_COLOR_RGBA = 4; // int + public static final int KEY_SCROLL_DELAY = 5; // int + public static final int KEY_WRAP_TEXT = 6; // int + public static final int KEY_START_TIME = 7; // int + public static final int KEY_STRUCT_BLINKING_TEXT_LIST = 8; // List<CharPos> + public static final int KEY_STRUCT_FONT_LIST = 9; // List<Font> + public static final int KEY_STRUCT_HIGHLIGHT_LIST = 10; // List<CharPos> + public static final int KEY_STRUCT_HYPER_TEXT_LIST = 11; // List<HyperText> + public static final int KEY_STRUCT_KARAOKE_LIST = 12; // List<Karaoke> + public static final int KEY_STRUCT_STYLE_LIST = 13; // List<Style> + public static final int KEY_STRUCT_TEXT_POS = 14; // TextPos + public static final int KEY_STRUCT_JUSTIFICATION = 15; // Justification + public static final int KEY_STRUCT_TEXT = 16; // Text + + private static final int LAST_PUBLIC_KEY = 16; + + private static final int FIRST_PRIVATE_KEY = 101; + + // The following keys are used between TimedText.java and + // TextDescription.cpp in order to parce the Parcel. + private static final int KEY_GLOBAL_SETTING = 101; + private static final int KEY_LOCAL_SETTING = 102; + private static final int KEY_START_CHAR = 103; + private static final int KEY_END_CHAR = 104; + private static final int KEY_FONT_ID = 105; + private static final int KEY_FONT_SIZE = 106; + private static final int KEY_TEXT_COLOR_RGBA = 107; + + private static final int LAST_PRIVATE_KEY = 107; + + private static final String TAG = "TimedText"; + + private Parcel mParcel = Parcel.obtain(); + private final HashMap<Integer, Object> mKeyObjectMap = + new HashMap<Integer, Object>(); + + private int mDisplayFlags = -1; + private int mBackgroundColorRGBA = -1; + private int mHighlightColorRGBA = -1; + private int mScrollDelay = -1; + private int mWrapText = -1; + + private List<CharPos> mBlinkingPosList = null; + private List<CharPos> mHighlightPosList = null; + private List<Karaoke> mKaraokeList = null; + private List<Font> mFontList = null; + private List<Style> mStyleList = null; + private List<HyperText> mHyperTextList = null; + + private TextPos mTextPos; + private Justification mJustification; + private Text mTextStruct; + + /** + * Helper class to hold the text length and text content of + * one text sample. The member variables in this class are + * read-only. + */ + public class Text { + /** + * The byte-count of this text sample + */ + public int textLen; + + /** + * The text sample + */ + public byte[] text; + + public Text() { } + } + + /** + * Helper class to hold the start char offset and end char offset + * for Blinking Text or Highlight Text. endChar is the end offset + * of the text (startChar + number of characters to be highlighted + * or blinked). The member variables in this class are read-only. + */ + public class CharPos { + /** + * The offset of the start character + */ + public int startChar = -1; + + /** + * The offset of the end character + */ + public int endChar = -1; + + public CharPos() { } + } + + /** + * Helper class to hold the box position to display the text sample. + * The member variables in this class are read-only. + */ + public class TextPos { + /** + * The top position of the text + */ + public int top = -1; + + /** + * The left position of the text + */ + public int left = -1; + + /** + * The bottom position of the text + */ + public int bottom = -1; + + /** + * The right position of the text + */ + public int right = -1; + + public TextPos() { } + } + + /** + * Helper class to hold the justification for text display in the text box. + * The member variables in this class are read-only. + */ + public class Justification { + /** + * horizontalJustification 0: left, 1: centered, -1: right + */ + public int horizontalJustification = -1; + + /** + * verticalJustification 0: top, 1: centered, -1: bottom + */ + public int verticalJustification = -1; + + public Justification() { } + } + + /** + * Helper class to hold the style information to display the text. + * The member variables in this class are read-only. + */ + public class Style { + /** + * The offset of the start character which applys this style + */ + public int startChar = -1; + + /** + * The offset of the end character which applys this style + */ + public int endChar = -1; + + /** + * ID of the font. This ID will be used to choose the font + * to be used from the font list. + */ + public int fontID = -1; + + /** + * True if the characters should be bold + */ + public boolean isBold = false; + + /** + * True if the characters should be italic + */ + public boolean isItalic = false; + + /** + * True if the characters should be underlined + */ + public boolean isUnderlined = false; + + /** + * The size of the font + */ + public int fontSize = -1; + + /** + * To specify the RGBA color: 8 bits each of red, green, blue, + * and an alpha(transparency) value + */ + public int colorRGBA = -1; + + public Style() { } + } + + /** + * Helper class to hold the font ID and name. + * The member variables in this class are read-only. + */ + public class Font { + /** + * The font ID + */ + public int ID = -1; + + /** + * The font name + */ + public String name; + + public Font() { } + } + + /** + * Helper class to hold the karaoke information. + * The member variables in this class are read-only. + */ + public class Karaoke { + /** + * The start time (in milliseconds) to highlight the characters + * specified by startChar and endChar. + */ + public int startTimeMs = -1; + + /** + * The end time (in milliseconds) to highlight the characters + * specified by startChar and endChar. + */ + public int endTimeMs = -1; + + /** + * The offset of the start character to be highlighted + */ + public int startChar = -1; + + /** + * The offset of the end character to be highlighted + */ + public int endChar = -1; + + public Karaoke() { } + } + + /** + * Helper class to hold the hyper text information. + * The member variables in this class are read-only. + */ + public class HyperText { + /** + * The offset of the start character + */ + public int startChar = -1; + + /** + * The offset of the end character + */ + public int endChar = -1; + + /** + * The linked-to URL + */ + public String URL; + + /** + * The "alt" string for user display + */ + public String altString; + + public HyperText() { } + } + + /** + * @param obj the byte array which contains the timed text. + * @throws IllegalArgumentExcept if parseParcel() fails. + * {@hide} + */ + public TimedText(byte[] obj) { + mParcel.unmarshall(obj, 0, obj.length); + + if (!parseParcel()) { + mKeyObjectMap.clear(); + throw new IllegalArgumentException("parseParcel() fails"); + } + } + + /** + * Go over all the records, collecting metadata keys and fields in the + * Parcel. These are stored in mKeyObjectMap for application to retrieve. + * @return false if an error occurred during parsing. Otherwise, true. + */ + private boolean parseParcel() { + mParcel.setDataPosition(0); + if (mParcel.dataAvail() == 0) { + return false; + } + + int type = mParcel.readInt(); + if (type == KEY_LOCAL_SETTING) { + type = mParcel.readInt(); + if (type != KEY_START_TIME) { + return false; + } + int mStartTimeMs = mParcel.readInt(); + mKeyObjectMap.put(type, mStartTimeMs); + + type = mParcel.readInt(); + if (type != KEY_STRUCT_TEXT) { + return false; + } + + mTextStruct = new Text(); + mTextStruct.textLen = mParcel.readInt(); + + mTextStruct.text = mParcel.createByteArray(); + mKeyObjectMap.put(type, mTextStruct); + + } else if (type != KEY_GLOBAL_SETTING) { + Log.w(TAG, "Invalid timed text key found: " + type); + return false; + } + + while (mParcel.dataAvail() > 0) { + int key = mParcel.readInt(); + if (!isValidKey(key)) { + Log.w(TAG, "Invalid timed text key found: " + key); + return false; + } + + Object object = null; + + switch (key) { + case KEY_STRUCT_STYLE_LIST: { + readStyle(); + object = mStyleList; + break; + } + case KEY_STRUCT_FONT_LIST: { + readFont(); + object = mFontList; + break; + } + case KEY_STRUCT_HIGHLIGHT_LIST: { + readHighlight(); + object = mHighlightPosList; + break; + } + case KEY_STRUCT_KARAOKE_LIST: { + readKaraoke(); + object = mKaraokeList; + break; + } + case KEY_STRUCT_HYPER_TEXT_LIST: { + readHyperText(); + object = mHyperTextList; + + break; + } + case KEY_STRUCT_BLINKING_TEXT_LIST: { + readBlinkingText(); + object = mBlinkingPosList; + + break; + } + case KEY_WRAP_TEXT: { + mWrapText = mParcel.readInt(); + object = mWrapText; + break; + } + case KEY_HIGHLIGHT_COLOR_RGBA: { + mHighlightColorRGBA = mParcel.readInt(); + object = mHighlightColorRGBA; + break; + } + case KEY_DISPLAY_FLAGS: { + mDisplayFlags = mParcel.readInt(); + object = mDisplayFlags; + break; + } + case KEY_STRUCT_JUSTIFICATION: { + mJustification = new Justification(); + + mJustification.horizontalJustification = mParcel.readInt(); + mJustification.verticalJustification = mParcel.readInt(); + + object = mJustification; + break; + } + case KEY_BACKGROUND_COLOR_RGBA: { + mBackgroundColorRGBA = mParcel.readInt(); + object = mBackgroundColorRGBA; + break; + } + case KEY_STRUCT_TEXT_POS: { + mTextPos = new TextPos(); + + mTextPos.top = mParcel.readInt(); + mTextPos.left = mParcel.readInt(); + mTextPos.bottom = mParcel.readInt(); + mTextPos.right = mParcel.readInt(); + + object = mTextPos; + break; + } + case KEY_SCROLL_DELAY: { + mScrollDelay = mParcel.readInt(); + object = mScrollDelay; + break; + } + default: { + break; + } + } + + if (object != null) { + if (mKeyObjectMap.containsKey(key)) { + mKeyObjectMap.remove(key); + } + mKeyObjectMap.put(key, object); + } + } + + mParcel.recycle(); + return true; + } + + /** + * To parse and store the Style list. + */ + private void readStyle() { + Style style = new Style(); + boolean endOfStyle = false; + + while (!endOfStyle && (mParcel.dataAvail() > 0)) { + int key = mParcel.readInt(); + switch (key) { + case KEY_START_CHAR: { + style.startChar = mParcel.readInt(); + break; + } + case KEY_END_CHAR: { + style.endChar = mParcel.readInt(); + break; + } + case KEY_FONT_ID: { + style.fontID = mParcel.readInt(); + break; + } + case KEY_STYLE_FLAGS: { + int flags = mParcel.readInt(); + // In the absence of any bits set in flags, the text + // is plain. Otherwise, 1: bold, 2: italic, 4: underline + style.isBold = ((flags % 2) == 1); + style.isItalic = ((flags % 4) >= 2); + style.isUnderlined = ((flags / 4) == 1); + break; + } + case KEY_FONT_SIZE: { + style.fontSize = mParcel.readInt(); + break; + } + case KEY_TEXT_COLOR_RGBA: { + style.colorRGBA = mParcel.readInt(); + break; + } + default: { + // End of the Style parsing. Reset the data position back + // to the position before the last mParcel.readInt() call. + mParcel.setDataPosition(mParcel.dataPosition() - 4); + endOfStyle = true; + break; + } + } + } + + if (mStyleList == null) { + mStyleList = new ArrayList<Style>(); + } + mStyleList.add(style); + } + + /** + * To parse and store the Font list + */ + private void readFont() { + int entryCount = mParcel.readInt(); + + for (int i = 0; i < entryCount; i++) { + Font font = new Font(); + + font.ID = mParcel.readInt(); + int nameLen = mParcel.readInt(); + + byte[] text = mParcel.createByteArray(); + font.name = new String(text, 0, nameLen); + + if (mFontList == null) { + mFontList = new ArrayList<Font>(); + } + mFontList.add(font); + } + } + + /** + * To parse and store the Highlight list + */ + private void readHighlight() { + CharPos pos = new CharPos(); + + pos.startChar = mParcel.readInt(); + pos.endChar = mParcel.readInt(); + + if (mHighlightPosList == null) { + mHighlightPosList = new ArrayList<CharPos>(); + } + mHighlightPosList.add(pos); + } + + /** + * To parse and store the Karaoke list + */ + private void readKaraoke() { + int entryCount = mParcel.readInt(); + + for (int i = 0; i < entryCount; i++) { + Karaoke kara = new Karaoke(); + + kara.startTimeMs = mParcel.readInt(); + kara.endTimeMs = mParcel.readInt(); + kara.startChar = mParcel.readInt(); + kara.endChar = mParcel.readInt(); + + if (mKaraokeList == null) { + mKaraokeList = new ArrayList<Karaoke>(); + } + mKaraokeList.add(kara); + } + } + + /** + * To parse and store HyperText list + */ + private void readHyperText() { + HyperText hyperText = new HyperText(); + + hyperText.startChar = mParcel.readInt(); + hyperText.endChar = mParcel.readInt(); + + int len = mParcel.readInt(); + byte[] url = mParcel.createByteArray(); + hyperText.URL = new String(url, 0, len); + + len = mParcel.readInt(); + byte[] alt = mParcel.createByteArray(); + hyperText.altString = new String(alt, 0, len); + + if (mHyperTextList == null) { + mHyperTextList = new ArrayList<HyperText>(); + } + mHyperTextList.add(hyperText); + } + + /** + * To parse and store blinking text list + */ + private void readBlinkingText() { + CharPos blinkingPos = new CharPos(); + + blinkingPos.startChar = mParcel.readInt(); + blinkingPos.endChar = mParcel.readInt(); + + if (mBlinkingPosList == null) { + mBlinkingPosList = new ArrayList<CharPos>(); + } + mBlinkingPosList.add(blinkingPos); + } + + /** + * To check whether the given key is valid. + * @param key the key to be checked. + * @return true if the key is a valid one. Otherwise, false. + */ + public boolean isValidKey(final int key) { + if (!((key >= FIRST_PUBLIC_KEY) && (key <= LAST_PUBLIC_KEY)) + && !((key >= FIRST_PRIVATE_KEY) && (key <= LAST_PRIVATE_KEY))) { + return false; + } + return true; + } + + /** + * To check whether the given key is contained in this TimedText object. + * @param key the key to be checked. + * @return true if the key is contained in this TimedText object. + * Otherwise, false. + */ + public boolean containsKey(final int key) { + if (isValidKey(key) && mKeyObjectMap.containsKey(key)) { + return true; + } + return false; + } + /** + * @return a set of the keys contained in this TimedText object. + */ + public Set keySet() { + return mKeyObjectMap.keySet(); + } + + /** + * To retrieve the object associated with the key. Caller must make sure + * the key is present using the containsKey method otherwise a + * RuntimeException will occur. + * @param key the key used to retrieve the object. + * @return an object. The object could be an instanceof Integer, List, or + * any of the helper classes such as TextPos, Justification, and Text. + */ + public Object getObject(final int key) { + if (containsKey(key)) { + return mKeyObjectMap.get(key); + } else { + throw new IllegalArgumentException("Invalid key: " + key); + } + } +} diff --git a/media/java/android/media/videoeditor/VideoEditorImpl.java b/media/java/android/media/videoeditor/VideoEditorImpl.java index 2105deb1b9e2..649b98a6fa57 100755 --- a/media/java/android/media/videoeditor/VideoEditorImpl.java +++ b/media/java/android/media/videoeditor/VideoEditorImpl.java @@ -38,6 +38,7 @@ import android.graphics.Bitmap; import android.graphics.Rect; import android.media.videoeditor.MediaImageItem; import android.media.videoeditor.MediaItem; +import android.media.MediaMetadataRetriever; import android.util.Log; import android.util.Xml; import android.view.Surface; @@ -1833,12 +1834,32 @@ public class VideoEditorImpl implements VideoEditor { } Bitmap projectBitmap = null; - try { - projectBitmap = mI.getThumbnail(width, height, 500); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException ("Illegal argument error creating project thumbnail"); - } catch (IOException e) { - throw new IllegalArgumentException ("IO Error creating project thumbnail"); + String filename = mI.getFilename(); + if (mI instanceof MediaVideoItem) { + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + retriever.setDataSource(filename); + Bitmap bitmap = retriever.getFrameAtTime(); + retriever.release(); + retriever = null; + if (bitmap == null) { + String msg = "Thumbnail extraction from " + + filename + " failed"; + throw new IllegalArgumentException(msg); + } + // Resize the thumbnail to the target size + projectBitmap = + Bitmap.createScaledBitmap(bitmap, width, height, true); + } else { + try { + projectBitmap = mI.getThumbnail(width, height, 500); + } catch (IllegalArgumentException e) { + String msg = "Project thumbnail extraction from " + + filename + " failed"; + throw new IllegalArgumentException(msg); + } catch (IOException e) { + String msg = "IO Error creating project thumbnail"; + throw new IllegalArgumentException(msg); + } } try { diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp index 5696433614fe..d43a5622a769 100755 --- a/media/jni/mediaeditor/VideoEditorClasses.cpp +++ b/media/jni/mediaeditor/VideoEditorClasses.cpp @@ -144,6 +144,7 @@ VIDEOEDIT_JAVA_DEFINE_CONSTANTS(ClipType) VIDEOEDIT_JAVA_CONSTANT_INIT("MP3", M4VIDEOEDITING_kFileType_MP3), VIDEOEDIT_JAVA_CONSTANT_INIT("PCM", M4VIDEOEDITING_kFileType_PCM), VIDEOEDIT_JAVA_CONSTANT_INIT("JPG", M4VIDEOEDITING_kFileType_JPG), + VIDEOEDIT_JAVA_CONSTANT_INIT("PNG", M4VIDEOEDITING_kFileType_PNG), VIDEOEDIT_JAVA_CONSTANT_INIT("M4V", M4VIDEOEDITING_kFileType_M4V), VIDEOEDIT_JAVA_CONSTANT_INIT("UNSUPPORTED", M4VIDEOEDITING_kFileType_Unsupported) }; @@ -1394,8 +1395,8 @@ videoEditClasses_getClipSettings( pSettings->FileType = (M4VIDEOEDITING_FileType)videoEditJava_getClipTypeJavaToC( &converted, pEnv->GetIntField(object, fieldIds.fileType)); - if ( pSettings->FileType == M4VIDEOEDITING_kFileType_JPG) - { + if (( pSettings->FileType == M4VIDEOEDITING_kFileType_JPG) || + ( pSettings->FileType == M4VIDEOEDITING_kFileType_PNG)) { pSettings->FileType = M4VIDEOEDITING_kFileType_ARGB8888; } diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 5fe511fbb543..5582f9278a64 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -889,11 +889,17 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { uint32_t entry_count = U32_AT(&buffer[4]); if (entry_count > 1) { - // For now we only support a single type of media per track. - - mLastTrack->skipTrack = true; - *offset += chunk_size; - break; + // For 3GPP timed text, there could be multiple tx3g boxes contain + // multiple text display formats. These formats will be used to + // display the timed text. + const char *mime; + CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime)); + if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { + // For now we only support a single type of media per track. + mLastTrack->skipTrack = true; + *offset += chunk_size; + break; + } } off64_t stop_offset = *offset + chunk_size; @@ -1324,9 +1330,53 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { return parseDrmSINF(offset, data_offset); } + case FOURCC('h', 'd', 'l', 'r'): + { + uint32_t buffer; + if (mDataSource->readAt( + data_offset + 8, &buffer, 4) < 4) { + return ERROR_IO; + } + + uint32_t type = ntohl(buffer); + // For the 3GPP file format, the handler-type within the 'hdlr' box + // shall be 'text' + if (type == FOURCC('t', 'e', 'x', 't')) { + mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP); + } + + *offset += chunk_size; + break; + } + case FOURCC('t', 'x', '3', 'g'): { - mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP); + uint32_t type; + const void *data; + size_t size = 0; + if (!mLastTrack->meta->findData( + kKeyTextFormatData, &type, &data, &size)) { + size = 0; + } + + uint8_t *buffer = new uint8_t[size + chunk_size]; + + if (size > 0) { + memcpy(buffer, data, size); + } + + if ((size_t)(mDataSource->readAt(*offset, buffer + size, chunk_size)) + < chunk_size) { + delete[] buffer; + buffer = NULL; + + return ERROR_IO; + } + + mLastTrack->meta->setData( + kKeyTextFormatData, 0, buffer, size + chunk_size); + + delete[] buffer; *offset += chunk_size; break; diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index ea9911cdee17..f075699d6a47 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -205,6 +205,8 @@ private: // Duration is time scale based void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur); void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur); + + bool isTrackMalFormed() const; void sendTrackSummary(bool hasMultipleTracks); // Write the boxes @@ -1975,7 +1977,6 @@ status_t MPEG4Writer::Track::threadEntry() { } CHECK(timestampUs >= 0); - LOGV("%s media time stamp: %lld and previous paused duration %lld", mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs); if (timestampUs > mTrackDurationUs) { @@ -2082,11 +2083,10 @@ status_t MPEG4Writer::Track::threadEntry() { } - if (mSampleSizes.empty() || // no samples written - (!mIsAudio && mNumStssTableEntries == 0) || // no sync frames for video - (OK != checkCodecSpecificData())) { // no codec specific data + if (isTrackMalFormed()) { err = ERROR_MALFORMED; } + mOwner->trackProgressStatus(mTrackId, -1, err); // Last chunk @@ -2136,6 +2136,24 @@ status_t MPEG4Writer::Track::threadEntry() { return err; } +bool MPEG4Writer::Track::isTrackMalFormed() const { + if (mSampleSizes.empty()) { // no samples written + LOGE("The number of recorded samples is 0"); + return true; + } + + if (!mIsAudio && mNumStssTableEntries == 0) { // no sync frames for video + LOGE("There are no sync frames for video track"); + return true; + } + + if (OK != checkCodecSpecificData()) { // no codec specific data + return true; + } + + return false; +} + void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { // Send track summary only if test mode is enabled. diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk index 9a6062cdd608..59d0e154c597 100644 --- a/media/libstagefright/timedtext/Android.mk +++ b/media/libstagefright/timedtext/Android.mk @@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ + TextDescriptions.cpp \ TimedTextParser.cpp \ TimedTextPlayer.cpp diff --git a/media/libstagefright/timedtext/TextDescriptions.cpp b/media/libstagefright/timedtext/TextDescriptions.cpp new file mode 100644 index 000000000000..f9c1fe093803 --- /dev/null +++ b/media/libstagefright/timedtext/TextDescriptions.cpp @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TextDescriptions.h" +#include <media/stagefright/Utils.h> +#include <media/stagefright/MediaErrors.h> + +namespace android { + +TextDescriptions::TextDescriptions() { +} + +status_t TextDescriptions::getParcelOfDescriptions( + const uint8_t *data, ssize_t size, + uint32_t flags, int timeMs, Parcel *parcel) { + parcel->freeData(); + + if (flags & IN_BAND_TEXT_3GPP) { + if (flags & GLOBAL_DESCRIPTIONS) { + return extract3GPPGlobalDescriptions(data, size, parcel, 0); + } else if (flags & LOCAL_DESCRIPTIONS) { + return extract3GPPLocalDescriptions(data, size, timeMs, parcel, 0); + } + } else if (flags & OUT_OF_BAND_TEXT_SRT) { + if (flags & LOCAL_DESCRIPTIONS) { + return extractSRTLocalDescriptions(data, size, timeMs, parcel); + } + } + + return ERROR_UNSUPPORTED; +} + +// Parse the SRT text sample, and store the timing and text sample in a Parcel. +// The Parcel will be sent to MediaPlayer.java through event, and will be +// parsed in TimedText.java. +status_t TextDescriptions::extractSRTLocalDescriptions( + const uint8_t *data, ssize_t size, int timeMs, Parcel *parcel) { + parcel->writeInt32(KEY_LOCAL_SETTING); + parcel->writeInt32(KEY_START_TIME); + parcel->writeInt32(timeMs); + + parcel->writeInt32(KEY_STRUCT_TEXT); + // write the size of the text sample + parcel->writeInt32(size); + // write the text sample as a byte array + parcel->writeInt32(size); + parcel->write(data, size); + + return OK; +} + +// Extract the local 3GPP display descriptions. 3GPP local descriptions +// are appended to the text sample if any. The descriptions could include +// information such as text styles, highlights, karaoke and so on. They +// are contained in different boxes, such as 'styl' box contains text +// styles, and 'krok' box contains karaoke timing and positions. +status_t TextDescriptions::extract3GPPLocalDescriptions( + const uint8_t *data, ssize_t size, + int timeMs, Parcel *parcel, int depth) { + if (depth == 0) { + parcel->writeInt32(KEY_LOCAL_SETTING); + + // write start time to display this text sample + parcel->writeInt32(KEY_START_TIME); + parcel->writeInt32(timeMs); + + ssize_t textLen = (*data) << 8 | (*(data + 1)); + + // write text sample length and text sample itself + parcel->writeInt32(KEY_STRUCT_TEXT); + parcel->writeInt32(textLen); + parcel->writeInt32(textLen); + parcel->write(data + 2, textLen); + + if (size > textLen) { + data += (textLen + 2); + size -= (textLen + 2); + } else { + return OK; + } + } + + const uint8_t *tmpData = data; + ssize_t chunkSize = U32_AT(tmpData); + uint32_t chunkType = U32_AT(tmpData + 4); + + if (chunkSize <= 0) { + return OK; + } + + tmpData += 8; + + switch(chunkType) { + // 'styl' box specifies the style of the text. + case FOURCC('s', 't', 'y', 'l'): + { + uint16_t count = U16_AT(tmpData); + + tmpData += 2; + + for (int i = 0; i < count; i++) { + parcel->writeInt32(KEY_STRUCT_STYLE_LIST); + parcel->writeInt32(KEY_START_CHAR); + parcel->writeInt32(U16_AT(tmpData)); + + parcel->writeInt32(KEY_END_CHAR); + parcel->writeInt32(U16_AT(tmpData + 2)); + + parcel->writeInt32(KEY_FONT_ID); + parcel->writeInt32(U16_AT(tmpData + 4)); + + parcel->writeInt32(KEY_STYLE_FLAGS); + parcel->writeInt32(*(tmpData + 6)); + + parcel->writeInt32(KEY_FONT_SIZE); + parcel->writeInt32(*(tmpData + 7)); + + parcel->writeInt32(KEY_TEXT_COLOR_RGBA); + uint32_t rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16 + | *(tmpData + 10) << 8 | *(tmpData + 11); + parcel->writeInt32(rgba); + + tmpData += 12; + } + + break; + } + // 'krok' box. The number of highlight events is specified, and each + // event is specified by a starting and ending char offset and an end + // time for the event. + case FOURCC('k', 'r', 'o', 'k'): + { + + parcel->writeInt32(KEY_STRUCT_KARAOKE_LIST); + + int startTime = U32_AT(tmpData); + uint16_t count = U16_AT(tmpData + 4); + parcel->writeInt32(count); + + tmpData += 6; + int lastEndTime = 0; + + for (int i = 0; i < count; i++) { + parcel->writeInt32(startTime + lastEndTime); + + lastEndTime = U32_AT(tmpData); + parcel->writeInt32(lastEndTime); + + parcel->writeInt32(U16_AT(tmpData + 4)); + parcel->writeInt32(U16_AT(tmpData + 6)); + + tmpData += 8; + } + + break; + } + // 'hlit' box specifies highlighted text + case FOURCC('h', 'l', 'i', 't'): + { + parcel->writeInt32(KEY_STRUCT_HIGHLIGHT_LIST); + + // the start char offset to highlight + parcel->writeInt32(U16_AT(tmpData)); + // the last char offset to highlight + parcel->writeInt32(U16_AT(tmpData + 2)); + + break; + } + // 'hclr' box specifies the RGBA color: 8 bits each of + // red, green, blue, and an alpha(transparency) value + case FOURCC('h', 'c', 'l', 'r'): + { + parcel->writeInt32(KEY_HIGHLIGHT_COLOR_RGBA); + + uint32_t rgba = *(tmpData) << 24 | *(tmpData + 1) << 16 + | *(tmpData + 2) << 8 | *(tmpData + 3); + parcel->writeInt32(rgba); + + break; + } + // 'dlay' box specifies a delay after a scroll in and/or + // before scroll out. + case FOURCC('d', 'l', 'a', 'y'): + { + parcel->writeInt32(KEY_SCROLL_DELAY); + + uint32_t delay = *(tmpData) << 24 | *(tmpData + 1) << 16 + | *(tmpData + 2) << 8 | *(tmpData + 3); + parcel->writeInt32(delay); + + break; + } + // 'href' box for hyper text link + case FOURCC('h', 'r', 'e', 'f'): + { + parcel->writeInt32(KEY_STRUCT_HYPER_TEXT_LIST); + + // the start offset of the text to be linked + parcel->writeInt32(U16_AT(tmpData)); + // the end offset of the text + parcel->writeInt32(U16_AT(tmpData + 2)); + + // the number of bytes in the following URL + int len = *(tmpData + 4); + parcel->writeInt32(len); + + // the linked-to URL + parcel->writeInt32(len); + parcel->write(tmpData + 5, len); + + tmpData += (5 + len); + + // the number of bytes in the following "alt" string + len = *tmpData; + parcel->writeInt32(len); + + // an "alt" string for user display + parcel->writeInt32(len); + parcel->write(tmpData + 1, len); + + break; + } + // 'tbox' box to indicate the position of the text with values + // of top, left, bottom and right + case FOURCC('t', 'b', 'o', 'x'): + { + parcel->writeInt32(KEY_STRUCT_TEXT_POS); + parcel->writeInt32(U16_AT(tmpData)); + parcel->writeInt32(U16_AT(tmpData + 2)); + parcel->writeInt32(U16_AT(tmpData + 4)); + parcel->writeInt32(U16_AT(tmpData + 6)); + + break; + } + // 'blnk' to specify the char range to be blinked + case FOURCC('b', 'l', 'n', 'k'): + { + parcel->writeInt32(KEY_STRUCT_BLINKING_TEXT_LIST); + + // start char offset + parcel->writeInt32(U16_AT(tmpData)); + // end char offset + parcel->writeInt32(U16_AT(tmpData + 2)); + + break; + } + // 'twrp' box specifies text wrap behavior. If the value if 0x00, + // then no wrap. If it's 0x01, then automatic 'soft' wrap is enabled. + // 0x02-0xff are reserved. + case FOURCC('t', 'w', 'r', 'p'): + { + parcel->writeInt32(KEY_WRAP_TEXT); + parcel->writeInt32(*tmpData); + + break; + } + default: + { + break; + } + } + + if (size > chunkSize) { + data += chunkSize; + size -= chunkSize; + // continue to parse next box + return extract3GPPLocalDescriptions(data, size, 0, parcel, 1); + } + + return OK; +} + +// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a Parcel +status_t TextDescriptions::extract3GPPGlobalDescriptions( + const uint8_t *data, ssize_t size, Parcel *parcel, int depth) { + + ssize_t chunkSize = U32_AT(data); + uint32_t chunkType = U32_AT(data + 4); + const uint8_t *tmpData = data; + tmpData += 8; + + if (size < chunkSize) { + return OK; + } + + if (depth == 0) { + parcel->writeInt32(KEY_GLOBAL_SETTING); + } + switch(chunkType) { + case FOURCC('t', 'x', '3', 'g'): + { + tmpData += 8; // skip the first 8 bytes + parcel->writeInt32(KEY_DISPLAY_FLAGS); + parcel->writeInt32(U32_AT(tmpData)); + + parcel->writeInt32(KEY_STRUCT_JUSTIFICATION); + parcel->writeInt32(tmpData[4]); + parcel->writeInt32(tmpData[5]); + + parcel->writeInt32(KEY_BACKGROUND_COLOR_RGBA); + uint32_t rgba = *(tmpData + 6) << 24 | *(tmpData + 7) << 16 + | *(tmpData + 8) << 8 | *(tmpData + 9); + parcel->writeInt32(rgba); + + tmpData += 10; + parcel->writeInt32(KEY_STRUCT_TEXT_POS); + parcel->writeInt32(U16_AT(tmpData)); + parcel->writeInt32(U16_AT(tmpData + 2)); + parcel->writeInt32(U16_AT(tmpData + 4)); + parcel->writeInt32(U16_AT(tmpData + 6)); + + tmpData += 8; + parcel->writeInt32(KEY_STRUCT_STYLE_LIST); + parcel->writeInt32(KEY_START_CHAR); + parcel->writeInt32(U16_AT(tmpData)); + + parcel->writeInt32(KEY_END_CHAR); + parcel->writeInt32(U16_AT(tmpData + 2)); + + parcel->writeInt32(KEY_FONT_ID); + parcel->writeInt32(U16_AT(tmpData + 4)); + + parcel->writeInt32(KEY_STYLE_FLAGS); + parcel->writeInt32(*(tmpData + 6)); + + parcel->writeInt32(KEY_FONT_SIZE); + parcel->writeInt32(*(tmpData + 7)); + + parcel->writeInt32(KEY_TEXT_COLOR_RGBA); + rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16 + | *(tmpData + 10) << 8 | *(tmpData + 11); + parcel->writeInt32(rgba); + + tmpData += 12; + parcel->writeInt32(KEY_STRUCT_FONT_LIST); + uint16_t count = U16_AT(tmpData); + parcel->writeInt32(count); + + tmpData += 2; + for (int i = 0; i < count; i++) { + // font ID + parcel->writeInt32(U16_AT(tmpData)); + + // font name length + parcel->writeInt32(*(tmpData + 2)); + + int len = *(tmpData + 2); + + parcel->write(tmpData + 3, len); + tmpData += 3 + len; + } + + break; + } + default: + { + break; + } + } + + data += chunkSize; + size -= chunkSize; + + if (size > 0) { + // continue to extract next 'tx3g' + return extract3GPPGlobalDescriptions(data, size, parcel, 1); + } + + return OK; +} + +} // namespace android diff --git a/media/libstagefright/timedtext/TextDescriptions.h b/media/libstagefright/timedtext/TextDescriptions.h new file mode 100644 index 000000000000..0144917505e9 --- /dev/null +++ b/media/libstagefright/timedtext/TextDescriptions.h @@ -0,0 +1,84 @@ + /* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TEXT_DESCRIPTIONS_H_ + +#define TEXT_DESCRIPTIONS_H_ + +#include <binder/Parcel.h> +#include <media/stagefright/foundation/ABase.h> + +namespace android { + +class TextDescriptions { +public: + enum { + IN_BAND_TEXT_3GPP = 0x01, + OUT_OF_BAND_TEXT_SRT = 0x02, + + GLOBAL_DESCRIPTIONS = 0x100, + LOCAL_DESCRIPTIONS = 0x200, + }; + + static status_t getParcelOfDescriptions( + const uint8_t *data, ssize_t size, + uint32_t flags, int timeMs, Parcel *parcel); +private: + TextDescriptions(); + + enum { + // These keys must be in sync with the keys in TimedText.java + KEY_DISPLAY_FLAGS = 1, // int + KEY_STYLE_FLAGS = 2, // int + KEY_BACKGROUND_COLOR_RGBA = 3, // int + KEY_HIGHLIGHT_COLOR_RGBA = 4, // int + KEY_SCROLL_DELAY = 5, // int + KEY_WRAP_TEXT = 6, // int + KEY_START_TIME = 7, // int + KEY_STRUCT_BLINKING_TEXT_LIST = 8, // List<CharPos> + KEY_STRUCT_FONT_LIST = 9, // List<Font> + KEY_STRUCT_HIGHLIGHT_LIST = 10, // List<CharPos> + KEY_STRUCT_HYPER_TEXT_LIST = 11, // List<HyperText> + KEY_STRUCT_KARAOKE_LIST = 12, // List<Karaoke> + KEY_STRUCT_STYLE_LIST = 13, // List<Style> + KEY_STRUCT_TEXT_POS = 14, // TextPos + KEY_STRUCT_JUSTIFICATION = 15, // Justification + KEY_STRUCT_TEXT = 16, // Text + + KEY_GLOBAL_SETTING = 101, + KEY_LOCAL_SETTING = 102, + KEY_START_CHAR = 103, + KEY_END_CHAR = 104, + KEY_FONT_ID = 105, + KEY_FONT_SIZE = 106, + KEY_TEXT_COLOR_RGBA = 107, + }; + + static status_t extractSRTLocalDescriptions( + const uint8_t *data, ssize_t size, + int timeMs, Parcel *parcel); + static status_t extract3GPPGlobalDescriptions( + const uint8_t *data, ssize_t size, + Parcel *parcel, int depth); + static status_t extract3GPPLocalDescriptions( + const uint8_t *data, ssize_t size, + int timeMs, Parcel *parcel, int depth); + + DISALLOW_EVIL_CONSTRUCTORS(TextDescriptions); +}; + +} // namespace android +#endif // TEXT_DESCRIPTIONS_H_ diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp index 50bb16d3f2a9..7c8a747c518f 100644 --- a/media/libstagefright/timedtext/TimedTextPlayer.cpp +++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp @@ -19,6 +19,7 @@ #include <utils/Log.h> #include <binder/IPCThreadState.h> + #include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaErrors.h> @@ -27,9 +28,11 @@ #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/FileSource.h> #include <media/stagefright/Utils.h> + #include "include/AwesomePlayer.h" #include "TimedTextPlayer.h" #include "TimedTextParser.h" +#include "TextDescriptions.h" namespace android { @@ -92,10 +95,11 @@ status_t TimedTextPlayer::start(uint8_t index) { return BAD_VALUE; } + status_t err; if (index < mTextTrackVector.size()) { // start an in-band text mSource = mTextTrackVector.itemAt(index); - status_t err = mSource->start(); + err = mSource->start(); if (err != OK) { return err; @@ -112,13 +116,17 @@ status_t TimedTextPlayer::start(uint8_t index) { mTextParser = new TimedTextParser(); } - status_t err; if ((err = mTextParser->init(mOutOfBandSource, fileType)) != OK) { return err; } mTextType = kOutOfBandText; } + // send sample description format + if ((err = extractAndSendGlobalDescriptions()) != OK) { + return err; + } + int64_t positionUs; mObserver->getPosition(&positionUs); seekTo(positionUs); @@ -211,21 +219,17 @@ void TimedTextPlayer::onTextEvent() { } mTextEventPending = false; + if (mData.dataSize() > 0) { + notifyListener(MEDIA_TIMED_TEXT, &mData); + mData.freeData(); + } + MediaSource::ReadOptions options; if (mSeeking) { options.setSeekTo(mSeekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); mSeeking = false; - if (mTextType == kInBandText) { - if (mTextBuffer != NULL) { - mTextBuffer->release(); - mTextBuffer = NULL; - } - } else { - mText.clear(); - } - notifyListener(MEDIA_TIMED_TEXT); //empty text to clear the screen } @@ -233,32 +237,12 @@ void TimedTextPlayer::onTextEvent() { mObserver->getPosition(&positionUs); if (mTextType == kInBandText) { - if (mTextBuffer != NULL) { - uint8_t *tmp = (uint8_t *)(mTextBuffer->data()); - size_t len = (*tmp) << 8 | (*(tmp + 1)); - - notifyListener(MEDIA_TIMED_TEXT, - tmp + 2, - len); - - mTextBuffer->release(); - mTextBuffer = NULL; - - } - if (mSource->read(&mTextBuffer, &options) != OK) { return; } mTextBuffer->meta_data()->findInt64(kKeyTime, &timeUs); } else { - if (mText.size() > 0) { - notifyListener(MEDIA_TIMED_TEXT, - mText.c_str(), - mText.size()); - mText.clear(); - } - int64_t endTimeUs; if (mTextParser->getText( &mText, &timeUs, &endTimeUs, &options) != OK) { @@ -266,6 +250,19 @@ void TimedTextPlayer::onTextEvent() { } } + if (timeUs > 0) { + extractAndAppendLocalDescriptions(timeUs); + } + + if (mTextType == kInBandText) { + if (mTextBuffer != NULL) { + mTextBuffer->release(); + mTextBuffer = NULL; + } + } else { + mText.clear(); + } + //send the text now if (timeUs <= positionUs + 100000ll) { postTextEvent(); @@ -297,7 +294,8 @@ status_t TimedTextPlayer::setParameter(int key, const Parcel &request) { Mutex::Autolock autoLock(mLock); if (key == KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE) { - String8 uri = request.readString8(); + const String16 uri16 = request.readString16(); + String8 uri = String8(uri16); KeyedVector<String8, String8> headers; // To support local subtitle file only for now @@ -327,21 +325,92 @@ status_t TimedTextPlayer::setParameter(int key, const Parcel &request) { return INVALID_OPERATION; } -void TimedTextPlayer::notifyListener( - int msg, const void *data, size_t size) { +void TimedTextPlayer::notifyListener(int msg, const Parcel *parcel) { if (mListener != NULL) { sp<MediaPlayerBase> listener = mListener.promote(); if (listener != NULL) { - if (size > 0) { - mData.freeData(); - mData.write(data, size); - - listener->sendEvent(msg, 0, 0, &mData); + if (parcel && (parcel->dataSize() > 0)) { + listener->sendEvent(msg, 0, 0, parcel); } else { // send an empty timed text to clear the screen listener->sendEvent(msg); } } } } + +// Each text sample consists of a string of text, optionally with sample +// modifier description. The modifier description could specify a new +// text style for the string of text. These descriptions are present only +// if they are needed. This method is used to extract the modifier +// description and append it at the end of the text. +status_t TimedTextPlayer::extractAndAppendLocalDescriptions(int64_t timeUs) { + const void *data; + size_t size = 0; + int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS; + + if (mTextType == kInBandText) { + const char *mime; + CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); + + if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { + flag |= TextDescriptions::IN_BAND_TEXT_3GPP; + data = mTextBuffer->data(); + size = mTextBuffer->size(); + } else { + // support 3GPP only for now + return ERROR_UNSUPPORTED; + } + } else { + data = mText.c_str(); + size = mText.size(); + flag |= TextDescriptions::OUT_OF_BAND_TEXT_SRT; + } + + if ((size > 0) && (flag != TextDescriptions::LOCAL_DESCRIPTIONS)) { + mData.freeData(); + return TextDescriptions::getParcelOfDescriptions( + (const uint8_t *)data, size, flag, timeUs / 1000, &mData); + } + + return OK; +} + +// To extract and send the global text descriptions for all the text samples +// in the text track or text file. +status_t TimedTextPlayer::extractAndSendGlobalDescriptions() { + const void *data; + size_t size = 0; + int32_t flag = TextDescriptions::GLOBAL_DESCRIPTIONS; + + if (mTextType == kInBandText) { + const char *mime; + CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); + + // support 3GPP only for now + if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { + uint32_t type; + // get the 'tx3g' box content. This box contains the text descriptions + // used to render the text track + if (!mSource->getFormat()->findData( + kKeyTextFormatData, &type, &data, &size)) { + return ERROR_MALFORMED; + } + + flag |= TextDescriptions::IN_BAND_TEXT_3GPP; + } + } + + if ((size > 0) && (flag != TextDescriptions::GLOBAL_DESCRIPTIONS)) { + Parcel parcel; + if (TextDescriptions::getParcelOfDescriptions( + (const uint8_t *)data, size, flag, 0, &parcel) == OK) { + if (parcel.dataSize() > 0) { + notifyListener(MEDIA_TIMED_TEXT, &parcel); + } + } + } + + return OK; +} } diff --git a/media/libstagefright/timedtext/TimedTextPlayer.h b/media/libstagefright/timedtext/TimedTextPlayer.h index 590760b10977..a744db59417b 100644 --- a/media/libstagefright/timedtext/TimedTextPlayer.h +++ b/media/libstagefright/timedtext/TimedTextPlayer.h @@ -103,8 +103,10 @@ private: void postTextEvent(int64_t delayUs = -1); void cancelTextEvent(); - void notifyListener( - int msg, const void *data = NULL, size_t size = 0); + void notifyListener(int msg, const Parcel *parcel = NULL); + + status_t extractAndAppendLocalDescriptions(int64_t timeUs); + status_t extractAndSendGlobalDescriptions(); DISALLOW_EVIL_CONSTRUCTORS(TimedTextPlayer); }; diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java index 187a486f8ce2..60906a1e08dd 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java @@ -1,93 +1,96 @@ -/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.usb;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.hardware.usb.UsbManager;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.util.Log;
-import android.widget.Button;
-
-import java.io.File;
-
-import com.android.systemui.R;
-
-public class UsbPreferenceActivity extends Activity implements View.OnClickListener {
-
- private static final String TAG = "UsbPreferenceActivity";
-
- private UsbManager mUsbManager;
- private String mCurrentFunction;
- private String[] mFunctions;
- private String mInstallerImagePath;
- private Button mMtpPtpButton;
- private Button mInstallerCdButton;
- private boolean mPtpActive;
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
-
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
- dialogBuilder.setTitle(getString(R.string.usb_preference_title));
-
- LayoutInflater inflater = (LayoutInflater)getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- View buttonView = inflater.inflate(R.layout.usb_preference_buttons, null);
- dialogBuilder.setView(buttonView);
- mMtpPtpButton = (Button)buttonView.findViewById(R.id.mtp_ptp_button);
- mInstallerCdButton = (Button)buttonView.findViewById(R.id.installer_cd_button);
- mMtpPtpButton.setOnClickListener(this);
- mInstallerCdButton.setOnClickListener(this);
-
- mPtpActive = mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_PTP);
- if (mPtpActive) {
- mMtpPtpButton.setText(R.string.use_mtp_button_title);
- }
-
- mInstallerImagePath = getString(com.android.internal.R.string.config_isoImagePath);
- if (!(new File(mInstallerImagePath)).exists()) {
- mInstallerCdButton.setVisibility(View.GONE);
- }
-
- dialogBuilder.show();
- }
-
- public void onClick(View v) {
- if (v.equals(mMtpPtpButton)) {
- if (mPtpActive) {
- mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_MTP);
- mUsbManager.setDefaultFunction(UsbManager.USB_FUNCTION_MTP);
- } else {
- mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_PTP);
- mUsbManager.setDefaultFunction(UsbManager.USB_FUNCTION_PTP);
- }
- } else if (v.equals(mInstallerCdButton)) {
- mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_MASS_STORAGE);
- mUsbManager.setMassStorageBackingFile(mInstallerImagePath);
- }
-
+/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.usb; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.hardware.usb.UsbManager; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.util.Log; +import android.widget.Button; + +import java.io.File; + +import com.android.systemui.R; + +public class UsbPreferenceActivity extends Activity implements View.OnClickListener { + + private static final String TAG = "UsbPreferenceActivity"; + + private UsbManager mUsbManager; + private String mCurrentFunction; + private String[] mFunctions; + private String mInstallerImagePath; + private AlertDialog mDialog; + private Button mMtpPtpButton; + private Button mInstallerCdButton; + private boolean mPtpActive; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE); + + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); + dialogBuilder.setTitle(getString(R.string.usb_preference_title)); + + LayoutInflater inflater = (LayoutInflater)getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + View buttonView = inflater.inflate(R.layout.usb_preference_buttons, null); + dialogBuilder.setView(buttonView); + mMtpPtpButton = (Button)buttonView.findViewById(R.id.mtp_ptp_button); + mInstallerCdButton = (Button)buttonView.findViewById(R.id.installer_cd_button); + mMtpPtpButton.setOnClickListener(this); + mInstallerCdButton.setOnClickListener(this); + + mPtpActive = mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_PTP); + if (mPtpActive) { + mMtpPtpButton.setText(R.string.use_mtp_button_title); + } + + mInstallerImagePath = getString(com.android.internal.R.string.config_isoImagePath); + if (!(new File(mInstallerImagePath)).exists()) { + mInstallerCdButton.setVisibility(View.GONE); + } + + mDialog = dialogBuilder.show(); + } + + public void onClick(View v) { + if (v.equals(mMtpPtpButton)) { + if (mPtpActive) { + mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MTP, true); + } else { + mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_PTP, true); + } + } else if (v.equals(mInstallerCdButton)) { + // installer CD is never default + mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MASS_STORAGE, false); + mUsbManager.setMassStorageBackingFile(mInstallerImagePath); + } + + if (mDialog != null) { + mDialog.dismiss(); + } finish();
- }
-}
+ } +} diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 75f466a35fdd..baa4ec398354 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -498,6 +498,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return; } + int width = WRAP_CONTENT; if (st.decorView == null || st.refreshDecorView) { if (st.decorView == null) { // Initialize the panel decor, this will populate st.decorView @@ -523,6 +524,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // If the contents is fill parent for the width, set the // corresponding background backgroundResId = st.fullBackground; + width = MATCH_PARENT; } else { // Otherwise, set the normal panel background backgroundResId = st.background; @@ -546,7 +548,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { st.isHandled = false; WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - WRAP_CONTENT, WRAP_CONTENT, + width, WRAP_CONTENT, st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG, WindowManager.LayoutParams.FLAG_DITHER | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index aa3dfa6201c0..e6f443a54bcd 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -466,12 +466,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b); mTethering = new Tethering(mContext, nmService, mHandler.getLooper()); - mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) || - !mTethering.isDunRequired()) && - (mTethering.getTetherableUsbRegexs().length != 0 || + mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 || mTethering.getTetherableWifiRegexs().length != 0 || mTethering.getTetherableBluetoothRegexs().length != 0) && - mTethering.getUpstreamIfaceRegexs().length != 0); + mTethering.getUpstreamIfaceTypes().length != 0); mVpn = new Vpn(mContext, new VpnCallback()); @@ -1576,12 +1574,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } addPrivateDnsRoutes(mNetTrackers[netType]); } - - /** Notify TetheringService if interface name has been changed. */ - if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(), - Phone.REASON_LINK_PROPERTIES_CHANGED)) { - handleTetherIfaceChange(netType); - } } else { if (mNetConfigs[netType].isDefault()) { removeDefaultRoute(mNetTrackers[netType]); @@ -2412,14 +2404,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private void handleTetherIfaceChange(int type) { - String iface = mNetTrackers[type].getLinkProperties().getInterfaceName(); - - if (isTetheringSupported()) { - mTethering.handleTetherIfaceChange(iface); - } - } - private void log(String s) { Slog.d(TAG, s); } diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index a9dfb22310d7..f6dd43a815b6 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -32,6 +32,7 @@ import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.ContentObserver; +import android.graphics.Rect; import android.net.Uri; import android.os.Binder; import android.os.Handler; @@ -814,6 +815,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub final AtomicInteger mInteractionIdCounter = new AtomicInteger(); + final Rect mTempBounds = new Rect(); + // the events pending events to be dispatched to this service final SparseArray<AccessibilityEvent> mPendingEvents = new SparseArray<AccessibilityEvent>(); @@ -932,9 +935,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub AccessibilityNodeInfo info = mCallback.getFindAccessibilityNodeInfoResultAndClear( interactionId); if (info != null) { + applyCompatibilityScaleIfNeeded(info); info.setConnection(this); + info.setSealed(true); } - info.setSealed(true); return info; } catch (RemoteException re) { if (DEBUG) { @@ -979,6 +983,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub final int infoCount = infos.size(); for (int i = 0; i < infoCount; i++) { AccessibilityNodeInfo info = infos.get(i); + applyCompatibilityScaleIfNeeded(info); info.setConnection(this); info.setSealed(true); } @@ -1019,6 +1024,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub AccessibilityNodeInfo info = mCallback.getFindAccessibilityNodeInfoResultAndClear(interactionId); if (info != null) { + applyCompatibilityScaleIfNeeded(info); info.setConnection(this); info.setSealed(true); } @@ -1093,6 +1099,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } return mWindowIdToInteractionConnectionMap.get(windowId); } + + private void applyCompatibilityScaleIfNeeded(AccessibilityNodeInfo info) { + IBinder windowToken = mWindowIdToWindowTokenMap.get(info.getWindowId()); + final float scale = mWindowManagerService.getWindowCompatibilityScale(windowToken); + + if (scale == 1.0f) { + return; + } + + Rect bounds = mTempBounds; + info.getBoundsInParent(bounds); + bounds.scale(scale); + info.setBoundsInParent(bounds); + + info.getBoundsInScreen(bounds); + bounds.scale(scale); + info.setBoundsInScreen(bounds); + } } final class SecurityPolicy { diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index d8772b82e60e..b94ee587793c 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -73,7 +73,7 @@ import java.util.List; */ final class ActivityStack { static final String TAG = ActivityManagerService.TAG; - static final boolean localLOGV = ActivityManagerService.localLOGV || true; + static final boolean localLOGV = ActivityManagerService.localLOGV; static final boolean DEBUG_SWITCH = ActivityManagerService.DEBUG_SWITCH; static final boolean DEBUG_PAUSE = ActivityManagerService.DEBUG_PAUSE; static final boolean DEBUG_VISBILITY = ActivityManagerService.DEBUG_VISBILITY; diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index 15e67d0e2dc4..911cac2bcc3d 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/java/com/android/server/connectivity/Tethering.java @@ -57,7 +57,9 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.net.InetAddress; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedList; import java.util.Set; /** @@ -82,7 +84,15 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private String[] mTetherableUsbRegexs; private String[] mTetherableWifiRegexs; private String[] mTetherableBluetoothRegexs; - private String[] mUpstreamIfaceRegexs; + private Collection<Integer> mUpstreamIfaceTypes; + + private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE); + private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI); + private static final Integer DUN_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_DUN); + + // if we have to connect to mobile, what APN type should we use? Calculated by examining the + // upstream type list and the DUN_REQUIRED secure-setting + private int mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_NONE; private INetworkManagementService mNMService; private Looper mLooper; @@ -112,9 +122,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8"; private static final String DNS_DEFAULT_SERVER2 = "8.8.4.4"; - // resampled each time we turn on tethering - used as cache for settings/config-val - private boolean mDunRequired; // configuration info - must use DUN apn on 3g - private StateMachine mTetherMasterSM; private Notification mTetheredNotification; @@ -159,7 +166,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) { mDhcpRange = DHCP_DEFAULT_RANGE; } - mDunRequired = false; // resample when we turn on mTetherableUsbRegexs = context.getResources().getStringArray( com.android.internal.R.array.config_tether_usb_regexs); @@ -167,8 +173,15 @@ public class Tethering extends INetworkManagementEventObserver.Stub { com.android.internal.R.array.config_tether_wifi_regexs); mTetherableBluetoothRegexs = context.getResources().getStringArray( com.android.internal.R.array.config_tether_bluetooth_regexs); - mUpstreamIfaceRegexs = context.getResources().getStringArray( - com.android.internal.R.array.config_tether_upstream_regexs); + int ifaceTypes[] = context.getResources().getIntArray( + com.android.internal.R.array.config_tether_upstream_types); + mUpstreamIfaceTypes = new ArrayList(); + for (int i : ifaceTypes) { + mUpstreamIfaceTypes.add(new Integer(i)); + } + + // check if the upstream type list needs to be modified due to secure-settings + checkDunRequired(); // TODO - remove and rely on real notifications of the current iface mDnsServers = new String[2]; @@ -509,9 +522,9 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } try { if (enabled) { - usbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_RNDIS); + usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false); } else { - usbManager.setPrimaryFunction(null); + usbManager.setCurrentFunction(null, false); } } catch (Exception e) { Log.e(TAG, "Error toggling usb RNDIS", e); @@ -582,16 +595,44 @@ public class Tethering extends INetworkManagementEventObserver.Stub { return mTetherableBluetoothRegexs; } - public String[] getUpstreamIfaceRegexs() { - return mUpstreamIfaceRegexs; + public int[] getUpstreamIfaceTypes() { + int values[] = new int[mUpstreamIfaceTypes.size()]; + Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator(); + for (int i=0; i < mUpstreamIfaceTypes.size(); i++) { + values[i] = iterator.next(); + } + return values; } - public boolean isDunRequired() { - boolean defaultVal = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_tether_dun_required); - boolean result = (Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.TETHER_DUN_REQUIRED, (defaultVal ? 1 : 0)) == 1); - return result; + public void checkDunRequired() { + int requiredApn = ((Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.TETHER_DUN_REQUIRED, 0) == 1) ? + ConnectivityManager.TYPE_MOBILE_DUN : + ConnectivityManager.TYPE_MOBILE_HIPRI); + if (mPreferredUpstreamMobileApn != requiredApn) { + if (requiredApn == ConnectivityManager.TYPE_MOBILE_DUN) { + while (mUpstreamIfaceTypes.contains(MOBILE_TYPE)) { + mUpstreamIfaceTypes.remove(MOBILE_TYPE); + } + while (mUpstreamIfaceTypes.contains(HIPRI_TYPE)) { + mUpstreamIfaceTypes.remove(HIPRI_TYPE); + } + if (mUpstreamIfaceTypes.contains(DUN_TYPE) == false) { + mUpstreamIfaceTypes.add(DUN_TYPE); + } + } else { + while (mUpstreamIfaceTypes.contains(DUN_TYPE)) { + mUpstreamIfaceTypes.remove(DUN_TYPE); + } + if (mUpstreamIfaceTypes.contains(MOBILE_TYPE) == false) { + mUpstreamIfaceTypes.add(MOBILE_TYPE); + } + if (mUpstreamIfaceTypes.contains(HIPRI_TYPE) == false) { + mUpstreamIfaceTypes.add(HIPRI_TYPE); + } + } + mPreferredUpstreamMobileApn = requiredApn; + } } public String[] getTetheredIfaces() { @@ -648,17 +689,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { return retVal; } - public void handleTetherIfaceChange(String iface) { - // check if iface is white listed - for (String regex : mUpstreamIfaceRegexs) { - if (iface.matches(regex)) { - if (DEBUG) Log.d(TAG, "Tethering got Interface Change"); - mTetherMasterSM.sendMessage(TetherMasterSM.CMD_IFACE_CHANGED, iface); - break; - } - } - } - class TetherInterfaceSM extends StateMachine { // notification from the master SM that it's not in tether mode static final int CMD_TETHER_MODE_DEAD = 1; @@ -1051,8 +1081,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { static final int CMD_CELL_CONNECTION_RENEW = 4; // we don't have a valid upstream conn, check again after a delay static final int CMD_RETRY_UPSTREAM = 5; - // received an indication that upstream interface has changed - static final int CMD_IFACE_CHANGED = 6; // This indicates what a timeout event relates to. A state that // sends itself a delayed timeout event and handles incoming timeout events @@ -1072,7 +1100,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private ArrayList mNotifyList; private int mCurrentConnectionSequence; - private boolean mMobileReserved = false; + private int mMobileApnReserved = ConnectivityManager.TYPE_NONE; private String mUpstreamIfaceName = null; @@ -1111,22 +1139,34 @@ public class Tethering extends INetworkManagementEventObserver.Stub { public boolean processMessage(Message m) { return false; } - protected boolean turnOnMobileConnection() { + protected String enableString(int apnType) { + switch (apnType) { + case ConnectivityManager.TYPE_MOBILE_DUN: + return Phone.FEATURE_ENABLE_DUN_ALWAYS; + case ConnectivityManager.TYPE_MOBILE: + case ConnectivityManager.TYPE_MOBILE_HIPRI: + return Phone.FEATURE_ENABLE_HIPRI; + } + return null; + } + protected boolean turnOnUpstreamMobileConnection(int apnType) { boolean retValue = true; - if (mMobileReserved) return retValue; + if (apnType == ConnectivityManager.TYPE_NONE) return false; + if (apnType != mMobileApnReserved) turnOffUpstreamMobileConnection(); IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b); int result = Phone.APN_REQUEST_FAILED; + String enableString = enableString(apnType); + if (enableString == null) return false; try { result = cm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - (mDunRequired ? Phone.FEATURE_ENABLE_DUN_ALWAYS : - Phone.FEATURE_ENABLE_HIPRI), new Binder()); + enableString, new Binder()); } catch (Exception e) { } switch (result) { case Phone.APN_ALREADY_ACTIVE: case Phone.APN_REQUEST_STARTED: - mMobileReserved = true; + mMobileApnReserved = apnType; Message m = obtainMessage(CMD_CELL_CONNECTION_RENEW); m.arg1 = ++mCurrentConnectionSequence; sendMessageDelayed(m, CELL_CONNECTION_RENEW_MS); @@ -1139,18 +1179,17 @@ public class Tethering extends INetworkManagementEventObserver.Stub { return retValue; } - protected boolean turnOffMobileConnection() { - if (mMobileReserved) { + protected boolean turnOffUpstreamMobileConnection() { + if (mMobileApnReserved != ConnectivityManager.TYPE_NONE) { IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b); try { cm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - (mDunRequired? Phone.FEATURE_ENABLE_DUN_ALWAYS : - Phone.FEATURE_ENABLE_HIPRI)); + enableString(mMobileApnReserved)); } catch (Exception e) { return false; } - mMobileReserved = false; + mMobileApnReserved = ConnectivityManager.TYPE_NONE; } return true; } @@ -1196,108 +1235,55 @@ public class Tethering extends INetworkManagementEventObserver.Stub { transitionTo(mInitialState); return true; } - protected String findActiveUpstreamIface() { - // check for what iface we can use - if none found switch to error. + + protected void chooseUpstreamType(boolean tryCell) { IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b); + int upType = ConnectivityManager.TYPE_NONE; + String iface = null; - try { - LinkProperties defaultProp = cm.getActiveLinkProperties(); - if (defaultProp != null) { - String iface = defaultProp.getInterfaceName(); - for(String regex : mUpstreamIfaceRegexs) { - if (iface.matches(regex)) return iface; - } - } - } catch (RemoteException e) { } - - String[] ifaces = new String[0]; - try { - ifaces = mNMService.listInterfaces(); - } catch (Exception e) { - Log.e(TAG, "Error listing Interfaces", e); - return null; - } - - for (String regex : mUpstreamIfaceRegexs) { - for (String iface : ifaces) { - if (iface.matches(regex)) { - // verify it is active - InterfaceConfiguration ifcg = null; - try { - ifcg = mNMService.getInterfaceConfig(iface); - if (ifcg.isActive()) { - return iface; - } - } catch (Exception e) { - Log.e(TAG, "Error getting iface config", e); - // ignore - try next - continue; - } - } + for (Integer netType : mUpstreamIfaceTypes) { + NetworkInfo info = null; + try { + info = cm.getNetworkInfo(netType.intValue()); + } catch (RemoteException e) { } + if ((info != null) && info.isConnected()) { + upType = netType.intValue(); + break; } } - return null; - } - protected void chooseUpstreamType(boolean tryCell) { - // decide if the current upstream is good or not and if not - // do something about it (start up DUN if required or HiPri if not) - String iface = findActiveUpstreamIface(); - IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); - IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b); - mMobileReserved = false; if (DEBUG) { - Log.d(TAG, "chooseUpstreamType(" + tryCell + "), dunRequired =" - + mDunRequired + ", iface=" + iface); + Log.d(TAG, "chooseUpstreamType(" + tryCell + "), preferredApn =" + + mPreferredUpstreamMobileApn + ", got type=" + upType); } - if (iface != null) { - try { - if (mDunRequired) { - // check if Dun is on - we can use that - NetworkInfo info = cm.getNetworkInfo( - ConnectivityManager.TYPE_MOBILE_DUN); - if (info.isConnected()) { - if (DEBUG) Log.d(TAG, "setting dun ifacename =" + iface); - // even if we're already connected - it may be somebody else's - // refcount, so add our own - turnOnMobileConnection(); - } else { - // verify the iface is not the default mobile - can't use that! - info = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); - if (info.isConnected()) { - iface = null; // can't accept this one - } - } - } else { - if (DEBUG) Log.d(TAG, "checking if hipri brought us this connection"); - NetworkInfo info = cm.getNetworkInfo( - ConnectivityManager.TYPE_MOBILE_HIPRI); - if (info.isConnected()) { - if (DEBUG) Log.d(TAG, "yes - hipri in use"); - // even if we're already connected - it may be sombody else's - // refcount, so add our own - turnOnMobileConnection(); - } - } - } catch (RemoteException e) { - Log.e(TAG, "RemoteException calling ConnectivityManager", e); - iface = null; - } + + // if we're on DUN, put our own grab on it + if (upType == ConnectivityManager.TYPE_MOBILE_DUN || + upType == ConnectivityManager.TYPE_MOBILE_HIPRI) { + turnOnUpstreamMobileConnection(upType); } - // may have been set to null in the if above - if (iface == null ) { - boolean success = false; - if (tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) { - success = turnOnMobileConnection(); + + if (upType == ConnectivityManager.TYPE_NONE) { + boolean tryAgainLater = true; + if ((tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) && + (turnOnUpstreamMobileConnection(mPreferredUpstreamMobileApn) == true)) { + // we think mobile should be coming up - don't set a retry + tryAgainLater = false; } - if (!success) { - // wait for things to settle and retry + if (tryAgainLater) { sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS); } + } else { + LinkProperties linkProperties = null; + try { + linkProperties = cm.getLinkProperties(upType); + } catch (RemoteException e) { } + if (linkProperties != null) iface = linkProperties.getInterfaceName(); } notifyTetheredOfNewUpstreamIface(iface); } + protected void notifyTetheredOfNewUpstreamIface(String ifaceName) { if (DEBUG) Log.d(TAG, "notifying tethered with iface =" + ifaceName); mUpstreamIfaceName = ifaceName; @@ -1312,7 +1298,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { class InitialState extends TetherMasterUtilState { @Override public void enter() { - mMobileReserved = false; } @Override public boolean processMessage(Message message) { @@ -1320,7 +1305,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { boolean retValue = true; switch (message.what) { case CMD_TETHER_MODE_REQUESTED: - mDunRequired = isDunRequired(); + checkDunRequired(); TetherInterfaceSM who = (TetherInterfaceSM)message.obj; if (DEBUG) Log.d(TAG, "Tether Mode requested by " + who.toString()); mNotifyList.add(who); @@ -1354,7 +1339,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } @Override public void exit() { - turnOffMobileConnection(); + turnOffUpstreamMobileConnection(); notifyTetheredOfNewUpstreamIface(null); } @Override @@ -1392,19 +1377,13 @@ public class Tethering extends INetworkManagementEventObserver.Stub { Log.d(TAG, "renewing mobile connection - requeuing for another " + CELL_CONNECTION_RENEW_MS + "ms"); } - mMobileReserved = false; // need to renew it - turnOnMobileConnection(); + turnOnUpstreamMobileConnection(mMobileApnReserved); } break; case CMD_RETRY_UPSTREAM: chooseUpstreamType(mTryCell); mTryCell = !mTryCell; break; - case CMD_IFACE_CHANGED: - String iface = (String)message.obj; - if (DEBUG) Log.d(TAG, "Activie upstream interface changed: " + iface); - notifyTetheredOfNewUpstreamIface(iface); - break; default: retValue = false; break; diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java index b7f9d5ccb04a..918f1b6b8355 100644 --- a/services/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/java/com/android/server/usb/UsbDeviceManager.java @@ -77,9 +77,8 @@ public class UsbDeviceManager { private static final int MSG_UPDATE_STATE = 0; private static final int MSG_ENABLE_ADB = 1; - private static final int MSG_SET_PRIMARY_FUNCTION = 2; - private static final int MSG_SET_DEFAULT_FUNCTION = 3; - private static final int MSG_SYSTEM_READY = 4; + private static final int MSG_SET_CURRENT_FUNCTION = 2; + private static final int MSG_SYSTEM_READY = 3; // Delay for debouncing USB disconnects. // We often get rapid connect/disconnect events when enabling USB functions, @@ -227,7 +226,7 @@ public class UsbDeviceManager { mHandler.updateState(state); } else if ("START".equals(accessory)) { Slog.d(TAG, "got accessory start"); - setPrimaryFunction(UsbManager.USB_FUNCTION_ACCESSORY); + setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false); } } }; @@ -371,6 +370,14 @@ public class UsbDeviceManager { sendMessage(m); } + public void sendMessage(int what, Object arg0, boolean arg1) { + removeMessages(what); + Message m = Message.obtain(this, what); + m.obj = arg0; + m.arg1 = (arg1 ? 1 : 0); + sendMessage(m); + } + public void updateState(String state) { int connected, configured; @@ -395,24 +402,30 @@ public class UsbDeviceManager { sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0); } - private boolean setUsbConfig(String config) { - // set the new configuration - SystemProperties.set("sys.usb.config", config); + private boolean waitForState(String state) { // wait for the transition to complete. // give up after 1 second. for (int i = 0; i < 20; i++) { // State transition is done when sys.usb.conf.done is set to the new configuration - if (config.equals(SystemProperties.get("sys.usb.state"))) return true; + if (state.equals(SystemProperties.get("sys.usb.state"))) return true; try { // try again in 50ms Thread.sleep(50); } catch (InterruptedException e) { } } + Log.e(TAG, "waitForState(" + state + ") FAILED"); return false; } - private void setCurrentFunctions(String functions) { + private boolean setUsbConfig(String config) { + Log.d(TAG, "setUsbConfig(" + config + ")"); + // set the new configuration + SystemProperties.set("sys.usb.config", config); + return waitForState(config); + } + + private void doSetCurrentFunctions(String functions) { if (!mCurrentFunctions.equals(functions)) { if (!setUsbConfig("none") || !setUsbConfig(functions)) { Log.e(TAG, "Failed to switch USB configuration to " + functions); @@ -428,17 +441,14 @@ public class UsbDeviceManager { if (enable != mAdbEnabled) { mAdbEnabled = enable; String functions; + // Due to the persist.sys.usb.config property trigger, changing adb state requires + // switching to default function if (enable) { - functions = addFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB); - mDefaultFunctions = addFunction(mDefaultFunctions, - UsbManager.USB_FUNCTION_ADB); + functions = addFunction(mDefaultFunctions, UsbManager.USB_FUNCTION_ADB); } else { - functions = removeFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB); - mDefaultFunctions = removeFunction(mDefaultFunctions, - UsbManager.USB_FUNCTION_ADB); + functions = removeFunction(mDefaultFunctions, UsbManager.USB_FUNCTION_ADB); } - SystemProperties.set("persist.sys.usb.config", mDefaultFunctions); - setCurrentFunctions(functions); + setCurrentFunction(functions, true); updateAdbNotification(mAdbEnabled && mConnected); } } @@ -449,7 +459,7 @@ public class UsbDeviceManager { } else { functionList = removeFunction(functionList, UsbManager.USB_FUNCTION_ADB); } - setCurrentFunctions(functionList); + doSetCurrentFunctions(functionList); } private void updateCurrentAccessory() { @@ -503,8 +513,6 @@ public class UsbDeviceManager { @Override public void handleMessage(Message msg) { - String function; - switch (msg.what) { case MSG_UPDATE_STATE: mConnected = (msg.arg1 == 1); @@ -518,7 +526,7 @@ public class UsbDeviceManager { if (!mConnected) { // restore defaults when USB is disconnected - setCurrentFunctions(mDefaultFunctions); + doSetCurrentFunctions(mDefaultFunctions); } if (mSystemReady) { updateUsbState(); @@ -527,20 +535,31 @@ public class UsbDeviceManager { case MSG_ENABLE_ADB: setAdbEnabled(msg.arg1 == 1); break; - case MSG_SET_PRIMARY_FUNCTION: - function = (String)msg.obj; - if (function == null) { - function = mDefaultFunctions; - } - setEnabledFunctions(function); - break; - case MSG_SET_DEFAULT_FUNCTION: - function = (String)msg.obj; - if (mAdbEnabled) { - function = addFunction(function, UsbManager.USB_FUNCTION_ADB); + case MSG_SET_CURRENT_FUNCTION: + String function = (String)msg.obj; + boolean makeDefault = (msg.arg1 == 1); + if (makeDefault) { + if (function == null) { + throw new NullPointerException(); + } + if (mAdbEnabled) { + function = addFunction(function, UsbManager.USB_FUNCTION_ADB); + } + + setUsbConfig("none"); + // setting this property will change the current USB state + // via a property trigger + SystemProperties.set("persist.sys.usb.config", function); + if (waitForState(function)) { + mCurrentFunctions = function; + mDefaultFunctions = function; + } + } else { + if (function == null) { + function = mDefaultFunctions; + } + setEnabledFunctions(function); } - SystemProperties.set("persist.sys.usb.config", function); - mDefaultFunctions = function; break; case MSG_SYSTEM_READY: updateUsbNotification(mConnected); @@ -588,15 +607,8 @@ public class UsbDeviceManager { return nativeOpenAccessory(); } - public void setPrimaryFunction(String function) { - mHandler.sendMessage(MSG_SET_PRIMARY_FUNCTION, function); - } - - public void setDefaultFunction(String function) { - if (function == null) { - throw new NullPointerException(); - } - mHandler.sendMessage(MSG_SET_DEFAULT_FUNCTION, function); + public void setCurrentFunction(String function, boolean makeDefault) { + mHandler.sendMessage(MSG_SET_CURRENT_FUNCTION, function, makeDefault); } public void setMassStorageBackingFile(String path) { diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java index 193638f64186..9f2c17aa8ae5 100644 --- a/services/java/com/android/server/usb/UsbService.java +++ b/services/java/com/android/server/usb/UsbService.java @@ -146,19 +146,10 @@ public class UsbService extends IUsbManager.Stub { mSettingsManager.clearDefaults(packageName); } - public void setPrimaryFunction(String function) { + public void setCurrentFunction(String function, boolean makeDefault) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); if (mDeviceManager != null) { - mDeviceManager.setPrimaryFunction(function); - } else { - throw new IllegalStateException("USB device mode not supported"); - } - } - - public void setDefaultFunction(String function) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); - if (mDeviceManager != null) { - mDeviceManager.setDefaultFunction(function); + mDeviceManager.setCurrentFunction(function, makeDefault); } else { throw new IllegalStateException("USB device mode not supported"); } diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java index 3be8af63a1d8..68066344586a 100644 --- a/services/java/com/android/server/wm/InputMonitor.java +++ b/services/java/com/android/server/wm/InputMonitor.java @@ -17,6 +17,7 @@ package com.android.server.wm; import android.graphics.Rect; +import android.os.Binder; import android.os.Process; import android.os.RemoteException; import android.util.Log; @@ -152,6 +153,8 @@ final class InputMonitor { } mUpdateInputWindowsNeeded = false; + if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED updateInputWindowsLw"); + // Populate the input window list with information about all of the windows that // could potentially receive input. // As an optimization, we could try to prune the list of windows but this turns @@ -232,6 +235,8 @@ final class InputMonitor { // Clear the list in preparation for the next round. // Also avoids keeping InputChannel objects referenced unnecessarily. mTempInputWindows.clear(); + + if (false) Slog.d(WindowManagerService.TAG, "<<<<<<< EXITED updateInputWindowsLw"); } /* Notifies that the input device configuration has changed. */ diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java index 0f09356f95e5..50b251f22ce0 100644 --- a/services/java/com/android/server/wm/Session.java +++ b/services/java/com/android/server/wm/Session.java @@ -153,11 +153,13 @@ final class Session extends IWindowSession.Stub int requestedWidth, int requestedHeight, int viewFlags, boolean insetsPending, Rect outFrame, Rect outContentInsets, Rect outVisibleInsets, Configuration outConfig, Surface outSurface) { - //Log.d(TAG, ">>>>>> ENTERED relayout from " + Binder.getCallingPid()); + if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED relayout from " + + Binder.getCallingPid()); int res = mService.relayoutWindow(this, window, attrs, requestedWidth, requestedHeight, viewFlags, insetsPending, outFrame, outContentInsets, outVisibleInsets, outConfig, outSurface); - //Log.d(TAG, "<<<<<< EXITING relayout to " + Binder.getCallingPid()); + if (false) Slog.d(WindowManagerService.TAG, "<<<<<< EXITING relayout to " + + Binder.getCallingPid()); return res; } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 1c87f5b4002d..d62c031bf1eb 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -2776,6 +2776,13 @@ public class WindowManagerService extends IWindowManager.Stub Binder.restoreCallingIdentity(origId); } + public float getWindowCompatibilityScale(IBinder windowToken) { + synchronized (mWindowMap) { + WindowState windowState = mWindowMap.get(windowToken); + return (windowState != null) ? windowState.mGlobalScale : 1.0f; + } + } + private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) { if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg=" + (lp != null ? lp.packageName : null) @@ -7817,18 +7824,30 @@ public class WindowManagerService extends IWindowManager.Stub TAG, "Placing surface #" + i + " " + w.mSurface + ": new=" + w.mShownFrame); - int width, height; - if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) { - // for a scaled surface, we just want to use - // the requested size. - width = w.mRequestedWidth; - height = w.mRequestedHeight; - } else { - width = w.mCompatFrame.width(); - height = w.mCompatFrame.height(); - } - if (w.mSurface != null) { + int width, height; + if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) { + // for a scaled surface, we just want to use + // the requested size. + width = w.mRequestedWidth; + height = w.mRequestedHeight; + } else { + width = w.mCompatFrame.width(); + height = w.mCompatFrame.height(); + } + + if (width < 1) { + width = 1; + } + if (height < 1) { + height = 1; + } + final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height; + if (surfaceResized) { + w.mSurfaceW = width; + w.mSurfaceH = height; + } + if (w.mSurfaceX != w.mShownFrame.left || w.mSurfaceY != w.mShownFrame.top) { try { @@ -7848,21 +7867,11 @@ public class WindowManagerService extends IWindowManager.Stub } } - if (width < 1) { - width = 1; - } - if (height < 1) { - height = 1; - } - - if (w.mSurfaceW != width || w.mSurfaceH != height) { + if (surfaceResized) { try { if (SHOW_TRANSACTIONS) logSurface(w, - "SIZE " + w.mShownFrame.width() + "x" - + w.mShownFrame.height(), null); + "SIZE " + width + "x" + height, null); w.mSurfaceResized = true; - w.mSurfaceW = width; - w.mSurfaceH = height; w.mSurface.setSize(width, height); } catch (RuntimeException e) { // If something goes wrong with the surface (such @@ -7878,9 +7887,9 @@ public class WindowManagerService extends IWindowManager.Stub } if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) { - w.mContentInsetsChanged = + w.mContentInsetsChanged |= !w.mLastContentInsets.equals(w.mContentInsets); - w.mVisibleInsetsChanged = + w.mVisibleInsetsChanged |= !w.mLastVisibleInsets.equals(w.mVisibleInsets); boolean configChanged = w.mConfiguration != mCurConfiguration @@ -7892,24 +7901,20 @@ public class WindowManagerService extends IWindowManager.Stub } if (localLOGV) Slog.v(TAG, "Resizing " + w + ": configChanged=" + configChanged - + " last=" + w.mLastCompatFrame + " frame=" + w.mCompatFrame); - boolean frameChanged = !w.mLastCompatFrame.equals(w.mCompatFrame); - if (frameChanged - || w.mContentInsetsChanged + + " last=" + w.mLastFrame + " frame=" + w.mFrame); + w.mLastFrame.set(w.mFrame); + if (w.mContentInsetsChanged || w.mVisibleInsetsChanged || w.mSurfaceResized || configChanged) { if (DEBUG_RESIZE || DEBUG_ORIENTATION) { Slog.v(TAG, "Resize reasons: " - + "frameChanged=" + frameChanged + " contentInsetsChanged=" + w.mContentInsetsChanged + " visibleInsetsChanged=" + w.mVisibleInsetsChanged + " surfaceResized=" + w.mSurfaceResized + " configChanged=" + configChanged); } - w.mLastFrame.set(w.mFrame); - w.mLastCompatFrame.set(w.mCompatFrame); w.mLastContentInsets.set(w.mContentInsets); w.mLastVisibleInsets.set(w.mVisibleInsets); // If the screen is currently frozen, then keep @@ -7944,9 +7949,12 @@ public class WindowManagerService extends IWindowManager.Stub w.mAppToken.allDrawn = false; } } - if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, - "Resizing window " + w + " to " + w.mCompatFrame); - mResizingWindows.add(w); + if (!mResizingWindows.contains(w)) { + if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, + "Resizing window " + w + " to " + w.mSurfaceW + + "x" + w.mSurfaceH); + mResizingWindows.add(w); + } } else if (w.mOrientationChanging) { if (!w.mDrawPending && !w.mCommitDrawPending) { if (DEBUG_ORIENTATION) Slog.v(TAG, @@ -8241,13 +8249,12 @@ public class WindowManagerService extends IWindowManager.Stub if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) { Slog.i(TAG, "Sending new config to window " + win + ": " - + win.mCompatFrame.width() + "x" + win.mCompatFrame.height() + + win.mSurfaceW + "x" + win.mSurfaceH + " / " + mCurConfiguration + " / 0x" + Integer.toHexString(diff)); } win.mConfiguration = mCurConfiguration; - win.mClient.resized(win.mCompatFrame.width(), - win.mCompatFrame.height(), win.mLastContentInsets, + win.mClient.resized(win.mSurfaceW, win.mSurfaceH, win.mLastContentInsets, win.mLastVisibleInsets, win.mDrawPending, configChanged ? win.mConfiguration : null); win.mContentInsetsChanged = false; diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 587685e624ff..b370ec9e12cd 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -111,7 +111,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { * applied). */ final Rect mShownFrame = new Rect(); - final Rect mLastShownFrame = new Rect(); /** * Set when we have changed the size of the surface, to know that @@ -182,7 +181,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { // Frame that is scaled to the application's coordinate space when in // screen size compatibility mode. final Rect mCompatFrame = new Rect(); - final Rect mLastCompatFrame = new Rect(); final Rect mContainingFrame = new Rect(); final Rect mDisplayFrame = new Rect(); @@ -1584,15 +1582,12 @@ final class WindowState implements WindowManagerPolicy.WindowState { } pw.print(prefix); pw.print("mConfiguration="); pw.println(mConfiguration); pw.print(prefix); pw.print("mShownFrame="); - mShownFrame.printShortString(pw); - pw.print(" last="); mLastShownFrame.printShortString(pw); - pw.println(); + mShownFrame.printShortString(pw); pw.println(); pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw); pw.print(" last="); mLastFrame.printShortString(pw); pw.println(); if (mEnforceSizeCompat) { pw.print(prefix); pw.print("mCompatFrame="); mCompatFrame.printShortString(pw); - pw.print(" last="); mLastCompatFrame.printShortString(pw); pw.println(); } pw.print(prefix); pw.print("mContainingFrame="); diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java index a45e8793d146..fb2fc8545338 100644 --- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java +++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java @@ -190,7 +190,6 @@ public class ICU_Delegate { // Used by DecimalFormatSymbols. result.zeroDigit = '0'; - result.digit = '0'; result.decimalSeparator = '.'; result.groupingSeparator = ','; result.patternSeparator = ' '; |