Merge "Fix flashing artifacts caused by invalidation bugs"
diff --git a/build/phone-hdpi-512-dalvik-heap.mk b/build/phone-hdpi-512-dalvik-heap.mk
index 788b686..16e0505 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 2b9c082..9bab797 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -82,11 +82,8 @@
/* 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 a828a23..67d200c 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -408,32 +408,18 @@
}
/**
- * 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 2242e9e..ce6f697 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -164,6 +164,12 @@
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 39c3c88..5fa8836 100644
--- a/core/java/android/server/BluetoothBondState.java
+++ b/core/java/android/server/BluetoothBondState.java
@@ -79,7 +79,6 @@
mService = service;
mBluetoothInputProfileHandler =
BluetoothInputProfileHandler.getInstance(mContext, mService);
- getProfileProxy();
}
synchronized void setPendingOutgoingBonding(String address) {
@@ -109,6 +108,7 @@
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 0421205..2f598f4 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -96,12 +96,9 @@
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 @@
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 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 @@
}
}
+ synchronized (mLock) {
+ if (mUpdateLayer) {
+ mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight());
+ mUpdateLayer = false;
+ }
+ }
+
return mLayer;
}
@@ -278,23 +287,15 @@
// 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 ca11c70..ad660c1 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -1005,8 +1005,7 @@
+ "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 b5d4933..bb4d192 100644
--- a/core/java/android/webkit/JniUtil.java
+++ b/core/java/android/webkit/JniUtil.java
@@ -23,6 +23,10 @@
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 0e52869..e88d257 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -535,7 +535,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 cbb110a..0c0205c 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -464,8 +464,7 @@
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 e301e44..16992997 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -649,7 +649,9 @@
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 dd68d82..03c6022 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 52b00c6..a8b7b75 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 deade5e..99b72ad 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -118,6 +118,9 @@
// 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 afab26a..e43f6e5 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -101,8 +101,14 @@
}
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 @@
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 @@
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 dcf2cf2..b83259f 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -292,6 +292,10 @@
return mBitmapResources;
}
+ const Vector<SkiaColorFilter*>& getFilterResources() const {
+ return mFilterResources;
+ }
+
const Vector<SkiaShader*>& getShaders() const {
return mShaders;
}
@@ -308,10 +312,6 @@
return mMatrices;
}
- const Vector<SkiaColorFilter*>& getFilterResources() const {
- return mFilterResources;
- }
-
private:
void insertRestoreToCount() {
if (mRestoreSaveCount >= 0) {
@@ -419,7 +419,9 @@
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 @@
// 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 @@
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 9aade51..cd2c405 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -48,9 +48,6 @@
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 @@
ref->destroyed = true;
if (ref->refCount == 0) {
deleteResourceReference(resource, ref);
- return;
}
}
@@ -162,7 +158,6 @@
ref->destroyed = true;
if (ref->refCount == 0) {
deleteResourceReference(resource, ref);
- return;
}
}
@@ -180,7 +175,6 @@
ref->destroyed = true;
if (ref->refCount == 0) {
deleteResourceReference(resource, ref);
- return;
}
}
@@ -195,7 +189,6 @@
ref->destroyed = true;
if (ref->refCount == 0) {
deleteResourceReference(resource, ref);
- return;
}
}
@@ -209,36 +202,32 @@
}
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 bf45e13..1bf475c 100644
--- a/libs/hwui/SkiaColorFilter.h
+++ b/libs/hwui/SkiaColorFilter.h
@@ -59,7 +59,7 @@
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 2557730..33312d1 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1568,7 +1568,14 @@
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 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 0000000..a055c8b
--- /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 2105deb..649b98a 100755
--- a/media/java/android/media/videoeditor/VideoEditorImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorImpl.java
@@ -38,6 +38,7 @@
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 @@
}
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 5696433..d43a562 100755
--- a/media/jni/mediaeditor/VideoEditorClasses.cpp
+++ b/media/jni/mediaeditor/VideoEditorClasses.cpp
@@ -144,6 +144,7 @@
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 @@
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 5fe511f..5582f92 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -889,11 +889,17 @@
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 @@
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 ea9911c..f075699d 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -205,6 +205,8 @@
// 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 @@
}
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 @@
}
- 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 @@
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 9a6062c..59d0e15 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -2,6 +2,7 @@
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 0000000..f9c1fe0
--- /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 0000000..01449175
--- /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 50bb16d..7c8a747 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 @@
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 @@
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 @@
}
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 @@
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 @@
}
}
+ 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 @@
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 @@
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 590760b..a744db5 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.h
+++ b/media/libstagefright/timedtext/TimedTextPlayer.h
@@ -103,8 +103,10 @@
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 187a486..60906a1 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 75f466a..baa4ec3 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 @@
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 @@
// 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 @@
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 aa3dfa6..e6f443a 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -466,12 +466,10 @@
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 @@
}
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 @@
}
}
- 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 a9dfb22..f6dd43a 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.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 @@
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 @@
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 @@
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 @@
AccessibilityNodeInfo info =
mCallback.getFindAccessibilityNodeInfoResultAndClear(interactionId);
if (info != null) {
+ applyCompatibilityScaleIfNeeded(info);
info.setConnection(this);
info.setSealed(true);
}
@@ -1093,6 +1099,24 @@
}
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 d8772b8..b94ee58 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -73,7 +73,7 @@
*/
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 15e67d0..911cac2 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.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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
transitionTo(mInitialState);
return true;
}
- protected String findActiveUpstreamIface() {
- // check for what iface we can use - if none found switch to error.
- IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
- IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
-
- 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;
- }
- }
- }
- }
- 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);
- }
- if (iface != null) {
+ int upType = ConnectivityManager.TYPE_NONE;
+ String iface = null;
+
+ for (Integer netType : mUpstreamIfaceTypes) {
+ NetworkInfo info = 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;
+ info = cm.getNetworkInfo(netType.intValue());
+ } catch (RemoteException e) { }
+ if ((info != null) && info.isConnected()) {
+ upType = netType.intValue();
+ break;
}
}
- // 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 (DEBUG) {
+ Log.d(TAG, "chooseUpstreamType(" + tryCell + "), preferredApn ="
+ + mPreferredUpstreamMobileApn + ", got type=" + upType);
+ }
+
+ // if we're on DUN, put our own grab on it
+ if (upType == ConnectivityManager.TYPE_MOBILE_DUN ||
+ upType == ConnectivityManager.TYPE_MOBILE_HIPRI) {
+ turnOnUpstreamMobileConnection(upType);
+ }
+
+ 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 @@
class InitialState extends TetherMasterUtilState {
@Override
public void enter() {
- mMobileReserved = false;
}
@Override
public boolean processMessage(Message message) {
@@ -1320,7 +1305,7 @@
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 @@
}
@Override
public void exit() {
- turnOffMobileConnection();
+ turnOffUpstreamMobileConnection();
notifyTetheredOfNewUpstreamIface(null);
}
@Override
@@ -1392,19 +1377,13 @@
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 b7f9d5c..918f1b6 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -77,9 +77,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
} else {
functionList = removeFunction(functionList, UsbManager.USB_FUNCTION_ADB);
}
- setCurrentFunctions(functionList);
+ doSetCurrentFunctions(functionList);
}
private void updateCurrentAccessory() {
@@ -503,8 +513,6 @@
@Override
public void handleMessage(Message msg) {
- String function;
-
switch (msg.what) {
case MSG_UPDATE_STATE:
mConnected = (msg.arg1 == 1);
@@ -518,7 +526,7 @@
if (!mConnected) {
// restore defaults when USB is disconnected
- setCurrentFunctions(mDefaultFunctions);
+ doSetCurrentFunctions(mDefaultFunctions);
}
if (mSystemReady) {
updateUsbState();
@@ -527,20 +535,31 @@
case MSG_ENABLE_ADB:
setAdbEnabled(msg.arg1 == 1);
break;
- case MSG_SET_PRIMARY_FUNCTION:
- function = (String)msg.obj;
- if (function == null) {
- function = mDefaultFunctions;
+ 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);
}
- setEnabledFunctions(function);
- break;
- case MSG_SET_DEFAULT_FUNCTION:
- function = (String)msg.obj;
- if (mAdbEnabled) {
- function = addFunction(function, UsbManager.USB_FUNCTION_ADB);
- }
- SystemProperties.set("persist.sys.usb.config", function);
- mDefaultFunctions = function;
break;
case MSG_SYSTEM_READY:
updateUsbNotification(mConnected);
@@ -588,15 +607,8 @@
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 193638f..9f2c17a 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -146,19 +146,10 @@
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 3be8af6..6806634 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 @@
}
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 @@
// 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 0f09356..50b251f 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/java/com/android/server/wm/Session.java
@@ -153,11 +153,13 @@
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 1c87f5b..d62c031 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -2776,6 +2776,13 @@
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 @@
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 @@
}
}
- 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 @@
}
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 @@
}
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 @@
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 @@
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 587685e..b370ec9 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -111,7 +111,6 @@
* 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 @@
// 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 @@
}
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 a45e879..fb2fc85 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 @@
// Used by DecimalFormatSymbols.
result.zeroDigit = '0';
- result.digit = '0';
result.decimalSeparator = '.';
result.groupingSeparator = ',';
result.patternSeparator = ' ';