diff options
228 files changed, 2927 insertions, 5814 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk index 337b30f0843a..6f9a1e15c5b3 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -90,6 +90,10 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libstagefright_aacdec_intermediates) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libstagefright_mp3dec_intermediates) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/ImageProcessing_intermediates/) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/ModelViewer_intermediates/) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/PerfTest_intermediates/) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/RSTest_intermediates/) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST diff --git a/api/current.xml b/api/current.xml index c4fc0e470c56..a36f0665498b 100644 --- a/api/current.xml +++ b/api/current.xml @@ -35340,6 +35340,17 @@ visibility="public" > </field> +<field name="EXTRA_NEW_SEARCH" + type="java.lang.String" + transient="false" + volatile="false" + value=""new_search"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="EXTRA_SELECT_QUERY" type="java.lang.String" transient="false" @@ -156122,6 +156133,17 @@ visibility="public" > </field> +<field name="EXTRA_CREATE_NEW_TAB" + type="java.lang.String" + transient="false" + volatile="false" + value=""create_new_tab"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="EXTRA_HEADERS" type="java.lang.String" transient="false" diff --git a/core/java/android/animation/package.html b/core/java/android/animation/package.html index ff4326092c41..92eeb20c96be 100644 --- a/core/java/android/animation/package.html +++ b/core/java/android/animation/package.html @@ -15,7 +15,7 @@ behaviors.</p> <p> For a guide on how to use the property animation system, see the -<a href="{@docRoot}guide/topics/media/index.html">Animation</a> developer guide. +<a href="{@docRoot}guide/topics/graphics/animation.html">Animation</a> developer guide. </p> </body> </html> diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index a660076b4b03..77dc08486810 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -30,11 +30,17 @@ import android.os.RemoteException; import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; +import android.os.ServiceManager; import android.os.SystemProperties; import android.text.TextUtils; import android.util.DisplayMetrics; +import android.util.Log; +import com.android.internal.app.IUsageStats; +import com.android.internal.os.PkgUsageStats; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Interact with the overall activities running in the system. @@ -1233,4 +1239,29 @@ public class ActivityManager { public static boolean isRunningInTestHarness() { return SystemProperties.getBoolean("ro.test_harness", false); } + + /** + * Returns the launch count of each installed package. + * + * @hide + */ + public Map<String, Integer> getAllPackageLaunchCounts() { + try { + IUsageStats usageStatsService = IUsageStats.Stub.asInterface( + ServiceManager.getService("usagestats")); + if (usageStatsService == null) { + return new HashMap<String, Integer>(); + } + + Map<String, Integer> launchCounts = new HashMap<String, Integer>(); + for (PkgUsageStats pkgUsageStats : usageStatsService.getAllPkgUsageStats()) { + launchCounts.put(pkgUsageStats.packageName, pkgUsageStats.launchCount); + } + + return launchCounts; + } catch (RemoteException e) { + Log.w(TAG, "Could not query launch counts", e); + return new HashMap<String, Integer>(); + } + } } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 4370ebf93c28..ccd65dee36dd 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -82,6 +82,7 @@ public class Notification implements Parcelable /** * The resource id of a drawable to use as the icon in the status bar. + * This is required; notifications with an invalid icon resource will not be shown. */ public int icon; diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index e3242c102379..6541c54edb5f 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -83,12 +83,14 @@ public class NotificationManager } /** - * Persistent notification on the status bar, + * Post a notification to be shown in the status bar. If a notification with + * the same id has already been posted by your application and has not yet been canceled, it + * will be replaced by the updated information. * * @param id An identifier for this notification unique within your * application. - * @param notification A {@link Notification} object describing how to - * notify the user, other than the view you're providing. Must not be null. + * @param notification A {@link Notification} object describing what to show the user. Must not + * be null. */ public void notify(int id, Notification notification) { @@ -96,13 +98,15 @@ public class NotificationManager } /** - * Persistent notification on the status bar, + * Post a notification to be shown in the status bar. If a notification with + * the same tag and id has already been posted by your application and has not yet been + * canceled, it will be replaced by the updated information. * * @param tag A string identifier for this notification. May be {@code null}. * @param id An identifier for this notification. The pair (tag, id) must be unique * within your application. - * @param notification A {@link Notification} object describing how to - * notify the user, other than the view you're providing. Must not be null. + * @param notification A {@link Notification} object describing what to + * show the user. Must not be null. */ public void notify(String tag, int id, Notification notification) { diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index 671501255e28..aab087fcf54f 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -138,6 +138,12 @@ public class SearchManager public final static String EXTRA_SELECT_QUERY = "select_query"; /** + * Boolean extra data key for {@link Intent#ACTION_WEB_SEARCH} intents. If {@code true}, + * this search should open a new browser window, rather than using an existing one. + */ + public final static String EXTRA_NEW_SEARCH = "new_search"; + + /** * Boolean extra data key for a suggestion provider to return in {@link Cursor#getExtras} to * indicate that the search is not complete yet. This can be used by the search UI * to indicate that a search is in progress. The suggestion provider can return partial results diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 1f4fe801e638..e1c904420a38 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -1052,6 +1052,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.INPUT_DEVICE) { BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener); return true; + } else if (profile == BluetoothProfile.PAN) { + BluetoothPan pan = new BluetoothPan(context, listener); + return true; } else { return false; } diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java index 1f07349b4c13..9ffed26f4acb 100644 --- a/core/java/android/bluetooth/BluetoothPan.java +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -27,187 +27,261 @@ import android.util.Log; import java.util.ArrayList; import java.util.List; + /** - * @hide + * This class provides the APIs to control the Bluetooth Pan + * Profile. + * + *<p>BluetoothPan is a proxy object for controlling the Bluetooth + * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get + * the BluetoothPan proxy object. + * + *<p>Each method is protected with its appropriate permission. + *@hide */ -public final class BluetoothPan { +public final class BluetoothPan implements BluetoothProfile { private static final String TAG = "BluetoothPan"; private static final boolean DBG = false; - //TODO: This needs to inherit from BluetoothProfile like other profiles. - - /** int extra for ACTION_PAN_STATE_CHANGED */ - public static final String EXTRA_PAN_STATE = "android.bluetooth.pan.extra.STATE"; - - /** int extra for ACTION_PAN_STATE_CHANGED */ - public static final String EXTRA_PREVIOUS_PAN_STATE = - "android.bluetooth.pan.extra.PREVIOUS_STATE"; + /** + * Intent used to broadcast the change in connection state of the Pan + * profile. + * + * <p>This intent will have 4 extras: + * <ul> + * <li> {@link #EXTRA_STATE} - The current state of the profile. </li> + * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li> + * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> + * <li> {@link #EXTRA_LOCAL_ROLE} - Which local role the remote device is + * bound to. </li> + * </ul> + * + * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of + * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, + * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. + * + * <p> {@link #EXTRA_LOCAL_ROLE} can be one of {@link #LOCAL_NAP_ROLE} or + * {@link #LOCAL_PANU_ROLE} + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to + * receive. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_CONNECTION_STATE_CHANGED = + "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED"; - /** int extra for ACTION_PAN_STATE_CHANGED */ + /** + * Extra for {@link #ACTION_CONNECTION_STATE_CHANGED} intent + * The local role of the PAN profile that the remote device is bound to. + * It can be one of {@link #LOCAL_NAP_ROLE} or {@link #LOCAL_PANU_ROLE}. + */ public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE"; + /** + * The local device is acting as a Network Access Point. + */ public static final int LOCAL_NAP_ROLE = 1; - public static final int LOCAL_PANU_ROLE = 2; /** - * Indicates the state of an PAN device has changed. - * This intent will always contain EXTRA_DEVICE_STATE, - * EXTRA_PREVIOUS_DEVICE_STATE, BluetoothDevice.EXTRA_DEVICE - * and EXTRA_LOCAL_ROLE. - * extras. + * The local device is acting as a PAN User. */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_PAN_STATE_CHANGED = - "android.bluetooth.pan.action.STATE_CHANGED"; - - public static final String NAP_ROLE = "nap"; - public static final String NAP_BRIDGE = "pan1"; - - public static final int MAX_CONNECTIONS = 7; - - public static final int STATE_DISCONNECTED = 0; - public static final int STATE_CONNECTING = 1; - public static final int STATE_CONNECTED = 2; - public static final int STATE_DISCONNECTING = 3; + public static final int LOCAL_PANU_ROLE = 2; /** * Return codes for the connect and disconnect Bluez / Dbus calls. + * @hide */ public static final int PAN_DISCONNECT_FAILED_NOT_CONNECTED = 1000; + /** + * @hide + */ public static final int PAN_CONNECT_FAILED_ALREADY_CONNECTED = 1001; + /** + * @hide + */ public static final int PAN_CONNECT_FAILED_ATTEMPT_FAILED = 1002; + /** + * @hide + */ public static final int PAN_OPERATION_GENERIC_FAILURE = 1003; + /** + * @hide + */ public static final int PAN_OPERATION_SUCCESS = 1004; - private final IBluetooth mService; - private final Context mContext; + private ServiceListener mServiceListener; + private BluetoothAdapter mAdapter; + private IBluetooth mService; /** * Create a BluetoothPan proxy object for interacting with the local - * Bluetooth Pan service. - * @param c Context + * Bluetooth Service which handles the Pan profile + * */ - public BluetoothPan(Context c) { - mContext = c; - + /*package*/ BluetoothPan(Context mContext, ServiceListener l) { IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE); + mServiceListener = l; + mAdapter = BluetoothAdapter.getDefaultAdapter(); if (b != null) { mService = IBluetooth.Stub.asInterface(b); + if (mServiceListener != null) { + mServiceListener.onServiceConnected(BluetoothProfile.PAN, this); + } } else { Log.w(TAG, "Bluetooth Service not available!"); // Instead of throwing an exception which prevents people from going - // into Wireless settings in the emulator. Let it crash later - // when it is actually used. + // into Wireless settings in the emulator. Let it crash later when it is actually used. mService = null; } } /** - * Initiate a PAN connection. - * - * This function returns false on error and true if the connection - * attempt is being made. - * - * Listen for {@link #ACTION_PAN_STATE_CHANGED} to find out when the - * connection is completed. - * - * @param device Remote BT device. - * @return false on immediate error, true otherwise + * {@inheritDoc} * @hide */ public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); - try { - return mService.connectPanDevice(device); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.connectPanDevice(device); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; } /** - * Initiate disconnect from PAN. - * - * This function return false on error and true if the disconnection - * attempt is being made. - * - * Listen for {@link #ACTION_PAN_STATE_CHANGED} to find out when - * disconnect is completed. - * - * @param device Remote BT device. - * @return false on immediate error, true otherwise + * {@inheritDoc} * @hide */ public boolean disconnect(BluetoothDevice device) { if (DBG) log("disconnect(" + device + ")"); - try { - return mService.disconnectPanDevice(device); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.disconnectPanDevice(device); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; } /** - * Get the state of a PAN Device. - * - * This function returns an int representing the state of the PAN connection - * - * @param device Remote BT device. - * @return The current state of the PAN Device - * @hide + * {@inheritDoc} */ - public int getPanDeviceState(BluetoothDevice device) { - if (DBG) log("getPanDeviceState(" + device + ")"); - try { - return mService.getPanDeviceState(device); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return STATE_DISCONNECTED; + public List<BluetoothDevice> getConnectedDevices() { + if (DBG) log("getConnectedDevices()"); + if (mService != null && isEnabled()) { + try { + return mService.getConnectedPanDevices(); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); } /** - * Returns a set of all the connected PAN Devices - * - * Does not include devices that are currently connecting or disconnecting - * - * @return List of PAN devices or empty on Error + * {@inheritDoc} + */ + public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { + if (DBG) log("getDevicesMatchingStates()"); + if (mService != null && isEnabled()) { + try { + return mService.getPanDevicesMatchingConnectionStates(states); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); + } + + /** + * {@inheritDoc} + */ + public int getConnectionState(BluetoothDevice device) { + if (DBG) log("getState(" + device + ")"); + if (mService != null && isEnabled() + && isValidDevice(device)) { + try { + return mService.getPanDeviceConnectionState(device); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return BluetoothProfile.STATE_DISCONNECTED; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return BluetoothProfile.STATE_DISCONNECTED; + } + + /** + * {@inheritDoc} * @hide */ - public List<BluetoothDevice> getConnectedDevices() { - if (DBG) log("getConnectedDevices"); - try { - return mService.getConnectedPanDevices(); - } catch (RemoteException e) { - Log.e(TAG, "", e); - return new ArrayList<BluetoothDevice>(); - } + public boolean setPriority(BluetoothDevice device, int priority) { + // Priorities are not supported for PAN devices - since we don't + // auto connect. + return false; } - private static void log(String msg) { - Log.d(TAG, msg); + /** + * {@inheritDoc} + * @hide + */ + public int getPriority(BluetoothDevice device) { + if (DBG) log("getPriority(" + device + ")"); + // Priorities are not supported for PAN devices - since we don't + // auto connect. + return BluetoothProfile.PRIORITY_ON; } public void setBluetoothTethering(boolean value) { + if (DBG) log("setBluetoothTethering(" + value + ")"); try { mService.setBluetoothTethering(value); } catch (RemoteException e) { - Log.e(TAG, "", e); + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); } } public boolean isTetheringOn() { + if (DBG) log("isTetheringOn()"); try { return mService.isTetheringOn(); } catch (RemoteException e) { - Log.e(TAG, "", e); + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return false; } } -} + + private boolean isEnabled() { + if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; + return false; + } + + private boolean isValidDevice(BluetoothDevice device) { + if (device == null) return false; + + if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; + return false; + } + + private static void log(String msg) { + Log.d(TAG, msg); + } +}
\ No newline at end of file diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index 1ffee7205395..1ad66f71b938 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -58,10 +58,12 @@ public interface BluetoothProfile { * Headset and Handsfree profile */ public static final int HEADSET = 1; + /** * A2DP profile. */ public static final int A2DP = 2; + /** * Input Device Profile * @hide @@ -69,6 +71,12 @@ public interface BluetoothProfile { public static final int INPUT_DEVICE = 3; /** + * PAN Profile + * @hide + */ + public static final int PAN = 4; + + /** * Default priority for devices that we try to auto-connect to and * and allow incoming connections for the profile * @hide diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java index aa1adcbbc2a8..c08f14f3f81f 100644 --- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java +++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java @@ -96,17 +96,32 @@ public class BluetoothTetheringDataTracker implements NetworkStateTracker { public void startMonitoring(Context context, Handler target) { mContext = context; mCsHandler = target; - mBluetoothPan = new BluetoothPan(mContext); + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + if (adapter != null) { + adapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.PAN); + } } + private BluetoothProfile.ServiceListener mProfileServiceListener = + new BluetoothProfile.ServiceListener() { + public void onServiceConnected(int profile, BluetoothProfile proxy) { + mBluetoothPan = (BluetoothPan) proxy; + } + public void onServiceDisconnected(int profile) { + mBluetoothPan = null; + } + }; + /** * Disable connectivity to a network * TODO: do away with return value after making MobileDataStateTracker async */ public boolean teardown() { mTeardownRequested.set(true); - for (BluetoothDevice device: mBluetoothPan.getConnectedDevices()) { - mBluetoothPan.disconnect(device); + if (mBluetoothPan != null) { + for (BluetoothDevice device: mBluetoothPan.getConnectedDevices()) { + mBluetoothPan.disconnect(device); + } } return true; } diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl index 69fb06a0f7b0..d25f5d0cb336 100644 --- a/core/java/android/bluetooth/IBluetooth.aidl +++ b/core/java/android/bluetooth/IBluetooth.aidl @@ -92,8 +92,9 @@ interface IBluetooth boolean isTetheringOn(); void setBluetoothTethering(boolean value); - int getPanDeviceState(in BluetoothDevice device); + int getPanDeviceConnectionState(in BluetoothDevice device); List<BluetoothDevice> getConnectedPanDevices(); + List<BluetoothDevice> getPanDevicesMatchingConnectionStates(in int[] states); boolean connectPanDevice(in BluetoothDevice device); boolean disconnectPanDevice(in BluetoothDevice device); diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index c2f3ae70b8b2..d8a5b45c9cda 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -508,23 +508,86 @@ public class Camera { * finish processing the data in them. * * <p>The size of the buffer is determined by multiplying the preview - * image width, height, and bytes per pixel. The width and height can be - * read from {@link Camera.Parameters#getPreviewSize()}. Bytes per pixel + * image width, height, and bytes per pixel. The width and height can be + * read from {@link Camera.Parameters#getPreviewSize()}. Bytes per pixel * can be computed from * {@link android.graphics.ImageFormat#getBitsPerPixel(int)} / 8, * using the image format from {@link Camera.Parameters#getPreviewFormat()}. * * <p>This method is only necessary when - * {@link #setPreviewCallbackWithBuffer(PreviewCallback)} is used. When + * {@link #setPreviewCallbackWithBuffer(PreviewCallback)} is used. When * {@link #setPreviewCallback(PreviewCallback)} or * {@link #setOneShotPreviewCallback(PreviewCallback)} are used, buffers - * are automatically allocated. + * are automatically allocated. When a supplied buffer is too small to + * hold the preview frame data, preview callback will return null and + * the buffer will be removed from the buffer queue. * * @param callbackBuffer the buffer to add to the queue. * The size should be width * height * bits_per_pixel / 8. * @see #setPreviewCallbackWithBuffer(PreviewCallback) */ - public native final void addCallbackBuffer(byte[] callbackBuffer); + public final void addCallbackBuffer(byte[] callbackBuffer) + { + _addCallbackBuffer(callbackBuffer, CAMERA_MSG_PREVIEW_FRAME); + } + + /** + * Adds a pre-allocated buffer to the raw image callback buffer queue. + * Applications can add one or more buffers to the queue. When a raw image + * frame arrives and there is still at least one available buffer, the + * buffer will be used to hold the raw image data and removed from the + * queue. Then raw image callback is invoked with the buffer. If a raw + * image frame arrives but there is no buffer left, the frame is + * discarded. Applications should add buffers back when they finish + * processing the data in them by calling this method again in order + * to avoid running out of raw image callback buffers. + * + * <p>The size of the buffer is determined by multiplying the raw image + * width, height, and bytes per pixel. The width and height can be + * read from {@link Camera.Parameters#getPictureSize()}. Bytes per pixel + * can be computed from + * {@link android.graphics.ImageFormat#getBitsPerPixel(int)} / 8, + * using the image format from {@link Camera.Parameters#getPreviewFormat()}. + * + * <p>This method is only necessary when the PictureCallbck for raw image + * is used while calling {@link #takePicture(Camera.ShutterCallback, + * Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)}. + * + * Please note that by calling this method, the mode for application-managed + * callback buffers is triggered. If this method has never been called, + * null will be returned by the raw image callback since there is + * no image callback buffer available. Furthermore, When a supplied buffer + * is too small to hold the raw image data, raw image callback will return + * null and the buffer will be removed from the buffer queue. + * + * @param callbackBuffer the buffer to add to the raw image callback buffer + * queue. The size should be width * height * (bits per pixel) / 8. An + * null callbackBuffer will be ignored and won't be added to the queue. + * + * @see #takePicture(Camera.ShutterCallback, + * Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)}. + * + * {@hide} + */ + public final void addRawImageCallbackBuffer(byte[] callbackBuffer) + { + addCallbackBuffer(callbackBuffer, CAMERA_MSG_RAW_IMAGE); + } + + private final void addCallbackBuffer(byte[] callbackBuffer, int msgType) + { + // CAMERA_MSG_VIDEO_FRAME may be allowed in the future. + if (msgType != CAMERA_MSG_PREVIEW_FRAME && + msgType != CAMERA_MSG_RAW_IMAGE) { + throw new IllegalArgumentException( + "Unsupported message type: " + msgType); + } + + _addCallbackBuffer(callbackBuffer, msgType); + } + + private native final void _addCallbackBuffer( + byte[] callbackBuffer, int msgType); private class EventHandler extends Handler { @@ -735,7 +798,7 @@ public class Camera { PictureCallback jpeg) { takePicture(shutter, raw, null, jpeg); } - private native final void native_takePicture(); + private native final void native_takePicture(int msgType); /** * Triggers an asynchronous image capture. The camera service will initiate @@ -743,7 +806,8 @@ public class Camera { * The shutter callback occurs after the image is captured. This can be used * to trigger a sound to let the user know that image has been captured. The * raw callback occurs when the raw image data is available (NOTE: the data - * may be null if the hardware does not have enough memory to make a copy). + * will be null if there is no raw image callback buffer available or the + * raw image callback buffer is not large enough to hold the raw image). * The postview callback occurs when a scaled, fully processed postview * image is available (NOTE: not all hardware supports this). The jpeg * callback occurs when the compressed image is available. If the @@ -762,6 +826,8 @@ public class Camera { * @param raw the callback for raw (uncompressed) image data, or null * @param postview callback with postview image data, may be null * @param jpeg the callback for JPEG image data, or null + * + * @see #addRawImageCallbackBuffer(byte[]) */ public final void takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback postview, PictureCallback jpeg) { @@ -769,7 +835,23 @@ public class Camera { mRawImageCallback = raw; mPostviewCallback = postview; mJpegCallback = jpeg; - native_takePicture(); + + // If callback is not set, do not send me callbacks. + int msgType = 0; + if (mShutterCallback != null) { + msgType |= CAMERA_MSG_SHUTTER; + } + if (mRawImageCallback != null) { + msgType |= CAMERA_MSG_RAW_IMAGE; + } + if (mPostviewCallback != null) { + msgType |= CAMERA_MSG_POSTVIEW_FRAME; + } + if (mJpegCallback != null) { + msgType |= CAMERA_MSG_COMPRESSED_IMAGE; + } + + native_takePicture(msgType); } /** diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java index 8c55bf33788b..78d7991796b9 100644 --- a/core/java/android/hardware/SensorEvent.java +++ b/core/java/android/hardware/SensorEvent.java @@ -122,13 +122,13 @@ public class SensorEvent { * * final float alpha = 0.8; * - * gravity[0] = alpha * gravity[0] + (1 - alpha) * event.data[0]; - * gravity[1] = alpha * gravity[1] + (1 - alpha) * event.data[1]; - * gravity[2] = alpha * gravity[2] + (1 - alpha) * event.data[2]; + * gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0]; + * gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1]; + * gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2]; * - * linear_acceleration[0] = event.data[0] - gravity[0]; - * linear_acceleration[1] = event.data[1] - gravity[1]; - * linear_acceleration[2] = event.data[2] - gravity[2]; + * linear_acceleration[0] = event.values[0] - gravity[0]; + * linear_acceleration[1] = event.values[1] - gravity[1]; + * linear_acceleration[2] = event.values[2] - gravity[2]; * } * </pre> * @@ -186,9 +186,9 @@ public class SensorEvent { * { * if (timestamp != 0) { * final float dT = (event.timestamp - timestamp) * NS2S; - * angle[0] += event.data[0] * dT; - * angle[1] += event.data[1] * dT; - * angle[2] += event.data[2] * dT; + * angle[0] += event.values[0] * dT; + * angle[1] += event.values[1] * dT; + * angle[2] += event.values[2] * dT; * } * timestamp = event.timestamp; * } diff --git a/core/java/android/pim/ICalendar.java b/core/java/android/pim/ICalendar.java index cc0f45ee2402..9c4eaf4f5765 100644 --- a/core/java/android/pim/ICalendar.java +++ b/core/java/android/pim/ICalendar.java @@ -578,6 +578,23 @@ public class ICalendar { + text); } parameter.name = text.substring(startIndex + 1, equalIndex); + } else if (c == '"') { + if (parameter == null) { + throw new FormatException("Expected parameter before '\"' in " + text); + } + if (equalIndex == -1) { + throw new FormatException("Expected '=' within parameter in " + text); + } + if (state.index > equalIndex + 1) { + throw new FormatException("Parameter value cannot contain a '\"' in " + text); + } + final int endQuote = text.indexOf('"', state.index + 1); + if (endQuote < 0) { + throw new FormatException("Expected closing '\"' in " + text); + } + parameter.value = text.substring(state.index + 1, endQuote); + state.index = endQuote + 1; + return parameter; } ++state.index; } diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java index 3bfd005d2058..57ee440755cd 100644 --- a/core/java/android/provider/Browser.java +++ b/core/java/android/provider/Browser.java @@ -139,8 +139,6 @@ public class Browser { public static final int SEARCHES_PROJECTION_SEARCH_INDEX = 1; public static final int SEARCHES_PROJECTION_DATE_INDEX = 2; - private static final String SEARCHES_WHERE_CLAUSE = "search = ?"; - /* Set a cap on the count of history items in the history/bookmark table, to prevent db and layout operations from dragging to a crawl. Revisit this cap when/if db/layout performance @@ -167,6 +165,13 @@ public class Browser { } /** + * Passed along with an Intent to a browser, specifying that a new tab + * be created. Overrides EXTRA_APPLICATION_ID; if both are set, a new tab + * will be used, rather than using the same one. + */ + public static final String EXTRA_CREATE_NEW_TAB = "create_new_tab"; + + /** * Stores a Bitmap extra in an {@link Intent} representing the screenshot of * a page to share. When receiving an {@link Intent#ACTION_SEND} from the * Browser, use this to access the screenshot. diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index b05b078a27d0..4f88612f0e39 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -862,8 +862,9 @@ public final class ContactsContract { } /** - * Types of data used to produce the display name for a contact. Listed in the order - * of increasing priority. + * Types of data used to produce the display name for a contact. In the order + * of increasing priority: {@link #EMAIL}, {@link #PHONE}, + * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_NAME}. */ public interface DisplayNameSources { public static final int UNDEFINED = 0; diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index c0b3cc8fb523..578580a180b1 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -785,7 +785,7 @@ class BluetoothEventLoop { boolean connected = false; BluetoothDevice device = mAdapter.getRemoteDevice(address); - int state = mBluetoothService.getPanDeviceState(device); + int state = mBluetoothService.getPanDeviceConnectionState(device); if (state == BluetoothPan.STATE_CONNECTING) { if (result == BluetoothPan.PAN_CONNECT_FAILED_ALREADY_CONNECTED) { connected = true; diff --git a/core/java/android/server/BluetoothPanProfileHandler.java b/core/java/android/server/BluetoothPanProfileHandler.java index fb964396e4fc..3f24811e2805 100644 --- a/core/java/android/server/BluetoothPanProfileHandler.java +++ b/core/java/android/server/BluetoothPanProfileHandler.java @@ -58,6 +58,9 @@ final class BluetoothPanProfileHandler { private Context mContext; private BluetoothService mBluetoothService; + static final String NAP_ROLE = "nap"; + static final String NAP_BRIDGE = "pan1"; + private BluetoothPanProfileHandler(Context context, BluetoothService service) { mContext = context; mPanDevices = new HashMap<BluetoothDevice, BluetoothPanDevice>(); @@ -114,7 +117,7 @@ final class BluetoothPanProfileHandler { } } - synchronized int getPanDeviceState(BluetoothDevice device) { + synchronized int getPanDeviceConnectionState(BluetoothDevice device) { BluetoothPanDevice panDevice = mPanDevices.get(device); if (panDevice == null) { return BluetoothPan.STATE_DISCONNECTED; @@ -125,13 +128,13 @@ final class BluetoothPanProfileHandler { synchronized boolean connectPanDevice(BluetoothDevice device) { String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress()); if (DBG) Log.d(TAG, "connect PAN(" + objectPath + ")"); - if (getPanDeviceState(device) != BluetoothPan.STATE_DISCONNECTED) { + if (getPanDeviceConnectionState(device) != BluetoothPan.STATE_DISCONNECTED) { errorLog(device + " already connected to PAN"); } int connectedCount = 0; for (BluetoothDevice panDevice: mPanDevices.keySet()) { - if (getPanDeviceState(panDevice) == BluetoothPan.STATE_CONNECTED) { + if (getPanDeviceConnectionState(panDevice) == BluetoothPan.STATE_CONNECTED) { connectedCount ++; } } @@ -187,18 +190,33 @@ final class BluetoothPanProfileHandler { List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); for (BluetoothDevice device: mPanDevices.keySet()) { - if (getPanDeviceState(device) == BluetoothPan.STATE_CONNECTED) { + if (getPanDeviceConnectionState(device) == BluetoothPan.STATE_CONNECTED) { devices.add(device); } } return devices; } + synchronized List<BluetoothDevice> getPanDevicesMatchingConnectionStates(int[] states) { + List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); + + for (BluetoothDevice device: mPanDevices.keySet()) { + int panDeviceState = getPanDeviceConnectionState(device); + for (int state : states) { + if (state == panDeviceState) { + devices.add(device); + break; + } + } + } + return devices; + } + synchronized boolean disconnectPanDevice(BluetoothDevice device) { String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress()); debugLog("disconnect PAN(" + objectPath + ")"); - int state = getPanDeviceState(device); + int state = getPanDeviceConnectionState(device); if (state != BluetoothPan.STATE_CONNECTED) { debugLog(device + " already disconnected from PAN"); return false; @@ -274,14 +292,10 @@ final class BluetoothPanProfileHandler { panDevice.mLocalRole = role; } - if (state == BluetoothPan.STATE_DISCONNECTED) { - mPanDevices.remove(device); - } - - Intent intent = new Intent(BluetoothPan.ACTION_PAN_STATE_CHANGED); + Intent intent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); - intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_PAN_STATE, prevState); - intent.putExtra(BluetoothPan.EXTRA_PAN_STATE, state); + intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_STATE, prevState); + intent.putExtra(BluetoothPan.EXTRA_STATE, state); intent.putExtra(BluetoothPan.EXTRA_LOCAL_ROLE, role); mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM); diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index 70aaf0a009f1..ebe3ef284029 100644 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -85,6 +85,7 @@ public class BluetoothService extends IBluetooth.Stub { private BluetoothEventLoop mEventLoop; private BluetoothHeadset mBluetoothHeadset; private BluetoothInputDevice mInputDevice; + private BluetoothPan mPan; private boolean mIsAirplaneSensitive; private boolean mIsAirplaneToggleable; private int mBluetoothState; @@ -357,7 +358,8 @@ public class BluetoothService extends IBluetooth.Stub { setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF); if (mAdapterSdpHandles != null) removeReservedServiceRecordsNative(mAdapterSdpHandles); - setBluetoothTetheringNative(false, BluetoothPan.NAP_ROLE, BluetoothPan.NAP_BRIDGE); + setBluetoothTetheringNative(false, BluetoothPanProfileHandler.NAP_ROLE, + BluetoothPanProfileHandler.NAP_BRIDGE); // Allow 3 seconds for profiles to gracefully disconnect // TODO: Introduce a callback mechanism so that each profile can notify @@ -606,7 +608,8 @@ public class BluetoothService extends IBluetooth.Stub { addReservedSdpRecords(uuids); // Enable profiles maintained by Bluez userspace. - setBluetoothTetheringNative(true, BluetoothPan.NAP_ROLE, BluetoothPan.NAP_BRIDGE); + setBluetoothTetheringNative(true, BluetoothPanProfileHandler.NAP_ROLE, + BluetoothPanProfileHandler.NAP_BRIDGE); // Add SDP records for profiles maintained by Bluez userspace uuids.add(BluetoothUuid.AudioSource); @@ -2082,6 +2085,8 @@ public class BluetoothService extends IBluetooth.Stub { mBluetoothProfileServiceListener, BluetoothProfile.HEADSET); mAdapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, BluetoothProfile.INPUT_DEVICE); + mAdapter.getProfileProxy(mContext, + mBluetoothProfileServiceListener, BluetoothProfile.PAN); pw.println("\n--Known devices--"); for (String address : mDeviceProperties.keySet()) { @@ -2125,6 +2130,7 @@ public class BluetoothService extends IBluetooth.Stub { dumpHeadsetProfile(pw); dumpInputDeviceProfile(pw); + dumpPanProfile(pw); pw.println("\n--Application Service Records--"); for (Integer handle : mServiceRecordToPid.keySet()) { @@ -2138,10 +2144,10 @@ public class BluetoothService extends IBluetooth.Stub { if (mBluetoothHeadset != null) { List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices(); if (deviceList.size() == 0) { - pw.println("\n--No headsets connected--"); + pw.println("No headsets connected"); } else { BluetoothDevice device = deviceList.get(0); - pw.println("\ngetConnectedDevices[0] = " + device); + pw.println("getConnectedDevices[0] = " + device); switch (mBluetoothHeadset.getConnectionState(device)) { case BluetoothHeadset.STATE_CONNECTING: @@ -2164,7 +2170,7 @@ public class BluetoothService extends IBluetooth.Stub { deviceList.clear(); deviceList = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] { BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED}); - pw.println("\n--Connected and Disconnected Headsets"); + pw.println("--Connected and Disconnected Headsets"); for (BluetoothDevice device: deviceList) { pw.println(device); if (mBluetoothHeadset.isAudioConnected(device)) { @@ -2180,9 +2186,9 @@ public class BluetoothService extends IBluetooth.Stub { if (mInputDevice != null) { List<BluetoothDevice> deviceList = mInputDevice.getConnectedDevices(); if (deviceList.size() == 0) { - pw.println("\nNo input devices connected--"); + pw.println("No input devices connected"); } else { - pw.println("\nNumber of connected devices:" + deviceList.size()); + pw.println("Number of connected devices:" + deviceList.size()); BluetoothDevice device = deviceList.get(0); pw.println("getConnectedDevices[0] = " + device); pw.println("Priority of Connected device = " + mInputDevice.getPriority(device)); @@ -2210,6 +2216,41 @@ public class BluetoothService extends IBluetooth.Stub { mAdapter.closeProfileProxy(BluetoothProfile.INPUT_DEVICE, mBluetoothHeadset); } + private void dumpPanProfile(PrintWriter pw) { + pw.println("\n--Bluetooth Service- Pan Profile"); + if (mPan != null) { + List<BluetoothDevice> deviceList = mPan.getConnectedDevices(); + if (deviceList.size() == 0) { + pw.println("No Pan devices connected"); + } else { + pw.println("Number of connected devices:" + deviceList.size()); + BluetoothDevice device = deviceList.get(0); + pw.println("getConnectedDevices[0] = " + device); + pw.println("Priority of Connected device = " + mPan.getPriority(device)); + + switch (mPan.getConnectionState(device)) { + case BluetoothInputDevice.STATE_CONNECTING: + pw.println("getConnectionState() = STATE_CONNECTING"); + break; + case BluetoothInputDevice.STATE_CONNECTED: + pw.println("getConnectionState() = STATE_CONNECTED"); + break; + case BluetoothInputDevice.STATE_DISCONNECTING: + pw.println("getConnectionState() = STATE_DISCONNECTING"); + break; + } + } + deviceList.clear(); + deviceList = mPan.getDevicesMatchingConnectionStates(new int[] { + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED}); + pw.println("--Connected and Disconnected Pan devices"); + for (BluetoothDevice device: deviceList) { + pw.println(device); + } + } + mAdapter.closeProfileProxy(BluetoothProfile.PAN, mBluetoothHeadset); + } + private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = new BluetoothProfile.ServiceListener() { public void onServiceConnected(int profile, BluetoothProfile proxy) { @@ -2217,6 +2258,8 @@ public class BluetoothService extends IBluetooth.Stub { mBluetoothHeadset = (BluetoothHeadset) proxy; } else if (profile == BluetoothProfile.INPUT_DEVICE) { mInputDevice = (BluetoothInputDevice) proxy; + } else if (profile == BluetoothProfile.PAN) { + mPan = (BluetoothPan) proxy; } } public void onServiceDisconnected(int profile) { @@ -2224,6 +2267,8 @@ public class BluetoothService extends IBluetooth.Stub { mBluetoothHeadset = null; } else if (profile == BluetoothProfile.INPUT_DEVICE) { mInputDevice = null; + } else if (profile == BluetoothProfile.PAN) { + mPan = null; } } }; @@ -2302,9 +2347,9 @@ public class BluetoothService extends IBluetooth.Stub { mBluetoothPanProfileHandler.setBluetoothTethering(value); } - public synchronized int getPanDeviceState(BluetoothDevice device) { + public synchronized int getPanDeviceConnectionState(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - return mBluetoothPanProfileHandler.getPanDeviceState(device); + return mBluetoothPanProfileHandler.getPanDeviceConnectionState(device); } public synchronized boolean connectPanDevice(BluetoothDevice device) { @@ -2318,6 +2363,12 @@ public class BluetoothService extends IBluetooth.Stub { return mBluetoothPanProfileHandler.getConnectedPanDevices(); } + public synchronized List<BluetoothDevice> getPanDevicesMatchingConnectionStates( + int[] states) { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); + return mBluetoothPanProfileHandler.getPanDevicesMatchingConnectionStates(states); + } + public synchronized boolean disconnectPanDevice(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); diff --git a/core/java/android/webkit/SelectActionModeCallback.java b/core/java/android/webkit/SelectActionModeCallback.java index ea09fc0c0ed0..104deb1c82f0 100644 --- a/core/java/android/webkit/SelectActionModeCallback.java +++ b/core/java/android/webkit/SelectActionModeCallback.java @@ -83,6 +83,7 @@ class SelectActionModeCallback implements ActionMode.Callback { case com.android.internal.R.id.websearch: mode.finish(); Intent i = new Intent(Intent.ACTION_WEB_SEARCH); + i.putExtra(SearchManager.EXTRA_NEW_SEARCH, true); i.putExtra(SearchManager.QUERY, mWebView.getSelection()); mWebView.getContext().startActivity(i); break; diff --git a/core/java/android/widget/ListAdapter.java b/core/java/android/widget/ListAdapter.java index 0fd2e7090b46..d8fd1c987bff 100644 --- a/core/java/android/widget/ListAdapter.java +++ b/core/java/android/widget/ListAdapter.java @@ -26,10 +26,14 @@ package android.widget; public interface ListAdapter extends Adapter { /** - * Are all items in this ListAdapter enabled? - * If yes it means all items are selectable and clickable. + * Indicates whether all the items in this adapter are enabled. If the + * value returned by this method changes over time, there is no guarantee + * it will take effect. If true, it means all items are selectable and + * clickable (there is no separator.) * - * @return True if all items are enabled + * @return True if all items are enabled, false otherwise. + * + * @see #isEnabled(int) */ public boolean areAllItemsEnabled(); @@ -41,7 +45,10 @@ public interface ListAdapter extends Adapter { * should be thrown in that case for fast failure. * * @param position Index of the item + * * @return True if the item is not a separator + * + * @see #areAllItemsEnabled() */ boolean isEnabled(int position); } diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 4b858d0dd154..9002b1ddaf8a 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -378,8 +378,7 @@ public class PopupWindow { * <p>Change the popup's content. The content is represented by an instance * of {@link android.view.View}.</p> * - * <p>This method has no effect if called when the popup is showing. To - * apply it while a popup is showing, call </p> + * <p>This method has no effect if called when the popup is showing.</p> * * @param contentView the new content for the popup * @@ -1040,7 +1039,7 @@ public class PopupWindow { * * @return true if the popup is translated upwards to fit on screen */ - private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p, + boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p, int xoff, int yoff) { anchor.getLocationInWindow(mDrawingLocation); @@ -1374,6 +1373,7 @@ public class PopupWindow { * height can be set to -1 to update location only. Calling this function * also updates the window with the current popup state as * described for {@link #update()}.</p> + * * <p>If the view later scrolls to move <code>anchor</code> to a different * location, the popup will be moved correspondingly.</p> * @@ -1395,9 +1395,13 @@ public class PopupWindow { } WeakReference<View> oldAnchor = mAnchor; - if (oldAnchor == null || oldAnchor.get() != anchor || - (updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff))) { + final boolean needsUpdate = updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff); + if (oldAnchor == null || oldAnchor.get() != anchor || (needsUpdate && !mIsDropdown)) { registerForScrollChanged(anchor, xoff, yoff); + } else if (needsUpdate) { + // No need to register again if this is a DropDown, showAsDropDown already did. + mAnchorXoff = xoff; + mAnchorYoff = yoff; } WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams(); diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index ef4e4e0a18a9..cf72ec40f604 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -701,8 +701,8 @@ public class ProgressBar extends View { if (mProgress > max) { mProgress = max; - refreshProgress(R.id.progress, mProgress, false); } + refreshProgress(R.id.progress, mProgress, false); } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index c4d95b26c9ea..6791a1d22e46 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -3873,9 +3873,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private void registerForPreDraw() { final ViewTreeObserver observer = getViewTreeObserver(); - if (observer == null) { - return; - } if (mPreDrawState == PREDRAW_NOT_REGISTERED) { observer.addOnPreDrawListener(this); @@ -3961,15 +3958,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } final ViewTreeObserver observer = getViewTreeObserver(); - if (observer != null) { - // No need to create the controller. - // The get method will add the listener on controller creation. - if (mInsertionPointCursorController != null) { - observer.addOnTouchModeChangeListener(mInsertionPointCursorController); - } - if (mSelectionModifierCursorController != null) { - observer.addOnTouchModeChangeListener(mSelectionModifierCursorController); - } + // No need to create the controller. + // The get method will add the listener on controller creation. + if (mInsertionPointCursorController != null) { + observer.addOnTouchModeChangeListener(mInsertionPointCursorController); + } + if (mSelectionModifierCursorController != null) { + observer.addOnTouchModeChangeListener(mSelectionModifierCursorController); } } @@ -3978,18 +3973,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener super.onDetachedFromWindow(); final ViewTreeObserver observer = getViewTreeObserver(); - if (observer != null) { - if (mPreDrawState != PREDRAW_NOT_REGISTERED) { - observer.removeOnPreDrawListener(this); - mPreDrawState = PREDRAW_NOT_REGISTERED; - } - // No need to create the controller, as getXXController would. - if (mInsertionPointCursorController != null) { - observer.removeOnTouchModeChangeListener(mInsertionPointCursorController); - } - if (mSelectionModifierCursorController != null) { - observer.removeOnTouchModeChangeListener(mSelectionModifierCursorController); - } + if (mPreDrawState != PREDRAW_NOT_REGISTERED) { + observer.removeOnPreDrawListener(this); + mPreDrawState = PREDRAW_NOT_REGISTERED; + } + // No need to create the controller, as getXXController would. + if (mInsertionPointCursorController != null) { + observer.removeOnTouchModeChangeListener(mInsertionPointCursorController); + } + if (mSelectionModifierCursorController != null) { + observer.removeOnTouchModeChangeListener(mSelectionModifierCursorController); } if (mError != null) { @@ -4290,10 +4283,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mPreDrawState == PREDRAW_DONE) { final ViewTreeObserver observer = getViewTreeObserver(); - if (observer != null) { - observer.removeOnPreDrawListener(this); - mPreDrawState = PREDRAW_NOT_REGISTERED; - } + observer.removeOnPreDrawListener(this); + mPreDrawState = PREDRAW_NOT_REGISTERED; } int color = mCurTextColor; @@ -5541,8 +5532,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener ellipsisWidth); } else { if (boring == UNKNOWN_BORING) { - boring = BoringLayout.isBoring(mTransformed, mTextPaint, - mBoring); + boring = BoringLayout.isBoring(mTransformed, mTextPaint, mBoring); if (boring != null) { mBoring = boring; } @@ -8655,9 +8645,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - private class HandleView extends View { + private class HandleView extends View implements ViewTreeObserver.OnScrollChangedListener { private Drawable mDrawable; - private final PopupWindow mContainer; + private final ScrollingPopupWindow mContainer; private int mPositionX; private int mPositionY; private final CursorController mController; @@ -8726,7 +8716,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public HandleView(CursorController controller, int pos) { super(TextView.this.mContext); mController = controller; - mContainer = new PopupWindow(TextView.this.mContext, null, + mContainer = new ScrollingPopupWindow(TextView.this.mContext, null, com.android.internal.R.attr.textSelectHandleWindowStyle); mContainer.setSplitTouchEnabled(true); mContainer.setClippingEnabled(false); @@ -8794,24 +8784,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return; } mContainer.setContentView(this); - final int[] coords = mTempCoords; - TextView.this.getLocationInWindow(coords); - mContainerPositionX = coords[0] + mPositionX; - mContainerPositionY = coords[1] + mPositionY; - mContainer.showAtLocation(TextView.this, 0, mContainerPositionX, mContainerPositionY); + mContainerPositionX = mPositionX; + mContainerPositionY = mPositionY - TextView.this.getHeight(); + mContainer.showAsDropDown(TextView.this, mContainerPositionX, mContainerPositionY); // Hide paste view when handle is moved on screen. - if (mPastePopupWindow != null) { - mPastePopupWindow.hide(); - } + hidePastePopupWindow(); } public void hide() { mIsDragging = false; mContainer.dismiss(); - if (mPastePopupWindow != null) { - mPastePopupWindow.hide(); - } + hidePastePopupWindow(); } public boolean isShowing() { @@ -8834,19 +8818,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int compoundPaddingRight = getCompoundPaddingRight(); final TextView hostView = TextView.this; - final int left = 0; - final int right = hostView.getWidth(); - final int top = 0; - final int bottom = hostView.getHeight(); if (mTempRect == null) { mTempRect = new Rect(); } final Rect clip = mTempRect; - clip.left = left + compoundPaddingLeft; - clip.top = top + extendedPaddingTop; - clip.right = right - compoundPaddingRight; - clip.bottom = bottom - extendedPaddingBottom; + clip.left = compoundPaddingLeft; + clip.top = extendedPaddingTop; + clip.right = hostView.getWidth() - compoundPaddingRight; + clip.bottom = hostView.getHeight() - extendedPaddingBottom; final ViewParent parent = hostView.getParent(); if (parent == null || !parent.getChildVisibleRect(hostView, clip, null)) { @@ -8858,7 +8838,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int posX = coords[0] + mPositionX + (int) mHotspotX; final int posY = coords[1] + mPositionY + (int) mHotspotY; - return posX >= clip.left && posX <= clip.right && + // Offset by 1 to take into account 0.5 and int rounding around getPrimaryHorizontal. + return posX >= clip.left - 1 && posX <= clip.right + 1 && posY >= clip.top && posY <= clip.bottom; } @@ -8868,23 +8849,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (isPositionVisible()) { int[] coords = null; if (mContainer.isShowing()) { - coords = mTempCoords; - TextView.this.getLocationInWindow(coords); - final int containerPositionX = coords[0] + mPositionX; - final int containerPositionY = coords[1] + mPositionY; + final int containerPositionX = mPositionX; + final int containerPositionY = mPositionY - TextView.this.getHeight(); if (containerPositionX != mContainerPositionX || containerPositionY != mContainerPositionY) { mContainerPositionX = containerPositionX; mContainerPositionY = containerPositionY; - mContainer.update(mContainerPositionX, mContainerPositionY, + mContainer.update(TextView.this, mContainerPositionX, mContainerPositionY, mRight - mLeft, mBottom - mTop); // Hide paste popup window as soon as a scroll occurs. - if (mPastePopupWindow != null) { - mPastePopupWindow.hide(); - } + hidePastePopupWindow(); } } else { show(); @@ -8902,9 +8879,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mLastParentY = coords[1]; } // Hide paste popup window as soon as the handle is dragged. - if (mPastePopupWindow != null) { - mPastePopupWindow.hide(); - } + hidePastePopupWindow(); } } else { hide(); @@ -9008,10 +8983,60 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mPastePopupWindow.show(); } } + + void hidePastePopupWindow() { + if (mPastePopupWindow != null) { + mPastePopupWindow.hide(); + } + } + + /** + * A popup window, attached to a view, and that listens to scroll events in its anchors' + * view hierarchy, so that it is automatically moved on such events. + */ + private class ScrollingPopupWindow extends PopupWindow { + + private int[] mDrawingLocations = new int[2]; + + public ScrollingPopupWindow(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p, + int xoff, int yoff) { + anchor.getLocationInWindow(mDrawingLocations); + p.x = mDrawingLocations[0] + xoff; + p.y = mDrawingLocations[1] + anchor.getHeight() + yoff; + + // Hide paste popup as soon as the view is scrolled. + hidePastePopupWindow(); + + if (!isPositionVisible()) { + dismiss(); + onHandleBecomeInvisible(); + } + + return false; + } + } + + public void onScrollChanged() { + if (isPositionVisible()) { + show(); + ViewTreeObserver vto = TextView.this.getViewTreeObserver(); + vto.removeOnScrollChangedListener(this); + } + } + + public void onHandleBecomeInvisible() { + ViewTreeObserver vto = TextView.this.getViewTreeObserver(); + vto.addOnScrollChangedListener(this); + } } private class InsertionPointCursorController implements CursorController { - private static final int DELAY_BEFORE_FADE_OUT = 4100; + private static final int DELAY_BEFORE_FADE_OUT = 4000; private static final int DELAY_BEFORE_PASTE = 2000; private static final int RECENT_CUT_COPY_DURATION = 15 * 1000; @@ -9027,7 +9052,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public void show(int delayBeforePaste) { updatePosition(); hideDelayed(); - getHandle().show(); removePastePopupCallback(); final long durationSinceCutOrCopy = SystemClock.uptimeMillis() - sLastCutOrCopyTime; if (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION) { @@ -9547,9 +9571,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mInsertionPointCursorController = new InsertionPointCursorController(); final ViewTreeObserver observer = getViewTreeObserver(); - if (observer != null) { - observer.addOnTouchModeChangeListener(mInsertionPointCursorController); - } + observer.addOnTouchModeChangeListener(mInsertionPointCursorController); } return mInsertionPointCursorController; @@ -9564,9 +9586,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mSelectionModifierCursorController = new SelectionModifierCursorController(); final ViewTreeObserver observer = getViewTreeObserver(); - if (observer != null) { - observer.addOnTouchModeChangeListener(mSelectionModifierCursorController); - } + observer.addOnTouchModeChangeListener(mSelectionModifierCursorController); } return mSelectionModifierCursorController; diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp index 147e1fa2e3a0..e9576351dcfe 100644 --- a/core/jni/android/graphics/TextLayout.cpp +++ b/core/jni/android/graphics/TextLayout.cpp @@ -23,6 +23,8 @@ #include "unicode/ushape.h" #include <utils/Log.h> +// Log debug messages from RTL related allocations +#define DEBUG_RTL_ALLOCATIONS 0 namespace android { // Returns true if we might need layout. If bidiFlags force LTR, assume no layout, if @@ -38,7 +40,7 @@ bool TextLayout::needsLayout(const jchar* text, jint len, jint bidiFlags) { return true; } for (int i = 0; i < len; ++i) { - if (text[i] >= 0x0590) { + if (text[i] >= UNICODE_FIRST_RTL_CHAR) { return true; } } @@ -59,7 +61,12 @@ bool TextLayout::needsLayout(const jchar* text, jint len, jint bidiFlags) { */ int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount, jchar* shaped, UErrorCode &status) { - jchar buffer[contextCount]; + SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount); + jchar* buffer = tempBuffer.get(); + +#if DEBUG_RTL_ALLOCATIONS + LOGD("TextLayout::shapeRtlText - allocated buffer with size: %d", contextCount); +#endif // Use fixed length since we need to keep start and count valid u_shapeArabic(context, contextCount, buffer, contextCount, @@ -68,10 +75,10 @@ int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsi U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status); if (U_SUCCESS(status)) { - // trim out 0xffff following ligatures, if any + // trim out UNICODE_NOT_A_CHAR following ligatures, if any int end = 0; for (int i = start, e = start + count; i < e; ++i) { - if (buffer[i] != 0xffff) { + if (buffer[i] != UNICODE_NOT_A_CHAR) { buffer[end++] = buffer[i]; } } @@ -83,7 +90,6 @@ int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsi return count; } } - return -1; } @@ -160,6 +166,11 @@ bool TextLayout::prepareText(SkPaint *paint, const jchar* text, jsize len, jint if (!buffer) { return false; } + +#if DEBUG_RTL_ALLOCATIONS + LOGD("TextLayout::prepareText - allocated buffer with size: %d", len); +#endif + UErrorCode status = U_ZERO_ERROR; len = layoutLine(text, len, bidiFlags, dir, buffer, status); // might change len, dir if (!U_SUCCESS(status)) { @@ -228,7 +239,7 @@ bool TextLayout::prepareRtlTextRun(const jchar* context, jsize start, jsize& cou if (U_SUCCESS(status)) { return true; } else { - LOG(LOG_WARN, "LAYOUT", "drawTextRun error %d\n", status); + LOGW("drawTextRun error %d\n", status); } return false; } @@ -242,7 +253,7 @@ void TextLayout::drawTextRun(SkPaint* paint, const jchar* chars, uint8_t rtl = dirFlags & 0x1; if (rtl) { - SkAutoSTMalloc<80, jchar> buffer(contextCount); + SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(contextCount); if (prepareRtlTextRun(chars, start, count, contextCount, buffer.get())) { canvas->drawText(buffer.get(), count << 1, x_, y_, *paint); } @@ -254,11 +265,17 @@ void TextLayout::drawTextRun(SkPaint* paint, const jchar* chars, void TextLayout::getTextRunAdvances(SkPaint *paint, const jchar *chars, jint start, jint count, jint contextCount, jint dirFlags, jfloat *resultAdvances, jfloat &resultTotalAdvance) { - jchar buffer[contextCount]; - - SkScalar* scalarArray = (SkScalar *)resultAdvances; resultTotalAdvance = 0; + SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount); + jchar* buffer = tempBuffer.get(); + +#if DEBUG_RTL_ALLOCATIONS + LOGD("TextLayout::getTextRunAdvances - allocated buffer with size: %d", contextCount); +#endif + + SkScalar* scalarArray = (SkScalar*)resultAdvances; + // this is where we'd call harfbuzz // for now we just use ushape.c @@ -274,8 +291,8 @@ void TextLayout::getTextRunAdvances(SkPaint *paint, const jchar *chars, jint sta // we shouldn't fail unless there's an out of memory condition, // in which case we're hosed anyway for (int i = start, e = i + count; i < e; ++i) { - if (buffer[i] == 0xffff) { - buffer[i] = 0x200b; // zero-width-space for skia + if (buffer[i] == UNICODE_NOT_A_CHAR) { + buffer[i] = UNICODE_ZWSP; // zero-width-space for skia } } text = buffer + start; @@ -293,8 +310,11 @@ void TextLayout::getTextRunAdvances(SkPaint *paint, const jchar *chars, jint sta // leaving the remaining widths zero. Not nice. for (int i = 0, p = 0; i < widths; ++i) { resultTotalAdvance += resultAdvances[p++] = SkScalarToFloat(scalarArray[i]); - if (p < count && text[p] >= 0xdc00 && text[p] < 0xe000 && - text[p-1] >= 0xd800 && text[p-1] < 0xdc00) { + if (p < count && + text[p] >= UNICODE_FIRST_LOW_SURROGATE && + text[p] < UNICODE_FIRST_PRIVATE_USE && + text[p-1] >= UNICODE_FIRST_HIGH_SURROGATE && + text[p-1] < UNICODE_FIRST_LOW_SURROGATE) { resultAdvances[p++] = 0; } } @@ -331,7 +351,12 @@ void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count, return; } - SkAutoSTMalloc<80, jchar> buffer(count); + SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(count); + +#if DEBUG_RTL_ALLOCATIONS + LOGD("TextLayout::drawTextOnPath - allocated buffer with size: %d", count); +#endif + int dir = kDirection_LTR; UErrorCode status = U_ZERO_ERROR; count = layoutLine(text, count, bidiFlags, dir, buffer.get(), status); diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h index 8f666c095ccf..c98f74543a99 100644 --- a/core/jni/android/graphics/TextLayout.h +++ b/core/jni/android/graphics/TextLayout.h @@ -22,6 +22,18 @@ namespace android { +#define UNICODE_NOT_A_CHAR 0xffff +#define UNICODE_ZWSP 0x200b +#define UNICODE_FIRST_LOW_SURROGATE 0xdc00 +#define UNICODE_FIRST_HIGH_SURROGATE 0xd800 +#define UNICODE_FIRST_PRIVATE_USE 0xe000 +#define UNICODE_FIRST_RTL_CHAR 0x0590 + +/* + * Temporary buffer size + */ +#define CHAR_BUFFER_SIZE 80 + class TextLayout { public: diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp index 0430a819d02d..56f2646e67ac 100644 --- a/core/jni/android_app_NativeActivity.cpp +++ b/core/jni/android_app_NativeActivity.cpp @@ -150,12 +150,12 @@ int32_t AInputQueue::hasEvents() { pfd[0].events = POLLIN; pfd[0].revents = 0; pfd[1].fd = mDispatchKeyRead; - pfd[0].events = POLLIN; - pfd[0].revents = 0; + pfd[1].events = POLLIN; + pfd[1].revents = 0; int nfd = poll(pfd, 2, 0); if (nfd <= 0) return 0; - return (pfd[0].revents == POLLIN || pfd[1].revents == POLLIN) ? 1 : -1; + return ((pfd[0].revents & POLLIN) || (pfd[1].revents & POLLIN)) ? 1 : -1; } int32_t AInputQueue::getEvent(AInputEvent** outEvent) { diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index 9f70509f43c0..bfbfd374bbe7 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -53,25 +53,48 @@ public: virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr); virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr); - void addCallbackBuffer(JNIEnv *env, jbyteArray cbb); + void addCallbackBuffer(JNIEnv *env, jbyteArray cbb, int msgType); void setCallbackMode(JNIEnv *env, bool installed, bool manualMode); sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; } + bool isRawImageCallbackBufferAvailable() const; void release(); private: void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType); + void clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers); void clearCallbackBuffers_l(JNIEnv *env); + jbyteArray getCallbackBuffer(JNIEnv *env, Vector<jbyteArray> *buffers, size_t bufferSize); jobject mCameraJObjectWeak; // weak reference to java object jclass mCameraJClass; // strong reference to java class sp<Camera> mCamera; // strong reference to native object Mutex mLock; + /* + * Global reference application-managed raw image buffer queue. + * + * Manual-only mode is supported for raw image callbacks, which is + * set whenever method addCallbackBuffer() with msgType = + * CAMERA_MSG_RAW_IMAGE is called; otherwise, null is returned + * with raw image callbacks. + */ + Vector<jbyteArray> mRawImageCallbackBuffers; + + /* + * Application-managed preview buffer queue and the flags + * associated with the usage of the preview buffer callback. + */ Vector<jbyteArray> mCallbackBuffers; // Global reference application managed byte[] bool mManualBufferMode; // Whether to use application managed buffers. - bool mManualCameraCallbackSet; // Whether the callback has been set, used to reduce unnecessary calls to set the callback. + bool mManualCameraCallbackSet; // Whether the callback has been set, used to + // reduce unnecessary calls to set the callback. }; +bool JNICameraContext::isRawImageCallbackBufferAvailable() const +{ + return !mRawImageCallbackBuffers.isEmpty(); +} + sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext) { sp<Camera> camera; @@ -128,10 +151,48 @@ void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2) return; } JNIEnv *env = AndroidRuntime::getJNIEnv(); + + /* + * If the notification or msgType is CAMERA_MSG_RAW_IMAGE_NOTIFY, change it + * to CAMERA_MSG_RAW_IMAGE since CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed + * to the Java app. + */ + if (msgType == CAMERA_MSG_RAW_IMAGE_NOTIFY) { + msgType = CAMERA_MSG_RAW_IMAGE; + } + env->CallStaticVoidMethod(mCameraJClass, fields.post_event, mCameraJObjectWeak, msgType, ext1, ext2, NULL); } +jbyteArray JNICameraContext::getCallbackBuffer( + JNIEnv* env, Vector<jbyteArray>* buffers, size_t bufferSize) +{ + jbyteArray obj = NULL; + + // Vector access should be protected by lock in postData() + if (!buffers->isEmpty()) { + LOGV("Using callback buffer from queue of length %d", buffers->size()); + jbyteArray globalBuffer = buffers->itemAt(0); + buffers->removeAt(0); + + obj = (jbyteArray)env->NewLocalRef(globalBuffer); + env->DeleteGlobalRef(globalBuffer); + + if (obj != NULL) { + jsize bufferLength = env->GetArrayLength(obj); + if ((int)bufferLength < (int)bufferSize) { + LOGE("Callback buffer was too small! Expected %d bytes, but got %d bytes!", + bufferSize, bufferLength); + env->DeleteLocalRef(obj); + return NULL; + } + } + } + + return obj; +} + void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType) { jbyteArray obj = NULL; @@ -141,7 +202,7 @@ void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int ssize_t offset; size_t size; sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size); - LOGV("postData: off=%d, size=%d", offset, size); + LOGV("copyAndPost: off=%ld, size=%d", offset, size); uint8_t *heapBase = (uint8_t*)heap->base(); if (heapBase != NULL) { @@ -151,32 +212,28 @@ void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int LOGV("Allocating callback buffer"); obj = env->NewByteArray(size); } else { - // Vector access should be protected by lock in postData() - if(!mCallbackBuffers.isEmpty()) { - LOGV("Using callback buffer from queue of length %d", mCallbackBuffers.size()); - jbyteArray globalBuffer = mCallbackBuffers.itemAt(0); - mCallbackBuffers.removeAt(0); - - obj = (jbyteArray)env->NewLocalRef(globalBuffer); - env->DeleteGlobalRef(globalBuffer); - - if (obj != NULL) { - jsize bufferLength = env->GetArrayLength(obj); - if ((int)bufferLength < (int)size) { - LOGE("Manually set buffer was too small! Expected %d bytes, but got %d!", - size, bufferLength); - env->DeleteLocalRef(obj); - return; + switch (msgType) { + case CAMERA_MSG_PREVIEW_FRAME: { + obj = getCallbackBuffer(env, &mCallbackBuffers, size); + + if (mCallbackBuffers.isEmpty()) { + LOGV("Out of buffers, clearing callback!"); + mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); + mManualCameraCallbackSet = false; + + if (obj == NULL) { + return; + } } + break; } - } - - if(mCallbackBuffers.isEmpty()) { - LOGV("Out of buffers, clearing callback!"); - mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); - mManualCameraCallbackSet = false; - - if (obj == NULL) { + case CAMERA_MSG_RAW_IMAGE: { + obj = getCallbackBuffer(env, &mRawImageCallbackBuffers, size); + break; + } + default: { + jniThrowException(env, + "java/lang/RuntimeException", "Unsupported message type"); return; } } @@ -212,21 +269,27 @@ void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr) } // return data based on callback type - switch(msgType) { - case CAMERA_MSG_VIDEO_FRAME: - // should never happen - break; - // don't return raw data to Java - case CAMERA_MSG_RAW_IMAGE: - LOGV("rawCallback"); - env->CallStaticVoidMethod(mCameraJClass, fields.post_event, - mCameraJObjectWeak, msgType, 0, 0, NULL); - break; - default: - // TODO: Change to LOGV - LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); - copyAndPost(env, dataPtr, msgType); - break; + switch (msgType) { + case CAMERA_MSG_VIDEO_FRAME: + // should never happen + break; + + // For backward-compatibility purpose, if there is no callback + // buffer for raw image, the callback returns null. + case CAMERA_MSG_RAW_IMAGE: + LOGV("rawCallback"); + if (mRawImageCallbackBuffers.isEmpty()) { + env->CallStaticVoidMethod(mCameraJClass, fields.post_event, + mCameraJObjectWeak, msgType, 0, 0, NULL); + } else { + copyAndPost(env, dataPtr, msgType); + } + break; + + default: + LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); + copyAndPost(env, dataPtr, msgType); + break; } } @@ -251,7 +314,7 @@ void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualM if (!installed) { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); - clearCallbackBuffers_l(env); + clearCallbackBuffers_l(env, &mCallbackBuffers); } else if (mManualBufferMode) { if (!mCallbackBuffers.isEmpty()) { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); @@ -259,24 +322,44 @@ void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualM } } else { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_BARCODE_SCANNER); - clearCallbackBuffers_l(env); + clearCallbackBuffers_l(env, &mCallbackBuffers); } } -void JNICameraContext::addCallbackBuffer(JNIEnv *env, jbyteArray cbb) +void JNICameraContext::addCallbackBuffer( + JNIEnv *env, jbyteArray cbb, int msgType) { + LOGV("addCallbackBuffer: 0x%x", msgType); if (cbb != NULL) { Mutex::Autolock _l(mLock); - jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); - mCallbackBuffers.push(cbb); - - LOGV("Adding callback buffer to queue, %d total", mCallbackBuffers.size()); - - // We want to make sure the camera knows we're ready for the next frame. - // This may have come unset had we not had a callbackbuffer ready for it last time. - if (mManualBufferMode && !mManualCameraCallbackSet) { - mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); - mManualCameraCallbackSet = true; + switch (msgType) { + case CAMERA_MSG_PREVIEW_FRAME: { + jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); + mCallbackBuffers.push(callbackBuffer); + + LOGV("Adding callback buffer to queue, %d total", + mCallbackBuffers.size()); + + // We want to make sure the camera knows we're ready for the + // next frame. This may have come unset had we not had a + // callbackbuffer ready for it last time. + if (mManualBufferMode && !mManualCameraCallbackSet) { + mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); + mManualCameraCallbackSet = true; + } + break; + } + case CAMERA_MSG_RAW_IMAGE: { + jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); + mRawImageCallbackBuffers.push(callbackBuffer); + break; + } + default: { + jniThrowException(env, + "java/lang/IllegalArgumentException", + "Unsupported message type"); + return; + } } } else { LOGE("Null byte array!"); @@ -285,10 +368,15 @@ void JNICameraContext::addCallbackBuffer(JNIEnv *env, jbyteArray cbb) void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env) { - LOGV("Clearing callback buffers, %d remained", mCallbackBuffers.size()); - while(!mCallbackBuffers.isEmpty()) { - env->DeleteGlobalRef(mCallbackBuffers.top()); - mCallbackBuffers.pop(); + clearCallbackBuffers_l(env, &mCallbackBuffers); + clearCallbackBuffers_l(env, &mRawImageCallbackBuffers); +} + +void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers) { + LOGV("Clearing callback buffers, %d remained", buffers->size()); + while (!buffers->isEmpty()) { + env->DeleteGlobalRef(buffers->top()); + buffers->pop(); } } @@ -458,13 +546,13 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t context->setCallbackMode(env, installed, manualBuffer); } -static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes) { - LOGV("addCallbackBuffer"); +static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, int msgType) { + LOGV("addCallbackBuffer: 0x%x", msgType); JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); if (context != NULL) { - context->addCallbackBuffer(env, bytes); + context->addCallbackBuffer(env, bytes, msgType); } } @@ -492,14 +580,32 @@ static void android_hardware_Camera_cancelAutoFocus(JNIEnv *env, jobject thiz) } } -static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) +static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz, int msgType) { LOGV("takePicture"); JNICameraContext* context; sp<Camera> camera = get_native_camera(env, thiz, &context); if (camera == 0) return; - if (camera->takePicture() != NO_ERROR) { + /* + * When CAMERA_MSG_RAW_IMAGE is requested, if the raw image callback + * buffer is available, CAMERA_MSG_RAW_IMAGE is enabled to get the + * notification _and_ the data; otherwise, CAMERA_MSG_RAW_IMAGE_NOTIFY + * is enabled to receive the callback notification but no data. + * + * Note that CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed to the + * Java application. + */ + if (msgType & CAMERA_MSG_RAW_IMAGE) { + LOGV("Enable raw image callback buffer"); + if (!context->isRawImageCallbackBufferAvailable()) { + LOGV("Enable raw image notification, since no callback buffer exists"); + msgType &= ~CAMERA_MSG_RAW_IMAGE; + msgType |= CAMERA_MSG_RAW_IMAGE_NOTIFY; + } + } + + if (camera->takePicture(msgType) != NO_ERROR) { jniThrowException(env, "java/lang/RuntimeException", "takePicture failed"); return; } @@ -638,8 +744,8 @@ static JNINativeMethod camMethods[] = { { "setHasPreviewCallback", "(ZZ)V", (void *)android_hardware_Camera_setHasPreviewCallback }, - { "addCallbackBuffer", - "([B)V", + { "_addCallbackBuffer", + "([BI)V", (void *)android_hardware_Camera_addCallbackBuffer }, { "native_autoFocus", "()V", @@ -648,7 +754,7 @@ static JNINativeMethod camMethods[] = { "()V", (void *)android_hardware_Camera_cancelAutoFocus }, { "native_takePicture", - "()V", + "(I)V", (void *)android_hardware_Camera_takePicture }, { "native_setParameters", "(Ljava/lang/String;)V", diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp index fc806a502f15..667ba75ebd46 100644 --- a/core/jni/android_net_wifi_Wifi.cpp +++ b/core/jni/android_net_wifi_Wifi.cpp @@ -556,6 +556,18 @@ static jboolean android_net_wifi_setSuspendOptimizationsCommand(JNIEnv* env, job return doBooleanCommand(cmdstr, "OK"); } +static void android_net_wifi_enableBackgroundScan(JNIEnv* env, jobject clazz, jboolean enable) +{ + //Note: BGSCAN-START and BGSCAN-STOP are documented in core/res/res/values/config.xml + //and will need an update if the names are changed + if (enable) { + doBooleanCommand("DRIVER BGSCAN-START", "OK"); + } + else { + doBooleanCommand("DRIVER BGSCAN-STOP", "OK"); + } +} + // ---------------------------------------------------------------------------- /* @@ -623,6 +635,7 @@ static JNINativeMethod gWifiMethods[] = { (void*) android_net_wifi_setSuspendOptimizationsCommand}, { "setCountryCodeCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_setCountryCodeCommand}, + { "enableBackgroundScan", "(Z)V", (void*) android_net_wifi_enableBackgroundScan}, }; int register_android_net_wifi_WifiManager(JNIEnv* env) diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 1df6fe5d8dec..12d7afd6eb20 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1196,7 +1196,7 @@ <permission android:name="android.permission.PACKAGE_USAGE_STATS" android:label="@string/permlab_pkgUsageStats" android:description="@string/permdesc_pkgUsageStats" - android:protectionLevel="signature" /> + android:protectionLevel="signatureOrSystem" /> <!-- Allows an application to collect battery statistics --> <permission android:name="android.permission.BATTERY_STATS" diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index d9eccd6f2729..b48adf136286 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3176,7 +3176,10 @@ <attr name="visible" format="boolean" /> </declare-styleable> + <!-- Drawable used to render several states. Each state is represented by + a child drawable. --> <declare-styleable name="StateListDrawable"> + <!-- Indicates whether the drawable should be initially visible. --> <attr name="visible" /> <!-- If true, allows the drawable's padding to change based on the current state that is selected. If false, the padding will @@ -3200,6 +3203,7 @@ <attr name="exitFadeDuration" format="integer" /> </declare-styleable> + <!-- Drawable used to render several animated frames. --> <declare-styleable name="AnimationDrawable"> <attr name="visible" /> <attr name="variablePadding" /> @@ -3209,6 +3213,7 @@ <attr name="oneshot" format="boolean" /> </declare-styleable> + <!-- Represents a single frame inside an AnimationDrawable. --> <declare-styleable name="AnimationDrawableItem"> <!-- Amount of time (in milliseconds) to display this frame. --> <attr name="duration" format="integer" /> @@ -3217,12 +3222,21 @@ <attr name="drawable" format="reference" /> </declare-styleable> + <!-- Drawable used to render a geometric shape, with a gradient or a solid color. --> <declare-styleable name="GradientDrawable"> + <!-- Indicates whether the drawable should intially be visible. --> <attr name="visible" /> + <!-- Enables or disables dithering. --> + <attr name="dither" /> + <!-- Indicates what shape to fill with a gradient. --> <attr name="shape"> + <!-- Rectangle shape, with optional rounder corners. --> <enum name="rectangle" value="0" /> + <!-- Oval shape. --> <enum name="oval" value="1" /> + <!-- Line shape. --> <enum name="line" value="2" /> + <!-- Ring shape. --> <enum name="ring" value="3" /> </attr> <!-- Inner radius of the ring expressed as a ratio of the ring's width. For instance, @@ -3237,71 +3251,123 @@ <attr name="innerRadius" format="dimension" /> <!-- Thickness of the ring. When defined, thicknessRatio is ignored. --> <attr name="thickness" format="dimension" /> + <!-- Indicates whether the drawable's level affects the way the gradient is drawn. --> <attr name="useLevel" /> </declare-styleable> + <!-- Used to specify the size of the shape for GradientDrawable. --> <declare-styleable name="GradientDrawableSize"> + <!-- Width of the gradient shape. --> <attr name="width" /> + <!-- Height of the gradient shape. --> <attr name="height" /> </declare-styleable> + <!-- Used to describe the gradient used to fill the shape of a GradientDrawable. --> <declare-styleable name="GradientDrawableGradient"> + <!-- Start color of the gradient. --> <attr name="startColor" format="color" /> - <!-- Optional center color. For linear gradients, use centerX or centerY to place the center color. --> + <!-- Optional center color. For linear gradients, use centerX or centerY + to place the center color. --> <attr name="centerColor" format="color" /> + <!-- End color of the gradient. --> <attr name="endColor" format="color" /> <attr name="useLevel" format="boolean" /> + <!-- Angle of the gradient. --> <attr name="angle" format="float" /> + <!-- Type of gradient. The default type is linear. --> <attr name="type"> + <!-- Linear gradient. --> <enum name="linear" value="0" /> + <!-- Radial, or circular, gradient. --> <enum name="radial" value="1" /> + <!-- Sweep, or angled or diamond, gradient. --> <enum name="sweep" value="2" /> </attr> + <!-- X coordinate of the origin of the gradient within the shape. --> <attr name="centerX" format="float|fraction" /> + <!-- Y coordinate of the origin of the gradient within the shape. --> <attr name="centerY" format="float|fraction" /> + <!-- Radius of the gradient, used only with radial gradient. --> <attr name="gradientRadius" format="float|fraction" /> </declare-styleable> + <!-- Used to fill the shape of GradientDrawable with a solid color. --> <declare-styleable name="GradientDrawableSolid"> + <!-- Solid color for the gradient shape. --> <attr name="color" format="color" /> </declare-styleable> + <!-- Used to describe the optional stroke of a GradientDrawable. --> <declare-styleable name="GradientDrawableStroke"> + <!-- Width of the gradient shape's stroke. --> <attr name="width" /> + <!-- Color of the gradient shape's stroke. --> <attr name="color" /> + <!-- Length of a dash in the stroke. --> <attr name="dashWidth" format="dimension" /> + <!-- Gap between dashes in the stroke. --> <attr name="dashGap" format="dimension" /> </declare-styleable> + <!-- Describes the corners for the rectangle shape of a GradientDrawable. + This can be used to render rounded corners. --> <declare-styleable name="DrawableCorners"> + <!-- Defines the radius of the four corners. --> <attr name="radius" format="dimension" /> + <!-- Radius of the top left corner. --> <attr name="topLeftRadius" format="dimension" /> + <!-- Radius of the top right corner. --> <attr name="topRightRadius" format="dimension" /> + <!-- Radius of the bottom left corner. --> <attr name="bottomLeftRadius" format="dimension" /> + <!-- Radius of the bottom right corner. --> <attr name="bottomRightRadius" format="dimension" /> </declare-styleable> + <!-- Used to specify the optional padding of a GradientDrawable. --> <declare-styleable name="GradientDrawablePadding"> + <!-- Amount of left padding inside the gradient shape. --> <attr name="left" format="dimension" /> + <!-- Amount of top padding inside the gradient shape. --> <attr name="top" format="dimension" /> + <!-- Amount of right padding inside the gradient shape. --> <attr name="right" format="dimension" /> + <!-- Amount of bottom padding inside the gradient shape. --> <attr name="bottom" format="dimension" /> </declare-styleable> + <!-- Drawable used to render several drawables stacked on top of each other. + Each child drawable can be controlled individually. --> <declare-styleable name="LayerDrawable"> + <!-- Indicates the opacity of the layer. This can be useful to allow the + system to enable drawing optimizations. The default value is + translucent. --> <attr name="opacity"> + <!-- Indicates that the layer is opaque and contains no transparent + nor translucent pixels. --> <enum name="opaque" value="-1" /> + <!-- The layer is completely transparent (no pixel will be drawn.) --> <enum name="transparent" value="-2" /> + <!-- The layer has translucent pixels. --> <enum name="translucent" value="-3" /> </attr> </declare-styleable> + <!-- Describes an item (or child) of a LayerDrawable. --> <declare-styleable name="LayerDrawableItem"> + <!-- Left coordinate of the layer. --> <attr name="left" /> + <!-- Top coordinate of the layer. --> <attr name="top" /> + <!-- Right coordinate of the layer. --> <attr name="right" /> + <!-- Bottom coordinate of the layer. --> <attr name="bottom" /> + <!-- Drawable used to render the layer. --> <attr name="drawable" /> + <!-- Identifier of the layer. This can be used to retrieve the layer + from a drawbable container. --> <attr name="id" /> </declare-styleable> @@ -3317,6 +3383,7 @@ <attr name="drawable" /> </declare-styleable> + <!-- Drawable used to rotate another drawable. --> <declare-styleable name="RotateDrawable"> <attr name="visible" /> <attr name="fromDegrees" format="float" /> @@ -3475,6 +3542,8 @@ <attr name="width" /> <!-- Defines the height of the shape. --> <attr name="height" /> + <!-- Enables or disables dithering. --> + <attr name="dither" /> </declare-styleable> <!-- ========================== --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 0edd33e35c86..ce37943b492c 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -194,6 +194,13 @@ <!-- Boolean indicating whether the wifi chipset has dual frequency band support --> <bool translatable="false" name="config_wifi_dual_band_support">false</bool> + <!-- Boolean indicating whether the wifi chipset supports background scanning mechanism. + This mechanism allows the host to remain in suspend state and the dongle to actively + scan and wake the host when a configured SSID is detected by the dongle. This chipset + capability can provide power savings when wifi needs to be always kept on. + The driver commands needed to support the feature are BGSCAN-START and BGSCAN-STOP --> + <bool translatable="false" name="config_wifi_background_scan_support">false</bool> + <!-- Flag indicating whether the keyguard should be bypassed when the slider is open. This can be set or unset depending how easily the slider can be opened (for example, in a pocket or purse). --> diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java index 1374e7f8afef..41104fe4ad72 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java @@ -108,15 +108,6 @@ public class WifiApStress fail("thread in sleep is interrupted"); } assertTrue("no uplink data connection after Wi-Fi tethering", mAct.pingTest(null)); - // Wait for 5 minutes, and verify the data connection again. - // bug id: 3400027 - try { - Thread.sleep(5 * 60 * 1000); - } catch (Exception e) { - fail("thread in sleep is interrupted"); - } - // Verify the uplink data connection - assertTrue("no uplink data connection", mAct.pingTest(null)); // Disable soft AP assertTrue(mAct.mWifiManager.setWifiApEnabled(config, false)); // Wait for 30 seconds until Wi-Fi tethering is stopped diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java index 35210e5c7b3d..85c5eaa85b9b 100644 --- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java +++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java @@ -16,6 +16,8 @@ package android.bluetooth; +import android.bluetooth.BluetoothPan; +import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -296,8 +298,8 @@ public class BluetoothTestUtils extends Assert { return; } - if (BluetoothPan.ACTION_PAN_STATE_CHANGED.equals(intent.getAction())) { - int state = intent.getIntExtra(BluetoothPan.EXTRA_PAN_STATE, -1); + if (BluetoothPan.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) { + int state = intent.getIntExtra(BluetoothPan.EXTRA_STATE, -1); assertNotSame(-1, state); switch (state) { case BluetoothPan.STATE_DISCONNECTED: @@ -331,6 +333,9 @@ public class BluetoothTestUtils extends Assert { case BluetoothProfile.INPUT_DEVICE: mInput = (BluetoothInputDevice) proxy; break; + case BluetoothProfile.PAN: + mPan = (BluetoothPan) proxy; + break; } } } @@ -347,6 +352,9 @@ public class BluetoothTestUtils extends Assert { case BluetoothProfile.INPUT_DEVICE: mInput = null; break; + case BluetoothProfile.PAN: + mPan = null; + break; } } } @@ -362,6 +370,7 @@ public class BluetoothTestUtils extends Assert { private BluetoothA2dp mA2dp; private BluetoothHeadset mHeadset; private BluetoothInputDevice mInput; + private BluetoothPan mPan; /** * Creates a utility instance for testing Bluetooth. @@ -706,13 +715,13 @@ public class BluetoothTestUtils extends Assert { * @param adapter The BT adapter. */ public void enablePan(BluetoothAdapter adapter) { - BluetoothPan pan = new BluetoothPan(mContext); - assertNotNull(pan); + if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN); + assertNotNull(mPan); long start = System.currentTimeMillis(); - pan.setBluetoothTethering(true); + mPan.setBluetoothTethering(true); long stop = System.currentTimeMillis(); - assertTrue(pan.isTetheringOn()); + assertTrue(mPan.isTetheringOn()); writeOutput(String.format("enablePan() completed in %d ms", (stop - start))); } @@ -724,13 +733,13 @@ public class BluetoothTestUtils extends Assert { * @param adapter The BT adapter. */ public void disablePan(BluetoothAdapter adapter) { - BluetoothPan pan = new BluetoothPan(mContext); - assertNotNull(pan); + if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN); + assertNotNull(mPan); long start = System.currentTimeMillis(); - pan.setBluetoothTethering(false); + mPan.setBluetoothTethering(false); long stop = System.currentTimeMillis(); - assertFalse(pan.isTetheringOn()); + assertFalse(mPan.isTetheringOn()); writeOutput(String.format("disablePan() completed in %d ms", (stop - start))); } @@ -1102,11 +1111,11 @@ public class BluetoothTestUtils extends Assert { fail(String.format("%s device not paired: device=%s", methodName, device)); } - BluetoothPan pan = new BluetoothPan(mContext); - assertNotNull(pan); + if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN); + assertNotNull(mPan); ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask); - int state = pan.getPanDeviceState(device); + int state = mPan.getConnectionState(device); switch (state) { case BluetoothPan.STATE_CONNECTED: removeReceiver(receiver); @@ -1119,7 +1128,7 @@ public class BluetoothTestUtils extends Assert { start = System.currentTimeMillis(); if (role == BluetoothPan.LOCAL_PANU_ROLE) { Log.i("BT", "connect to pan"); - assertTrue(pan.connect(device)); + assertTrue(mPan.connect(device)); } break; default: @@ -1130,7 +1139,7 @@ public class BluetoothTestUtils extends Assert { long s = System.currentTimeMillis(); while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) { - state = pan.getPanDeviceState(device); + state = mPan.getConnectionState(device); if (state == BluetoothPan.STATE_CONNECTED && (receiver.getFiredFlags() & mask) == mask) { long finish = receiver.getCompletedTime(); @@ -1209,23 +1218,23 @@ public class BluetoothTestUtils extends Assert { fail(String.format("%s device not paired: device=%s", methodName, device)); } - BluetoothPan pan = new BluetoothPan(mContext); - assertNotNull(pan); + if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN); + assertNotNull(mPan); ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask); - int state = pan.getPanDeviceState(device); + int state = mPan.getConnectionState(device); switch (state) { - case BluetoothInputDevice.STATE_CONNECTED: - case BluetoothInputDevice.STATE_CONNECTING: + case BluetoothPan.STATE_CONNECTED: + case BluetoothPan.STATE_CONNECTING: start = System.currentTimeMillis(); if (role == BluetoothPan.LOCAL_PANU_ROLE) { - assertTrue(pan.disconnect(device)); + assertTrue(mPan.disconnect(device)); } break; - case BluetoothInputDevice.STATE_DISCONNECTED: + case BluetoothPan.STATE_DISCONNECTED: removeReceiver(receiver); return; - case BluetoothInputDevice.STATE_DISCONNECTING: + case BluetoothPan.STATE_DISCONNECTING: mask = 0; // Don't check for received intents since we might have missed them. break; default: @@ -1236,7 +1245,7 @@ public class BluetoothTestUtils extends Assert { long s = System.currentTimeMillis(); while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) { - state = pan.getPanDeviceState(device); + state = mPan.getConnectionState(device); if (state == BluetoothInputDevice.STATE_DISCONNECTED && (receiver.getFiredFlags() & mask) == mask) { long finish = receiver.getCompletedTime(); @@ -1321,7 +1330,7 @@ public class BluetoothTestUtils extends Assert { private ConnectPanReceiver getConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) { - String[] actions = {BluetoothPan.ACTION_PAN_STATE_CHANGED}; + String[] actions = {BluetoothPan.ACTION_CONNECTION_STATE_CHANGED}; ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags); addReceiver(receiver, actions); return receiver; @@ -1351,6 +1360,11 @@ public class BluetoothTestUtils extends Assert { sleep(POLL_TIME); } return mInput; + case BluetoothProfile.PAN: + while (mPan == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) { + sleep(POLL_TIME); + } + return mPan; default: return null; } diff --git a/docs/html/guide/appendix/market-filters.jd b/docs/html/guide/appendix/market-filters.jd index f826f43d3712..ef1deba470e4 100644 --- a/docs/html/guide/appendix/market-filters.jd +++ b/docs/html/guide/appendix/market-filters.jd @@ -24,6 +24,8 @@ manifest file to the configurations defined by the device, as well as other fact <li><a href="{@docRoot}guide/practices/compatibility.html">Android Compatibility</a></li> <li><code><a +href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html"><supports-gl-texture></a></code></li> +<li><code><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><supports-screens></a></code></li> <li><code><a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><uses-configuration></a></code></li> @@ -395,5 +397,12 @@ href="{@docRoot}guide/topics/manifest/supports-screens-element.html">{@code with alternative resources.</p> </td> </tr> + <tr> + <td><nobr><a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html">{@code +<supports-gl-texture>}</a></nobr></td> + <td> + <p>Android Market filters the application unless one or more of the GL texture compression formats supported by the application are also supported by the device. </p> + </td> + </tr> </table> diff --git a/docs/html/guide/appendix/media-formats.jd b/docs/html/guide/appendix/media-formats.jd index bac6bf43be98..8509466d4856 100644 --- a/docs/html/guide/appendix/media-formats.jd +++ b/docs/html/guide/appendix/media-formats.jd @@ -168,7 +168,7 @@ page.title=Android Supported Media Formats <tr> -<td rowspan="3">Video</td> +<td rowspan="4">Video</td> <td>H.263</td> <td style="text-align: center;"><big>•</big></td> <td style="text-align: center;"><big>•</big></td> @@ -192,6 +192,14 @@ page.title=Android Supported Media Formats <td>3GPP (.3gp)</td> </tr> +<tr> +<td>VP8</td> +<td> </td> +<td style="text-align: center;"><big>•</big><br><small>(Android 2.3.3+)</small></td> +<td> </td> +<td><a href="http://www.webmproject.org/">WebM</a> (.webm)</td> +</tr> + </tbody></table> diff --git a/docs/html/guide/developing/building/building-cmdline.jd b/docs/html/guide/developing/building/building-cmdline.jd index 81c117828bef..5f193bc2a988 100644 --- a/docs/html/guide/developing/building/building-cmdline.jd +++ b/docs/html/guide/developing/building/building-cmdline.jd @@ -72,7 +72,7 @@ ant debug <p>This creates your debug <code>.apk</code> file inside the project <code>bin/</code> directory, named <code><your_project_name>-debug.apk</code>. The file is already signed with the debug key and has been aligned with - <a href="{@docRoot}/guide/developing/tools/zipalign.html"><code>zipalign</code></a>. + <a href="{@docRoot}guide/developing/tools/zipalign.html"><code>zipalign</code></a>. </p> </li> </ol> diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index d81b41670924..b13600cc742c 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -60,7 +60,7 @@ <li class="toggle-list"> <div><a href="<?cs var:toroot ?>guide/topics/fundamentals/activities.html"> <span class="en">Activities</span> - </a> <span class="new">new!</span></div> + </a> <span class="new-child">new!</span></div> <ul> <li><a href="<?cs var:toroot ?>guide/topics/fundamentals/fragments.html"> <span class="en">Fragments</span> @@ -69,18 +69,17 @@ <span class="en">Loaders</span> </a> <span class="new">new!</span></li> <li><a href="<?cs var:toroot ?>guide/topics/fundamentals/tasks-and-back-stack.html"> - <span class="en">Tasks and Back Stack</span> - </a> <span class="new">new!</span></li> + <span class="en">Tasks and Back Stack</span></a></li> </ul> </li> <li class="toggle-list"> <div><a href="<?cs var:toroot ?>guide/topics/fundamentals/services.html"> <span class="en">Services</span> - </a> <span class="new">new!</span></div> + </a></div> <ul> <li><a href="<?cs var:toroot ?>guide/topics/fundamentals/bound-services.html"> <span class="en">Bound Services</span> - </a> <span class="new">new!</span></li> + </a></li> </ul> </li> <li><a href="<?cs var:toroot ?>guide/topics/providers/content-providers.html"> @@ -91,7 +90,7 @@ </a></li> <li><a href="<?cs var:toroot ?>guide/topics/fundamentals/processes-and-threads.html"> <span class="en">Processes and Threads</span> - </a> <span class="new">new!</span></li> + </a></li> </ul> @@ -100,7 +99,7 @@ <div><a href="<?cs var:toroot ?>guide/topics/ui/index.html"> <span class="en">User Interface</span> </a> - <span class="new">more!</span></div> + <span class="new-child">new!</span></div> <ul> <li><a href="<?cs var:toroot ?>guide/topics/ui/declaring-layout.html"> <span class="en">Declaring Layout</span> @@ -130,10 +129,9 @@ </a></li> </ul> </li> - <li> - <a href="<?cs var:toroot ?>guide/topics/ui/drag-drop.html"> - Dragging and Dropping - </a><span class="new">new!</span> + <li><a href="<?cs var:toroot ?>guide/topics/ui/drag-drop.html"> + <span class="en">Dragging and Dropping</span> + </a> <span class="new">new!</span> </li> <li><a href="<?cs var:toroot ?>guide/topics/ui/themes.html"> <span class="en">Applying Styles and Themes</span> @@ -225,6 +223,7 @@ <li><a href="<?cs var:toroot ?>guide/topics/manifest/provider-element.html"><provider></a></li> <li><a href="<?cs var:toroot ?>guide/topics/manifest/receiver-element.html"><receiver></a></li> <li><a href="<?cs var:toroot ?>guide/topics/manifest/service-element.html"><service></a></li> + <li><a href="<?cs var:toroot ?>guide/topics/manifest/supports-gl-texture-element.html"><supports-gl-texture></a></li> <li><a href="<?cs var:toroot ?>guide/topics/manifest/supports-screens-element.html"><supports-screens></a></li> <!-- ##api level 4## --> <li><a href="<?cs var:toroot ?>guide/topics/manifest/uses-configuration-element.html"><uses-configuration></a></li> <li><a href="<?cs var:toroot ?>guide/topics/manifest/uses-feature-element.html"><uses-feature></a></li> <!-- ##api level 4## --> @@ -240,7 +239,7 @@ <div><a href="<?cs var:toroot ?>guide/topics/graphics/index.html"> <span class="en">Graphics</span> </a> - <span class="new">more!</span></div> + <span class="new-child">new!</span></div> <ul> <li><a href="<?cs var:toroot ?>guide/topics/graphics/2d-graphics.html"> <span class="en">2D Graphics</span> @@ -250,10 +249,10 @@ </a></li> <li><a href="<?cs var:toroot ?>guide/topics/graphics/renderscript.html"> <span class="en">3D with Renderscript</span> - </a><span class="new">new!</span></li> + </a> <span class="new">new!</span></li> <li><a href="<?cs var:toroot ?>guide/topics/graphics/animation.html"> <span class="en">Property Animation</span> - </a><span class="new">new!</span></li> + </a> <span class="new">new!</span></li> <li><a href="<?cs var:toroot ?>guide/topics/graphics/view-animation.html"> <span class="en">View Animation</span> </a></li> @@ -653,6 +652,9 @@ <li><a href="<?cs var:toroot ?>guide/practices/screens_support.html"> <span class="en">Supporting Multiple Screens</span> </a></li> + <li><a href="<?cs var:toroot ?>guide/practices/optimizing-for-3.0.html"> + <span class="en">Optimizing Apps for Android 3.0</span> + </a> <span class="new">new!</span></li> <li class="toggle-list"> <div><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/index.html"> <span class="en">UI Guidelines</span> diff --git a/docs/html/sdk/android-3.0-optimize.jd b/docs/html/guide/practices/optimizing-for-3.0.jd index a22e69af2076..a22e69af2076 100644 --- a/docs/html/sdk/android-3.0-optimize.jd +++ b/docs/html/guide/practices/optimizing-for-3.0.jd diff --git a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd index 7f35b047d305..31ad466dc0b3 100644 --- a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd +++ b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd @@ -1,4 +1,6 @@ page.title=Activity and Task Design Guidelines +parent.title=UI Guidelines +parent.link=index.html @jd:body <div id="qv-wrapper"> diff --git a/docs/html/guide/practices/ui_guidelines/menu_design.jd b/docs/html/guide/practices/ui_guidelines/menu_design.jd index 840ee66b64d2..7751a7b46efa 100644 --- a/docs/html/guide/practices/ui_guidelines/menu_design.jd +++ b/docs/html/guide/practices/ui_guidelines/menu_design.jd @@ -1,4 +1,6 @@ page.title=Menu Design Guidelines +parent.title=UI Guidelines +parent.link=index.html @jd:body <div id="qv-wrapper"> diff --git a/docs/html/guide/practices/ui_guidelines/widget_design.jd b/docs/html/guide/practices/ui_guidelines/widget_design.jd index e9780696f3b8..49aa4981c581 100644 --- a/docs/html/guide/practices/ui_guidelines/widget_design.jd +++ b/docs/html/guide/practices/ui_guidelines/widget_design.jd @@ -1,4 +1,6 @@ page.title=Widget Design Guidelines +parent.title=UI Guidelines +parent.link=index.html @jd:body <div id="qv-wrapper"> diff --git a/docs/html/guide/topics/graphics/renderscript.jd b/docs/html/guide/topics/graphics/renderscript.jd index 0e64c786ab11..60bffdb1a49a 100644 --- a/docs/html/guide/topics/graphics/renderscript.jd +++ b/docs/html/guide/topics/graphics/renderscript.jd @@ -115,7 +115,7 @@ parent.link=index.html <code><em>ScriptC_renderscript_filename</em></code>. Accessor methods are generated, so the Android system layer can access the values. The <code>get</code> method comes with a one-way communication restriction. - The Android system layer always caches the last value that is set and returns that during a call to a <code>get<code> method. + The Android system layer always caches the last value that is set and returns that during a call to a <code>get</code> method. If the native Renderscript code changes the value, the change does not propagate back to the Android system layer. If the global variables are initialized in the native Renderscript code, those values are used to initialize the corresponding values in the Android system. If global variables are marked as <code>const</code>, @@ -373,11 +373,11 @@ parent.link=index.html graphics context by calling {@link android.renderscript.RenderScriptGL#bindProgramVertex bindProgramVertex()}. It is then used for all subsequent draw calls until you bind a new program. If the program has constant inputs, the - user needs to bind an allocation containing those inputs. The allocation’s type must match + user needs to bind an allocation containing those inputs. The allocation's type must match the one provided during creation. The Renderscript library then does all the necessary plumbing to send those constants to the graphics hardware. Varying inputs to the shader, such as position, normal, and texture coordinates are matched by name between the input - Element and the Mesh object being drawn. The signatures don’t have to be exact or in any + Element and the Mesh object being drawn. The signatures don't have to be exact or in any strict order. As long as the input name in the shader matches a channel name and size available on the mesh, the run-time would take care of connecting the two. Unlike OpenGL, there is no need to link the vertex and fragment programs.</p> @@ -396,7 +396,7 @@ parent.link=index.html <td>rs_program_fragment</td> <td><p>The Renderscript fragment program, also known as the fragment shader, is responsible for - manipulating pixel data in a user-defined way. It’s constructed from a GLSL shader string + manipulating pixel data in a user-defined way. It's constructed from a GLSL shader string containing the program body, textures inputs, and a Type object describing the constants used by the program. Like the vertex programs, when an allocation with constant input values is bound to the shader, its values are sent to the graphics program automatically. Note that the @@ -445,7 +445,7 @@ parent.link=index.html mip-maps are used and the amount of anisotropy required. There may be situations where hardware limitations prevent the exact behavior from being matched. In these cases, the runtime attempts to provide the closest possible approximation. For example, the user - requested 16x anisotropy, but only 8x was set because it’s the best available on the + requested 16x anisotropy, but only 8x was set because it's the best available on the hardware.</td> </tr> diff --git a/docs/html/guide/topics/manifest/action-element.jd b/docs/html/guide/topics/manifest/action-element.jd index d7ba78d73418..8ad94cdc1d50 100644 --- a/docs/html/guide/topics/manifest/action-element.jd +++ b/docs/html/guide/topics/manifest/action-element.jd @@ -1,4 +1,6 @@ page.title=<action> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/activity-alias-element.jd b/docs/html/guide/topics/manifest/activity-alias-element.jd index 4521b4bddc3f..ba2c1542ce0f 100644 --- a/docs/html/guide/topics/manifest/activity-alias-element.jd +++ b/docs/html/guide/topics/manifest/activity-alias-element.jd @@ -1,4 +1,6 @@ page.title=<activity-alias> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd index 5e0b5367896f..c910686946bc 100644 --- a/docs/html/guide/topics/manifest/activity-element.jd +++ b/docs/html/guide/topics/manifest/activity-element.jd @@ -1,4 +1,6 @@ page.title=<activity> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> @@ -14,6 +16,7 @@ page.title=<activity> android:<a href="#exclude">excludeFromRecents</a>=["true" | "false"] android:<a href="#exported">exported</a>=["true" | "false"] android:<a href="#finish">finishOnTaskLaunch</a>=["true" | "false"] + android:<a href="#hwaccel">hardwareAccelerated</a>=["true" | "false"] android:<a href="#icon">icon</a>="<i>drawable resource</i>" android:<a href="#label">label</a>="<i>string resource</i>" android:<a href="#lmode">launchMode</a>=["multiple" | "singleTop" | @@ -286,6 +289,24 @@ are both "{@code true}", this attribute trumps the other. The affinity of the activity is ignored. The activity is not re-parented, but destroyed. </p> +<dt><a name="hwaccel"></a>{@code android:hardwareAccelerated}</dt> +<dd>Whether or not hardware-accelerated rendering should be enabled for this +Activity — "{@code true}" if it should be enabled, and "{@code false}" if +not. The default value is "{@code false}". + +<p>Starting from Android 3.0, a hardware-accelerated OpenGL renderer is +available to applications, to improve performance for many common 2D graphics +operations. When the hardware-accelerated renderer is enabled, most operations +in Canvas, Paint, Xfermode, ColorFilter, Shader, and Camera are accelerated. +This results in smoother animations, smoother scrolling, and improved +responsiveness overall, even for applications that do not explicitly make use +the framework's OpenGL libraries. </p> + +<p>Note that not all of the OpenGL 2D operations are accelerated. If you enable +the hardware-accelerated renderer, test your application to ensure that it can +make use of the renderer without errors.</p> +</dd> + <dt><a name="icon"></a>{@code android:icon}</dt> <dd>An icon representing the activity. The icon is displayed to users when a representation of the activity is required on-screen. For example, icons diff --git a/docs/html/guide/topics/manifest/application-element.jd b/docs/html/guide/topics/manifest/application-element.jd index 1fadc6e32c85..41313ed35cc2 100644 --- a/docs/html/guide/topics/manifest/application-element.jd +++ b/docs/html/guide/topics/manifest/application-element.jd @@ -1,4 +1,6 @@ page.title=<application> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> @@ -9,6 +11,7 @@ page.title=<application> android:<a href="#desc">description</a>="<i>string resource</i>" android:<a href="#enabled">enabled</a>=["true" | "false"] android:<a href="#code">hasCode</a>=["true" | "false"] + android:<a href="#hwaccel">hardwareAccelerated</a>=["true" | "false"] android:<a href="#icon">icon</a>="<i>drawable resource</i>" android:<a href="#killrst">killAfterRestore</a>=["true" | "false"] android:<a href="#label">label</a>="<i>string resource</i>" @@ -108,7 +111,26 @@ The default value is "{@code true}". <p> An application would not have any code of its own only if it's using nothing but built-in component classes, such as an activity that uses the {@link -android.app.AliasActivity} class, a rare occurrence. +android.app.AliasActivity} class, a rare occurrence.</p> +</dd> + +<dt><a name="hwaccel"></a>{@code android:hardwareAccelerated}</dt> +<dd>Whether or not hardware-accelerated rendering should be enabled for all +Activities and Views in this application — "{@code true}" if it +should be enabled, and "{@code false}" if not. The default value is "{@code false}". + +<p>Starting from Android 3.0, a hardware-accelerated OpenGL renderer is +available to applications, to improve performance for many common 2D graphics +operations. When the hardware-accelerated renderer is enabled, most operations +in Canvas, Paint, Xfermode, ColorFilter, Shader, and Camera are accelerated. +This results in smoother animations, smoother scrolling, and improved +responsiveness overall, even for applications that do not explicitly make use +the framework's OpenGL libraries. </p> + +<p>Note that not all of the OpenGL 2D operations are accelerated. If you enable +the hardware-accelerated renderer, test your application to ensure that it can +make use of the renderer without errors.</p> +</dd> <dt><a name="icon"></a>{@code android:icon}</dt> <dd>An icon for the application as whole, and the default icon for diff --git a/docs/html/guide/topics/manifest/category-element.jd b/docs/html/guide/topics/manifest/category-element.jd index b9a1aa68df65..f392c0a30f52 100644 --- a/docs/html/guide/topics/manifest/category-element.jd +++ b/docs/html/guide/topics/manifest/category-element.jd @@ -1,4 +1,6 @@ page.title=<category> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/compatible-screens-element.jd b/docs/html/guide/topics/manifest/compatible-screens-element.jd index 9fb0fd2c891d..866987489290 100644 --- a/docs/html/guide/topics/manifest/compatible-screens-element.jd +++ b/docs/html/guide/topics/manifest/compatible-screens-element.jd @@ -1,4 +1,6 @@ page.title=<compatible-screens> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/data-element.jd b/docs/html/guide/topics/manifest/data-element.jd index b77fd059917b..9b0d0df6ae06 100644 --- a/docs/html/guide/topics/manifest/data-element.jd +++ b/docs/html/guide/topics/manifest/data-element.jd @@ -1,4 +1,6 @@ page.title=<data> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/grant-uri-permission-element.jd b/docs/html/guide/topics/manifest/grant-uri-permission-element.jd index 9dafe8514f12..dc98cbb55709 100644 --- a/docs/html/guide/topics/manifest/grant-uri-permission-element.jd +++ b/docs/html/guide/topics/manifest/grant-uri-permission-element.jd @@ -1,4 +1,6 @@ page.title=<grant-uri-permission> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/instrumentation-element.jd b/docs/html/guide/topics/manifest/instrumentation-element.jd index b18e77757bd6..9408b8435049 100644 --- a/docs/html/guide/topics/manifest/instrumentation-element.jd +++ b/docs/html/guide/topics/manifest/instrumentation-element.jd @@ -1,4 +1,6 @@ page.title=<instrumentation> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/intent-filter-element.jd b/docs/html/guide/topics/manifest/intent-filter-element.jd index 2b1322c5021f..d2934005f47b 100644 --- a/docs/html/guide/topics/manifest/intent-filter-element.jd +++ b/docs/html/guide/topics/manifest/intent-filter-element.jd @@ -1,4 +1,6 @@ page.title=<intent-filter> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd index 7f21e6bbb9fb..a8125b3384cb 100644 --- a/docs/html/guide/topics/manifest/manifest-element.jd +++ b/docs/html/guide/topics/manifest/manifest-element.jd @@ -1,4 +1,6 @@ page.title=<manifest> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/manifest-intro.jd b/docs/html/guide/topics/manifest/manifest-intro.jd index d7a3e3ef6a7b..0f2030556587 100644 --- a/docs/html/guide/topics/manifest/manifest-intro.jd +++ b/docs/html/guide/topics/manifest/manifest-intro.jd @@ -83,6 +83,8 @@ other mention of the element name. <a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><uses-configuration /></a> <!-- ##api level 3## --> <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><uses-feature /></a> <!-- ##api level 4## --> <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><supports-screens /></a> <!-- ##api level 4## --> + <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><compatible-screens /></a> <!-- ##api level 9## --> + <a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html"><supports-gl-texture /></a> <!-- ##api level 11## --> <a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a> diff --git a/docs/html/guide/topics/manifest/meta-data-element.jd b/docs/html/guide/topics/manifest/meta-data-element.jd index 101b05a4987e..85a871d0bebd 100644 --- a/docs/html/guide/topics/manifest/meta-data-element.jd +++ b/docs/html/guide/topics/manifest/meta-data-element.jd @@ -1,4 +1,6 @@ page.title=<meta-data> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/path-permission-element.jd b/docs/html/guide/topics/manifest/path-permission-element.jd index 5c271a73b86f..e644d6819bff 100644 --- a/docs/html/guide/topics/manifest/path-permission-element.jd +++ b/docs/html/guide/topics/manifest/path-permission-element.jd @@ -1,4 +1,6 @@ page.title=<path-permission> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/permission-element.jd b/docs/html/guide/topics/manifest/permission-element.jd index ad64d5dd31f7..c256fb1961c1 100644 --- a/docs/html/guide/topics/manifest/permission-element.jd +++ b/docs/html/guide/topics/manifest/permission-element.jd @@ -1,4 +1,6 @@ page.title=<permission> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/permission-group-element.jd b/docs/html/guide/topics/manifest/permission-group-element.jd index 0ad76a68044f..fc1de1fc7b64 100644 --- a/docs/html/guide/topics/manifest/permission-group-element.jd +++ b/docs/html/guide/topics/manifest/permission-group-element.jd @@ -1,4 +1,6 @@ page.title=<permission-group> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/permission-tree-element.jd b/docs/html/guide/topics/manifest/permission-tree-element.jd index 6d6cd0a1bfdd..a9c00cdf13e5 100644 --- a/docs/html/guide/topics/manifest/permission-tree-element.jd +++ b/docs/html/guide/topics/manifest/permission-tree-element.jd @@ -1,4 +1,6 @@ page.title=<permission-tree> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/provider-element.jd b/docs/html/guide/topics/manifest/provider-element.jd index c80b20742cc2..dd0022405152 100644 --- a/docs/html/guide/topics/manifest/provider-element.jd +++ b/docs/html/guide/topics/manifest/provider-element.jd @@ -1,4 +1,6 @@ page.title=<provider> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/receiver-element.jd b/docs/html/guide/topics/manifest/receiver-element.jd index b2089177b605..7012c0fda67f 100644 --- a/docs/html/guide/topics/manifest/receiver-element.jd +++ b/docs/html/guide/topics/manifest/receiver-element.jd @@ -1,4 +1,6 @@ page.title=<receiver> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/service-element.jd b/docs/html/guide/topics/manifest/service-element.jd index 0a44e2c0cf54..d9a81b3a05e4 100644 --- a/docs/html/guide/topics/manifest/service-element.jd +++ b/docs/html/guide/topics/manifest/service-element.jd @@ -1,4 +1,6 @@ page.title=<service> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/supports-gl-texture-element.jd b/docs/html/guide/topics/manifest/supports-gl-texture-element.jd new file mode 100644 index 000000000000..6c4a05a4351e --- /dev/null +++ b/docs/html/guide/topics/manifest/supports-gl-texture-element.jd @@ -0,0 +1,189 @@ +page.title=<supports-gl-texture> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html +@jd:body + +<dl class="xml"> + +<dt>syntax:</dt> +<dd> +<pre class="stx"> +<supports-gl-texture android:<a href="#name">name</a>="<em>string</em>" /> +</pre> +</dd> + +<dt>contained in:</dt> +<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd> + + <div class="sidebox-wrapper"> + <img id="rule" src="{@docRoot}assets/images/grad-rule-qv.png"> + <div id="qv-sub-rule"> + <img src="{@docRoot}assets/images/icon_market.jpg" + style="float:left;margin:0;padding:0;"> + <p style="color:#669999;">Android Market and <code + style="color:#669999;"><supports-gl-texture></code> elements</p> + <p style="margin-top:1em;">Android Market filters applications according + to the texture compression formats that they support, to ensure that + they can be installed only on devices that can handle their textures + properly. Developers can use texture compression filtering + as a way of targeting specific device types, based on GPU platform.</p> + + <p style="margin-top:1em;" class="caution">For important information about how + Android Market uses <code><supports-gl-texture></code> elements as + the basis for filtering, please read <a href="#market-texture-filtering">Android + Market and texture compression filtering</a>, below.</p> +</div> +</div> + +<dt>description:</dt> +<dd>Declares a single GL texture compression format that is supported by +the application. + +<p>An application "supports" a GL texture compression format if it is capable of +providing texture assets that are compressed in that format, once the +application is installed on a device. The application can provide the +compressed assets locally, from inside the <code>.apk</code>, or it can download them +from a server at runtime.</p> + +<p>Each <code><supports-gl-texture></code> element declares exactly one +supported texture compression format, specified as the value of a +<code>android:name</code> attribute. If your application supports multiple +texture compression formats, you can declare multiple +<code><supports-gl-texture></code> elements. For example:</p> + +<pre><supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" /> +<supports-gl-texture android:name="GL_OES_compressed_paletted_texture" /></pre> + +<p>Declared <code><supports-gl-texture></code> elements are informational, +meaning that the Android system itself does not examine the elements at install +time to ensure matching support on the device. However, other services +(such as Android Market) or applications can check your application's +<code><supports-gl-texture></code> declarations as part of handling or +interacting with your application. For this reason, it's very important that +you declare all of the texture compression formats (from the list below) that +your application is capable of supporting. </p> + +<p>Applications and devices typically declare their supported GL texture +compression formats using the same set of well-known strings, as listed below. +The set of format strings may grow over time, as needed, and since the values +are strings, applications are free to declare other formats as needed.</p> + +<p>Assuming that the application is built with SDK Platform Tools r3 or higher, +filtering based on the <code><supports-gl-texture></code> element is activated +for all API levels.</p> + +<dt>attributes:</dt> + +<dd> +<dl class="attr"> + + <dt><a name="name"></a>{@code android:name}</dt> + <dd>Specifies a single GL texture compression format supported by the application, + as a descriptor string. Common descriptor values are listed in the table below. + +<table> +<tr> +<th>Texture Compression Format Descriptor</th> +<th>Comments</th> +</tr> +<tr> +<td><code>GL_OES_compressed_ETC1_RGB8_texture</code></td> +<td>Ericsson texture compression. Specified in OpenGL ES 2.0 and available in all +Android-powered devices that support OpenGL ES 2.0.</td> +</tr> +<tr> +<td><code>GL_OES_compressed_paletted_texture</code></td> +<td>Generic paletted texture compression.</td> +</tr> +<tr> +<td><code>GL_AMD_compressed_3DC_texture</code></td> +<td>ATI 3Dc texture compression. </td> +</tr> +<tr> +<td><code>GL_AMD_compressed_ATC_texture</code></td> +<td>ATI texture compression. Available on devices running Adreno GPU, including +HTC Nexus One, Droid Incredible, EVO, and others. For widest compatibility, +devices may also declare a <code><supports-gl-texture></code> element with the +descriptor <code>GL_ATI_texture_compression_atitc</code>. </td> +</tr> +<tr> +<td><code>GL_EXT_texture_compression_latc</code></td> +<td>Luminance alpha texture compression. </td> +</tr> +<tr> +<td><code>GL_EXT_texture_compression_dxt1</code></td> +<td>S3 DXT1 texture compression. Supported on devices running Nvidia Tegra2 +platform, including Motorala Xoom, Motorola Atrix, Droid Bionic, and +others.</td> +</tr> +<tr> +<td><code>GL_EXT_texture_compression_s3tc</code></td> +<td>S3 texture compression, nonspecific to DXT variant. Supported on devices +running Nvidia Tegra2 platform, including Motorala Xoom, Motorola Atrix, Droid +Bionic, and others. If your application requires a specific DXT variant, declare +that descriptor instead of this one.</td> +</tr> +<tr> +<td><code>GL_IMG_texture_compression_pvrtc</code></td> +<td>PowerVR texture compression. Available in devices running PowerVR SGX530/540 +GPU, such as Motorola DROID series; Samsung Galaxy S, Nexus S, and Galaxy Tab; +and others.</td> +</tr> +</table> + +</dd> +</dl></dd> + +<!-- ##api level indication## +<dt>introduced in:</dt> +<dd>API Level </dd>--> + +<dt>see also:</dt> +<dd> + <ul> + <li><a href="{@docRoot}guide/appendix/market-filters.html">Android Market Filters</a></li> + </ul> +</dd> + +<h2 id="market-texture-filtering">Android Market and texture compression filtering</h2> + +<p>Android Market filters the applications that are visible to users, so that +users can see and download only those applications that are compatible with +their devices. One of the ways Market filters applications is by texture +compression compatibility, giving you control over the availability of your +application to various devices, based on the capabilities of their GPUs.</p> + +<p>To determine an application's texture compression compatibility with a given +user's device, Android Market compares:</p> + +<ul> +<li>Texture compression formats that are supported by the application — +an application declares its supported texture compression formats in +<code><supports-gl-texture></code> elements in its manifest <br/>with...</li> +<li>Texture compression formats that are supported by the GPU on the device — +a device reports the formats it supports as read-only system properties.</li> +</ul> + +<p>Each time you upload an application to the Android Market Publisher Site, +Android Market scans the application's manifest file and looks for any +<code><supports-gl-texture></code> elements. It extracts the +format descriptors from the elements and stores them internally as +metadata associated with the application <code>.apk</code> and the application +version. </p> + +<p>When a user searches or browses for applications on Android Market, +the service compares the texture compression formats supported by the application +with those supported by the user's device. The comparison is based on the format +descriptor strings and a match must be exact.</p> + +<p>If <em>any</em> of an application's supported texture compression formats is +also supported by the device, Android Market allows the user to see the +application and potentially download it. Otherwise, if none of the application's +formats is supported by the device, Android Market filters the application so +that it is not available for download. </p> + +<p>If an application does not declare any <code><supports-gl-texture></code> elements, +Android Market does not apply any filtering based on GL texture compression format.</p> + +</dl> + diff --git a/docs/html/guide/topics/manifest/supports-screens-element.jd b/docs/html/guide/topics/manifest/supports-screens-element.jd index 92c769e37c18..ee99a3706349 100644 --- a/docs/html/guide/topics/manifest/supports-screens-element.jd +++ b/docs/html/guide/topics/manifest/supports-screens-element.jd @@ -1,4 +1,6 @@ page.title=<supports-screens> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/uses-configuration-element.jd b/docs/html/guide/topics/manifest/uses-configuration-element.jd index 4578c63fa72f..20ec85f51af5 100755 --- a/docs/html/guide/topics/manifest/uses-configuration-element.jd +++ b/docs/html/guide/topics/manifest/uses-configuration-element.jd @@ -1,4 +1,6 @@ page.title=<uses-configuration> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <!-- ##api level 3## see comment below --> diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd index 0828e8b25edc..fec6a980e305 100644 --- a/docs/html/guide/topics/manifest/uses-feature-element.jd +++ b/docs/html/guide/topics/manifest/uses-feature-element.jd @@ -1,4 +1,6 @@ page.title=<uses-feature> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/uses-library-element.jd b/docs/html/guide/topics/manifest/uses-library-element.jd index 1d38c1afee0a..d94ad9fb3ab7 100644 --- a/docs/html/guide/topics/manifest/uses-library-element.jd +++ b/docs/html/guide/topics/manifest/uses-library-element.jd @@ -1,4 +1,6 @@ page.title=<uses-library> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> @@ -44,7 +46,7 @@ page.title=<uses-library> <dd> Android Market filters applications based on the libraries installed on the user's device. For more information about filtering, see the topic - <a href="{@docRoot}/guide/appendix/market-filters.html">Market Filters</a>. + <a href="{@docRoot}guide/appendix/market-filters.html">Market Filters</a>. </dd> </dl> <p> diff --git a/docs/html/guide/topics/manifest/uses-permission-element.jd b/docs/html/guide/topics/manifest/uses-permission-element.jd index 085b9f0eeca2..967fc5a65316 100644 --- a/docs/html/guide/topics/manifest/uses-permission-element.jd +++ b/docs/html/guide/topics/manifest/uses-permission-element.jd @@ -1,4 +1,6 @@ page.title=<uses-permission> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd index 971d4cb3aba7..b371f34ba72e 100644 --- a/docs/html/guide/topics/manifest/uses-sdk-element.jd +++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd @@ -1,4 +1,6 @@ page.title=<uses-sdk> +parent.title=The AndroidManifest.xml File +parent.link=manifest-intro.html @jd:body <dl class="xml"> diff --git a/docs/html/guide/topics/ui/drag-drop.jd b/docs/html/guide/topics/ui/drag-drop.jd index c33c5078a9e5..0329c192e5ef 100644 --- a/docs/html/guide/topics/ui/drag-drop.jd +++ b/docs/html/guide/topics/ui/drag-drop.jd @@ -1,5 +1,8 @@ page.title=Dragging and Dropping +parent.title=User Interface +parent.link=index.html @jd:body + <div id="qv-wrapper"> <div id="qv"> <h2>Quickview</h2> diff --git a/docs/html/guide/topics/ui/notifiers/index.jd b/docs/html/guide/topics/ui/notifiers/index.jd index d29324cc8797..8fc57fc750d3 100644 --- a/docs/html/guide/topics/ui/notifiers/index.jd +++ b/docs/html/guide/topics/ui/notifiers/index.jd @@ -1,4 +1,6 @@ page.title=Notifying the User +parent.title=User Interface +parent.link=../index.html @jd:body <div id="qv-wrapper"> diff --git a/docs/html/resources/community-more.jd b/docs/html/resources/community-more.jd index 9f16feaffbf2..df729265cc05 100644 --- a/docs/html/resources/community-more.jd +++ b/docs/html/resources/community-more.jd @@ -24,7 +24,11 @@ page.title=IRC and Twitter </tr> </table> -<p>If you haven't used IRC before, check <a href="http://en.wikipedia.org/wiki/List_of_IRC_clients">http://en.wikipedia.org/wiki/List_of_IRC_clients »</a> for a helpful list of IRC clients. Alternatively, you could also use this <a href="http://java.freenode.net/index.php?channel=android-dev">web interface »</a>, which does not require any installation, to join discussions on the Android IRC channels. </p> +<p>If you haven't used IRC before, check <a +href="http://en.wikipedia.org/wiki/List_of_IRC_clients">http://en.wikipedia.org/wiki/ +List_of_IRC_clients »</a> for a helpful list of IRC clients. Alternatively, you could also use +this <a href="http://webchat.freenode.net/?channels=android-dev">web interface »</a>, which +does not require any installation, to join discussions on the Android IRC channels. </p> <p>Here are some tips for using IRC:</h4> diff --git a/docs/html/resources/resources-data.js b/docs/html/resources/resources-data.js index b80e59a556b0..e919de94ee0a 100644 --- a/docs/html/resources/resources-data.js +++ b/docs/html/resources/resources-data.js @@ -496,7 +496,7 @@ var ANDROID_RESOURCES = [ } }, { - tags: ['sample', 'new'], + tags: ['sample', 'new', 'newfeature', 'performance', 'gamedev', 'gl'], path: 'samples/Renderscript/index.html', title: { en: 'Renderscript' diff --git a/docs/html/sdk/android-3.0-highlights.jd b/docs/html/sdk/android-3.0-highlights.jd index 591f08806da0..ebeb3789f48d 100644 --- a/docs/html/sdk/android-3.0-highlights.jd +++ b/docs/html/sdk/android-3.0-highlights.jd @@ -46,7 +46,9 @@ page.title=Android 3.0 Platform Highlights <p>Welcome to Android 3.0!</p> <p>The Android 3.0 platform introduces many new and exciting features for users and developers. -This document provides a glimpse of some of the new features and technologies, as delivered in the Android 3.0 Preview SDK. For more information about the SDK or how to download it, please see the <a href="{@docRoot}sdk/preview/index.html">Preview SDK</a> document.</p> +This document provides a glimpse of some of the new features and technologies, as delivered in +Android 3.0. For a more detailed look at new developer APIs, see the <a +href="{@docRoot}sdk/android-3.0.html">Android 3.0 Platform</a> document.</p> <ul> <li><a href="#UserFeatures">New User Features</a></li> @@ -259,7 +261,8 @@ allowscriptaccess="always" allowfullscreen="true" width="278" height="180"></emb </object> </div> -<p>For more information about the new developer APIs, see the Android 3.0 Platform notes in the SDK Preview documentation, available by download through the Android SDK Manager.</p> +<p>For more information about the new developer APIs, see the <a +href="{@docRoot}sdk/android-3.0.html">Android 3.0 Platform</a> document.</p> <p>For a video overview of platform features, see the Android 3.0 Sneak Peek. </p> diff --git a/docs/html/sdk/android-3.0.jd b/docs/html/sdk/android-3.0.jd index 6c88146d7c84..6c087bb41b7c 100644 --- a/docs/html/sdk/android-3.0.jd +++ b/docs/html/sdk/android-3.0.jd @@ -1,4 +1,4 @@ -page.title=Android 3.0 Platform Preview +page.title=Android 3.0 Platform sdk.platform.version=3.0 sdk.platform.apiLevel=11 @jd:body @@ -25,7 +25,7 @@ Differences Report »</a> </li> <h2>See Also</h2> <ol> - <li><a href="{@docRoot}sdk/android-3.0-optimize.html">Optimizing Apps for Android 3.0</a></li> + <li><a href="{@docRoot}guide/practices/optimizing-for-3.0.html">Optimizing Apps for Android 3.0</a></li> </ol> </div> @@ -48,10 +48,12 @@ href="{@docRoot}sdk/index.html">download the SDK Starter Package</a> first.</p> href="{@docRoot}sdk/android-{@sdkPlatformVersion}-highlights.html">Platform Highlights</a>.</p> -<p>Also see the <a href="{@docRoot}sdk/android-3.0-optimize.html">Optimizing Apps for Android -3.0</a> document for information about how to optimize your existing applications for Android 3.0 -devices, even if you want to remain compatible with previous versions.</p> - +<p class="note"><strong>Note:</strong> +If you've already published an Android application, please test and optimize your application on +Android 3.0 as soon as possible. You should do so to be sure your application provides the best +experience possible on the latest Android-powered devices. For information about what you can do, +read <a href="{@docRoot}guide/practices/optimizing-for-3.0.html">Optimizing Apps for Android +3.0</a>.</p> <h2 id="relnotes">Revisions</h2> @@ -866,8 +868,8 @@ dimensions.</p> <h3>JSON utilities</h3> <p>New classes, {@link android.util.JsonReader} and {@link android.util.JsonWriter}, help you -read and write JSON streams. The new APIs compliment the {@link org.json} classes which manipulate a -document in memory.</p> +read and write JSON streams. The new APIs complement the {@link org.json} classes, which manipulate +a document in memory.</p> <p>You can create an instance of {@link android.util.JsonReader} by calling its constructor method and passing the {@link java.io.InputStreamReader} that feeds the JSON string. diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd index df8869e4b854..7f6f0105ad67 100644 --- a/docs/html/sdk/index.jd +++ b/docs/html/sdk/index.jd @@ -2,20 +2,20 @@ page.title=Android SDK sdk.redirect=0 sdk.win_installer=installer_r10-windows.exe -sdk.win_installer_bytes=32845713 -sdk.win_installer_checksum=4e4356c472a6271ac9c062df0219dcb3 +sdk.win_installer_bytes=32878481 +sdk.win_installer_checksum=8ffa2dd734829d0bbd3ea601b50b36c7 sdk.win_download=android-sdk_r10-windows.zip -sdk.win_bytes=30112516 -sdk.win_checksum=643a75d99f5d4ca39dcf743fe894d599 +sdk.win_bytes=32832260 +sdk.win_checksum=1e42b8f528d9ca6d9b887c58c6f1b9a2 sdk.mac_download=android-sdk_r10-mac_x86.zip -sdk.mac_bytes=28224540 -sdk.mac_checksum=4d0a99a458e4f4bde65a01f8545f27e9 +sdk.mac_bytes=28847132 +sdk.mac_checksum=e3aa5578a6553b69cc36659c9505be3f sdk.linux_download=android-sdk_r10-linux_x86.tgz -sdk.linux_bytes=26556013 -sdk.linux_checksum=10cafdd44771bfe2ba9d4440886389e7 +sdk.linux_bytes=26981997 +sdk.linux_checksum=c022dda3a56c8a67698e6a39b0b1a4e0 @jd:body diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd index 40231a315e5d..bc9ba4be6259 100644 --- a/docs/html/sdk/ndk/index.jd +++ b/docs/html/sdk/ndk/index.jd @@ -1,16 +1,16 @@ ndk=true -ndk.win_download=android-ndk-r6-windows.zip -ndk.win_bytes=64147764 -ndk.win_checksum=771b56328b7fc7751aa8040fb9dd09f0 +ndk.win_download=android-ndk-r5b-windows.zip +ndk.win_bytes=61299831 +ndk.win_checksum=87745ada305ab639399161ab4faf684c -ndk.mac_download=android-ndk-r6-darwin-x86.tar.bz2 -ndk.mac_bytes=50244722 -ndk.mac_checksum=d107f6d63478b73e09ed2eecd4c62bd3 +ndk.mac_download=android-ndk-r5b-darwin-x86.tar.bz2 +ndk.mac_bytes=50210863 +ndk.mac_checksum=019a14622a377b3727ec789af6707037 -ndk.linux_download=android-ndk-r6-linux-x86.tar.bz2 -ndk.linux_bytes=44088689 -ndk.linux_checksum=c83c3ab5a5e5a3b3fe7b907735ce77d4 +ndk.linux_download=android-ndk-r5b-linux-x86.tar.bz2 +ndk.linux_bytes=44138539 +ndk.linux_checksum=4c0045ddc2bfd657be9d5177d0e0b7e7 page.title=Android NDK @jd:body @@ -61,55 +61,6 @@ padding: .25em 1em; <div class="toggleable open"> <a href="#" - onclick="return toggleDiv(this)"><img src="{@docRoot}assets/images/triangle-opened.png" - class="toggle-img" - height="9px" - width="9px" /> Android NDK, Revision 6</a> <em>(February 2011)</em> - - <div class="toggleme"> - <p>This release of the NDK introduces the following header files:</p> - <ul> - <li><p><code><android/asset_manager.h></code>: Allows access to assets - using 64-bit file offsets and sizes. This is useful for very large assets that exceed - 2GB, as required by some games. The following APIs are provided:<p> - <ul> - <li><code>AAsset_getLength64</code></li> - <li><code>AAsset_getRemainingLength64</code></li> - <li><code>AAsset_openFileDescriptor64</code></li> - <li><code>AAsset_seek64</code></li> - </ul> - </li> - - <li><code><android/input.h></code>: Provides the following AMETA_XXX constants - that are related to the new input framework in Honeycomb: -<pre> -AMETA_FUNCTION_ON = 0x08, -AMETA_CTRL_ON = 0x1000, -AMETA_CTRL_LEFT_ON = 0x2000, -AMETA_CTRL_RIGHT_ON = 0x4000, -AMETA_META_ON = 0x10000, -AMETA_META_LEFT_ON = 0x20000, -AMETA_META_RIGHT_ON = 0x40000, -AMETA_CAPS_LOCK_ON = 0x100000, -AMETA_NUM_LOCK_ON = 0x200000, -AMETA_SCROLL_LOCK_ON = 0x400000, -</pre> - </li> - - <li><code><android/keycodes></code>: Provides <code>AKEYCODE_XXX</code> - constants that are related to the new input framework in Honeycomb. - </li> - - <li><code><android/native_activity.h></code>: Adds a new field to the - system-allocated <code>ANativeActivity</code> structure named <code>obbPath</code> that - contains the path of your application's OBB files, if any. - </li> - </ul> - </div> - </div> - -<div class="toggleable closed"> - <a href="#" onclick="return toggleDiv(this)"><img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs index c1894d89c393..a1c26db3208c 100644 --- a/docs/html/sdk/sdk_toc.cs +++ b/docs/html/sdk/sdk_toc.cs @@ -80,7 +80,6 @@ class="new">new!</span></li> <div><a href="<?cs var:toroot ?>sdk/android-3.0.html"> <span class="en">Android 3.0 Platform</span></a> <span class="new">new!</span></div> <ul> - <li><a href="<?cs var:toroot ?>sdk/android-3.0-optimize.html">Optimizing Apps for 3.0</a></li> <li><a href="<?cs var:toroot ?>sdk/android-3.0-highlights.html">Platform Highlights</a></li> <li><a href="<?cs var:toroot ?>sdk/api_diff/11/changes.html">API Differences Report »</a></li> </ul> @@ -152,8 +151,8 @@ class="new">new!</span></li> <span style="display:none" class="zh-TW"></span> </h2> <ul> - <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r6</a> - <span class="new">new!</span></li> + <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r5b</a> + </li> <li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li> </ul> </li> diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index cffee5fd4e9c..8d1756152eca 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -240,7 +240,7 @@ public class BitmapFactory { /** * The resulting height of the bitmap, set independent of the state of * inJustDecodeBounds. However, if there is an error trying to decode, - * outHeight will be set to -1. + * outHeight will be set to -1. */ public int outHeight; diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index 65c6ccfa25d7..33f050c40028 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -624,6 +624,8 @@ public class GradientDrawable extends Drawable { int shapeType = a.getInt( com.android.internal.R.styleable.GradientDrawable_shape, RECTANGLE); + boolean dither = a.getBoolean( + com.android.internal.R.styleable.GradientDrawable_dither, false); if (shapeType == RING) { st.mInnerRadius = a.getDimensionPixelSize( @@ -645,10 +647,11 @@ public class GradientDrawable extends Drawable { a.recycle(); setShape(shapeType); - + setDither(dither); + int type; - final int innerDepth = parser.getDepth()+1; + final int innerDepth = parser.getDepth() + 1; int depth; while ((type=parser.next()) != XmlPullParser.END_DOCUMENT && ((depth=parser.getDepth()) >= innerDepth @@ -811,11 +814,12 @@ public class GradientDrawable extends Drawable { com.android.internal.R.styleable.DrawableCorners_bottomRightRadius, radius); if (topLeftRadius != radius || topRightRadius != radius || bottomLeftRadius != radius || bottomRightRadius != radius) { + // The corner radii are specified in clockwise order (see Path.addRoundRect()) setCornerRadii(new float[] { topLeftRadius, topLeftRadius, topRightRadius, topRightRadius, - bottomLeftRadius, bottomLeftRadius, - bottomRightRadius, bottomRightRadius + bottomRightRadius, bottomRightRadius, + bottomLeftRadius, bottomLeftRadius }); } a.recycle(); diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java index cb8774ddf874..4445b6a8636e 100644 --- a/graphics/java/android/graphics/drawable/ShapeDrawable.java +++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java @@ -286,7 +286,7 @@ public class ShapeDrawable extends Drawable { protected boolean inflateTag(String name, Resources r, XmlPullParser parser, AttributeSet attrs) { - if (name.equals("padding")) { + if ("padding".equals(name)) { TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ShapeDrawablePadding); setPadding( @@ -315,7 +315,10 @@ public class ShapeDrawable extends Drawable { int color = mShapeState.mPaint.getColor(); color = a.getColor(com.android.internal.R.styleable.ShapeDrawable_color, color); mShapeState.mPaint.setColor(color); - + + boolean dither = a.getBoolean(com.android.internal.R.styleable.ShapeDrawable_dither, false); + mShapeState.mPaint.setDither(dither); + setIntrinsicWidth((int) a.getDimension(com.android.internal.R.styleable.ShapeDrawable_width, 0f)); setIntrinsicHeight((int) diff --git a/include/camera/Camera.h b/include/camera/Camera.h index e5f7e623c476..f3c8f64ad3de 100644 --- a/include/camera/Camera.h +++ b/include/camera/Camera.h @@ -66,16 +66,17 @@ namespace android { // msgType in notifyCallback and dataCallback functions enum { - CAMERA_MSG_ERROR = 0x001, - CAMERA_MSG_SHUTTER = 0x002, - CAMERA_MSG_FOCUS = 0x004, - CAMERA_MSG_ZOOM = 0x008, - CAMERA_MSG_PREVIEW_FRAME = 0x010, - CAMERA_MSG_VIDEO_FRAME = 0x020, - CAMERA_MSG_POSTVIEW_FRAME = 0x040, - CAMERA_MSG_RAW_IMAGE = 0x080, - CAMERA_MSG_COMPRESSED_IMAGE = 0x100, - CAMERA_MSG_ALL_MSGS = 0x1FF + CAMERA_MSG_ERROR = 0x0001, + CAMERA_MSG_SHUTTER = 0x0002, + CAMERA_MSG_FOCUS = 0x0004, + CAMERA_MSG_ZOOM = 0x0008, + CAMERA_MSG_PREVIEW_FRAME = 0x0010, + CAMERA_MSG_VIDEO_FRAME = 0x0020, + CAMERA_MSG_POSTVIEW_FRAME = 0x0040, + CAMERA_MSG_RAW_IMAGE = 0x0080, + CAMERA_MSG_COMPRESSED_IMAGE = 0x0100, + CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x0200, + CAMERA_MSG_ALL_MSGS = 0xFFFF }; // cmdType in sendCommand functions @@ -207,7 +208,7 @@ public: status_t cancelAutoFocus(); // take a picture - picture returned from callback - status_t takePicture(); + status_t takePicture(int msgType); // set preview/capture parameters - key/value pairs status_t setParameters(const String8& params); diff --git a/include/camera/ICamera.h b/include/camera/ICamera.h index b2310a64c7d7..2344b3f3f423 100644 --- a/include/camera/ICamera.h +++ b/include/camera/ICamera.h @@ -70,7 +70,7 @@ public: virtual status_t startRecording() = 0; // stop recording mode - virtual void stopRecording() = 0; + virtual void stopRecording() = 0; // get recording state virtual bool recordingEnabled() = 0; @@ -84,8 +84,14 @@ public: // cancel auto focus virtual status_t cancelAutoFocus() = 0; - // take a picture - virtual status_t takePicture() = 0; + /* + * take a picture. + * @param msgType the message type an application selectively turn on/off + * on a photo-by-photo basis. The supported message types are: + * CAMERA_MSG_SHUTTER, CAMERA_MSG_RAW_IMAGE, CAMERA_MSG_COMPRESSED_IMAGE, + * and CAMERA_MSG_POSTVIEW_FRAME. Any other message types will be ignored. + */ + virtual status_t takePicture(int msgType) = 0; // set preview/capture parameters - key/value pairs virtual status_t setParameters(const String8& params) = 0; diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h index 0bfb166a464d..cce9129c0f80 100644 --- a/include/media/IMediaPlayerService.h +++ b/include/media/IMediaPlayerService.h @@ -54,6 +54,22 @@ public: virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0; virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0; virtual sp<IOMX> getOMX() = 0; + + // codecs usage tracking for the battery app + enum BatteryDataBits { + // tracking audio codec + kBatteryDataTrackAudio = 1, + // tracking video codec + kBatteryDataTrackVideo = 2, + // codec is started, otherwise codec is paused + kBatteryDataCodecStarted = 4, + // tracking decoder (for media player), + // otherwise tracking encoder (for media recorder) + kBatteryDataTrackDecoder = 8, + }; + + virtual void addBatteryData(uint32_t params) = 0; + virtual status_t pullBatteryData(Parcel* reply) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h index c24c0dbcb28f..f8d96cf1e84c 100644 --- a/include/utils/RefBase.h +++ b/include/utils/RefBase.h @@ -18,7 +18,6 @@ #define ANDROID_REF_BASE_H #include <cutils/atomic.h> -#include <utils/TextOutput.h> #include <stdint.h> #include <sys/types.h> @@ -27,6 +26,10 @@ // --------------------------------------------------------------------------- namespace android { +class TextOutput; +TextOutput& printStrongPointer(TextOutput& to, const void* val); +TextOutput& printWeakPointer(TextOutput& to, const void* val); + template<typename T> class wp; // --------------------------------------------------------------------------- @@ -427,8 +430,7 @@ sp<T>::sp(T* p, weakref_type* refs) template <typename T> inline TextOutput& operator<<(TextOutput& to, const sp<T>& val) { - to << "sp<>(" << val.get() << ")"; - return to; + return printStrongPointer(to, val.get()); } // --------------------------------------------------------------------------- @@ -585,8 +587,7 @@ void wp<T>::clear() template <typename T> inline TextOutput& operator<<(TextOutput& to, const wp<T>& val) { - to << "wp<>(" << val.unsafe_get() << ")"; - return to; + return printWeakPointer(to, val.unsafe_get()); } }; // namespace android diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp index 907f119b8174..e2883121e497 100644 --- a/libs/camera/Camera.cpp +++ b/libs/camera/Camera.cpp @@ -301,12 +301,12 @@ status_t Camera::cancelAutoFocus() } // take a picture -status_t Camera::takePicture() +status_t Camera::takePicture(int msgType) { - LOGV("takePicture"); + LOGV("takePicture: 0x%x", msgType); sp <ICamera> c = mCamera; if (c == 0) return NO_INIT; - return c->takePicture(); + return c->takePicture(msgType); } // set preview/capture parameters - key/value pairs diff --git a/libs/camera/ICamera.cpp b/libs/camera/ICamera.cpp index 0881d65ae3d2..931b57d048aa 100644 --- a/libs/camera/ICamera.cpp +++ b/libs/camera/ICamera.cpp @@ -223,11 +223,12 @@ public: } // take a picture - returns an IMemory (ref-counted mmap) - status_t takePicture() + status_t takePicture(int msgType) { - LOGV("takePicture"); + LOGV("takePicture: 0x%x", msgType); Parcel data, reply; data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); + data.writeInt32(msgType); remote()->transact(TAKE_PICTURE, data, &reply); status_t ret = reply.readInt32(); return ret; @@ -401,7 +402,8 @@ status_t BnCamera::onTransact( case TAKE_PICTURE: { LOGV("TAKE_PICTURE"); CHECK_INTERFACE(ICamera, data, reply); - reply->writeInt32(takePicture()); + int msgType = data.readInt32(); + reply->writeInt32(takePicture(msgType)); return NO_ERROR; } break; case SET_PARAMETERS: { diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp index 0bd1af4ebf18..f934eec80f80 100644 --- a/libs/utils/RefBase.cpp +++ b/libs/utils/RefBase.cpp @@ -23,6 +23,7 @@ #include <utils/KeyedVector.h> #include <utils/Log.h> #include <utils/threads.h> +#include <utils/TextOutput.h> #include <stdlib.h> #include <stdio.h> @@ -530,5 +531,20 @@ bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id) void RefBase::onLastWeakRef(const void* /*id*/) { } - + +// --------------------------------------------------------------------------- + +TextOutput& printStrongPointer(TextOutput& to, const void* val) +{ + to << "sp<>(" << val << ")"; + return to; +} + +TextOutput& printWeakPointer(TextOutput& to, const void* val) +{ + to << "wp<>(" << val << ")"; + return to; +} + + }; // namespace android diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java index ee2c1e8cb2d0..a027bc629967 100644 --- a/media/java/android/media/MediaFile.java +++ b/media/java/android/media/MediaFile.java @@ -141,7 +141,9 @@ public class MediaFile { private static boolean isWMAEnabled() { List<AudioDecoder> decoders = DecoderCapabilities.getAudioDecoders(); - for (AudioDecoder decoder: decoders) { + int count = decoders.size(); + for (int i = 0; i < count; i++) { + AudioDecoder decoder = decoders.get(i); if (decoder == AudioDecoder.AUDIO_DECODER_WMA) { return true; } @@ -149,6 +151,18 @@ public class MediaFile { return false; } + private static boolean isWMVEnabled() { + List<VideoDecoder> decoders = DecoderCapabilities.getVideoDecoders(); + int count = decoders.size(); + for (int i = 0; i < count; i++) { + VideoDecoder decoder = decoders.get(i); + if (decoder == VideoDecoder.VIDEO_DECODER_WMV) { + return true; + } + } + return false; + } + static { addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg", MtpConstants.FORMAT_MP3); addFileType("M4A", FILE_TYPE_M4A, "audio/mp4", MtpConstants.FORMAT_MPEG); @@ -184,8 +198,10 @@ public class MediaFile { addFileType("WEBM", FILE_TYPE_MKV, "video/x-matroska"); addFileType("TS", FILE_TYPE_MP2TS, "video/mp2ts"); - addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv", MtpConstants.FORMAT_WMV); - addFileType("ASF", FILE_TYPE_ASF, "video/x-ms-asf"); + if (isWMVEnabled()) { + addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv", MtpConstants.FORMAT_WMV); + addFileType("ASF", FILE_TYPE_ASF, "video/x-ms-asf"); + } addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg", MtpConstants.FORMAT_EXIF_JPEG); addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg", MtpConstants.FORMAT_EXIF_JPEG); diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index f61ac0f794b8..9c92ace2f47e 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1055,7 +1055,14 @@ public class MediaPlayer /** * Releases resources associated with this MediaPlayer object. * It is considered good practice to call this method when you're - * done using the MediaPlayer. + * done using the MediaPlayer. For instance, whenever the Activity + * of an application is paused, this method should be invoked to + * release the MediaPlayer object. In addition to unnecessary resources + * (such as memory and instances of codecs) being hold, failure to + * call this method immediately if a MediaPlayer object is no longer + * needed may also lead to continuous battery consumption for mobile + * devices, and playback failure if no multiple instances of the + * same codec is supported on a device. */ public void release() { stayAwake(false); @@ -1228,6 +1235,14 @@ public class MediaPlayer private native final void native_setup(Object mediaplayer_this); private native final void native_finalize(); + /** + * @param reply Parcel with audio/video duration info for battery + tracking usage + * @return The status code. + * {@hide} + */ + public native static int native_pullBatteryData(Parcel reply); + @Override protected void finalize() { native_finalize(); } diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java index ad2bf954543e..e0df257eca55 100644 --- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java +++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java @@ -3807,7 +3807,6 @@ class MediaArtistNativeHelper { } catch (Throwable e) { // Allocating to new size with Fixed count try { - System.gc(); rgb888 = new int[thumbnailSize * MAX_THUMBNAIL_PERMITTED]; bitmaps = new Bitmap[MAX_THUMBNAIL_PERMITTED]; thumbnailCount = MAX_THUMBNAIL_PERMITTED; diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java index 69088edd32b7..4faa83a02fe3 100755 --- a/media/java/android/media/videoeditor/MediaImageItem.java +++ b/media/java/android/media/videoeditor/MediaImageItem.java @@ -197,7 +197,6 @@ public class MediaImageItem extends MediaItem { fl.close(); } imageBitmap.recycle(); - System.gc(); } /* diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 0884e350d769..ca544328952c 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -36,6 +36,8 @@ #include "android_util_Binder.h" #include <binder/Parcel.h> #include <surfaceflinger/Surface.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> // ---------------------------------------------------------------------------- @@ -723,6 +725,21 @@ static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL ); } +static jint +android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject java_reply) +{ + sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player")); + sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); + if (service.get() == NULL) { + jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService"); + return UNKNOWN_ERROR; + } + + Parcel *reply = parcelForJavaObject(env, java_reply); + + return service->pullBatteryData(reply); +} + // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { @@ -758,6 +775,7 @@ static JNINativeMethod gMethods[] = { {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, {"setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel}, {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect}, + {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData}, }; static const char* const kClassPathName = "android/media/MediaPlayer"; diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index 77199e12e719..17a0362862e0 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -37,7 +37,9 @@ enum { DECODE_FD, CREATE_MEDIA_RECORDER, CREATE_METADATA_RETRIEVER, - GET_OMX + GET_OMX, + ADD_BATTERY_DATA, + PULL_BATTERY_DATA }; class BpMediaPlayerService: public BpInterface<IMediaPlayerService> @@ -156,6 +158,19 @@ public: remote()->transact(GET_OMX, data, &reply); return interface_cast<IOMX>(reply.readStrongBinder()); } + + virtual void addBatteryData(uint32_t params) { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + data.writeInt32(params); + remote()->transact(ADD_BATTERY_DATA, data, &reply); + } + + virtual status_t pullBatteryData(Parcel* reply) { + Parcel data; + data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + return remote()->transact(PULL_BATTERY_DATA, data, reply); + } }; IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService"); @@ -270,6 +285,17 @@ status_t BnMediaPlayerService::onTransact( reply->writeStrongBinder(omx->asBinder()); return NO_ERROR; } break; + case ADD_BATTERY_DATA: { + CHECK_INTERFACE(IMediaPlayerService, data, reply); + uint32_t params = data.readInt32(); + addBatteryData(params); + return NO_ERROR; + } break; + case PULL_BATTERY_DATA: { + CHECK_INTERFACE(IMediaPlayerService, data, reply); + pullBatteryData(reply); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 60bdd6233b91..8c6f76b19996 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -23,6 +23,7 @@ #include <sys/types.h> #include <sys/stat.h> +#include <sys/time.h> #include <dirent.h> #include <unistd.h> @@ -51,6 +52,8 @@ #include <media/Metadata.h> #include <media/AudioTrack.h> +#include <private/android_filesystem_config.h> + #include "MediaRecorderClient.h" #include "MediaPlayerService.h" #include "MetadataRetrieverClient.h" @@ -1762,4 +1765,93 @@ int MediaPlayerService::AudioCache::getSessionId() return 0; } +void MediaPlayerService::addBatteryData(uint32_t params) +{ + Mutex::Autolock lock(mLock); + int uid = IPCThreadState::self()->getCallingUid(); + if (uid == AID_MEDIA) { + return; + } + int index = mBatteryData.indexOfKey(uid); + int32_t time = systemTime() / 1000000L; + + if (index < 0) { // create a new entry for this UID + BatteryUsageInfo info; + info.audioTotalTime = 0; + info.videoTotalTime = 0; + info.audioLastTime = 0; + info.videoLastTime = 0; + info.refCount = 0; + + mBatteryData.add(uid, info); + } + + BatteryUsageInfo &info = mBatteryData.editValueFor(uid); + + if (params & kBatteryDataCodecStarted) { + if (params & kBatteryDataTrackAudio) { + info.audioLastTime -= time; + info.refCount ++; + } + if (params & kBatteryDataTrackVideo) { + info.videoLastTime -= time; + info.refCount ++; + } + } else { + if (info.refCount == 0) { + LOGW("Battery track warning: refCount is already 0"); + return; + } else if (info.refCount < 0) { + LOGE("Battery track error: refCount < 0"); + mBatteryData.removeItem(uid); + return; + } + + if (params & kBatteryDataTrackAudio) { + info.audioLastTime += time; + info.refCount --; + } + if (params & kBatteryDataTrackVideo) { + info.videoLastTime += time; + info.refCount --; + } + + // no stream is being played by this UID + if (info.refCount == 0) { + info.audioTotalTime += info.audioLastTime; + info.audioLastTime = 0; + info.videoTotalTime += info.videoLastTime; + info.videoLastTime = 0; + } + } +} + +status_t MediaPlayerService::pullBatteryData(Parcel* reply) { + Mutex::Autolock lock(mLock); + BatteryUsageInfo info; + int size = mBatteryData.size(); + + reply->writeInt32(size); + int i = 0; + + while (i < size) { + info = mBatteryData.valueAt(i); + + reply->writeInt32(mBatteryData.keyAt(i)); //UID + reply->writeInt32(info.audioTotalTime); + reply->writeInt32(info.videoTotalTime); + + info.audioTotalTime = 0; + info.videoTotalTime = 0; + + // remove the UID entry where no stream is being played + if (info.refCount <= 0) { + mBatteryData.removeItemsAt(i); + size --; + i --; + } + i++; + } + return NO_ERROR; +} } // namespace android diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 62f8ed67bf96..9f41db034028 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -204,7 +204,31 @@ public: void removeClient(wp<Client> client); + // For battery usage tracking purpose + struct BatteryUsageInfo { + // how many streams are being played by one UID + int refCount; + // a temp variable to store the duration(ms) of audio codecs + // when we start a audio codec, we minus the system time from audioLastTime + // when we pause it, we add the system time back to the audioLastTime + // so after the pause, audioLastTime = pause time - start time + // if multiple audio streams are played (or recorded), then audioLastTime + // = the total playing time of all the streams + int32_t audioLastTime; + // when all the audio streams are being paused, we assign audioLastTime to + // this variable, so this value could be provided to the battery app + // in the next pullBatteryData call + int32_t audioTotalTime; + + int32_t videoLastTime; + int32_t videoTotalTime; + }; + KeyedVector<int, BatteryUsageInfo> mBatteryData; + // Collect info of the codec usage from media player and media recorder + virtual void addBatteryData(uint32_t params); + // API for the Battery app to pull the data of codecs usage + virtual status_t pullBatteryData(Parcel* reply); private: class Client : public BnMediaPlayer { diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 87fdbf248c37..e3dfabb02493 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -20,6 +20,10 @@ #include "StagefrightRecorder.h" +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> + +#include <media/IMediaPlayerService.h> #include <media/stagefright/AudioSource.h> #include <media/stagefright/AMRWriter.h> #include <media/stagefright/CameraSource.h> @@ -46,9 +50,23 @@ namespace android { +// To collect the encoder usage for the battery app +static void addBatteryData(uint32_t params) { + sp<IBinder> binder = + defaultServiceManager()->getService(String16("media.player")); + sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); + CHECK(service.get() != NULL); + + service->addBatteryData(params); +} + + StagefrightRecorder::StagefrightRecorder() : mWriter(NULL), mWriterAux(NULL), - mOutputFd(-1), mOutputFdAux(-1) { + mOutputFd(-1), mOutputFdAux(-1), + mAudioSource(AUDIO_SOURCE_LIST_END), + mVideoSource(VIDEO_SOURCE_LIST_END), + mStarted(false) { LOGV("Constructor"); reset(); @@ -745,30 +763,54 @@ status_t StagefrightRecorder::start() { return UNKNOWN_ERROR; } + status_t status = OK; + switch (mOutputFormat) { case OUTPUT_FORMAT_DEFAULT: case OUTPUT_FORMAT_THREE_GPP: case OUTPUT_FORMAT_MPEG_4: - return startMPEG4Recording(); + status = startMPEG4Recording(); + break; case OUTPUT_FORMAT_AMR_NB: case OUTPUT_FORMAT_AMR_WB: - return startAMRRecording(); + status = startAMRRecording(); + break; case OUTPUT_FORMAT_AAC_ADIF: case OUTPUT_FORMAT_AAC_ADTS: - return startAACRecording(); + status = startAACRecording(); + break; case OUTPUT_FORMAT_RTP_AVP: - return startRTPRecording(); + status = startRTPRecording(); + break; case OUTPUT_FORMAT_MPEG2TS: - return startMPEG2TSRecording(); + status = startMPEG2TSRecording(); + break; default: LOGE("Unsupported output file format: %d", mOutputFormat); - return UNKNOWN_ERROR; + status = UNKNOWN_ERROR; + break; + } + + if ((status == OK) && (!mStarted)) { + mStarted = true; + + uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted; + if (mAudioSource != AUDIO_SOURCE_LIST_END) { + params |= IMediaPlayerService::kBatteryDataTrackAudio; + } + if (mVideoSource != VIDEO_SOURCE_LIST_END) { + params |= IMediaPlayerService::kBatteryDataTrackVideo; + } + + addBatteryData(params); } + + return status; } sp<MediaSource> StagefrightRecorder::createAudioSource() { @@ -1458,6 +1500,21 @@ status_t StagefrightRecorder::pause() { mWriterAux->pause(); } + if (mStarted) { + mStarted = false; + + uint32_t params = 0; + if (mAudioSource != AUDIO_SOURCE_LIST_END) { + params |= IMediaPlayerService::kBatteryDataTrackAudio; + } + if (mVideoSource != VIDEO_SOURCE_LIST_END) { + params |= IMediaPlayerService::kBatteryDataTrackVideo; + } + + addBatteryData(params); + } + + return OK; } @@ -1494,6 +1551,21 @@ status_t StagefrightRecorder::stop() { } } + if (mStarted) { + mStarted = false; + + uint32_t params = 0; + if (mAudioSource != AUDIO_SOURCE_LIST_END) { + params |= IMediaPlayerService::kBatteryDataTrackAudio; + } + if (mVideoSource != VIDEO_SOURCE_LIST_END) { + params |= IMediaPlayerService::kBatteryDataTrackVideo; + } + + addBatteryData(params); + } + + return err; } diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 72225dbdd78d..2c440c1a0dec 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -107,6 +107,8 @@ private: bool mIsMetaDataStoredInVideoBuffers; MediaProfiles *mEncoderProfiles; + bool mStarted; + status_t setupMPEG4Recording( bool useSplitCameraSource, int outputFd, diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index b1d3630c67df..1b63ab2461c4 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -28,6 +28,8 @@ #include "include/MPEG2TSExtractor.h" #include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <media/IMediaPlayerService.h> #include <media/stagefright/foundation/hexdump.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/AudioPlayer.h> @@ -155,8 +157,17 @@ private: const AwesomeNativeWindowRenderer &); }; -//////////////////////////////////////////////////////////////////////////////// +// To collect the decoder usage +void addBatteryData(uint32_t params) { + sp<IBinder> binder = + defaultServiceManager()->getService(String16("media.player")); + sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); + CHECK(service.get() != NULL); + + service->addBatteryData(params); +} +//////////////////////////////////////////////////////////////////////////////// AwesomePlayer::AwesomePlayer() : mQueueStarted(false), mTimeSource(NULL), @@ -379,6 +390,17 @@ void AwesomePlayer::reset_l() { mDrmManagerClient = NULL; } + if (mFlags & PLAYING) { + uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder; + if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { + params |= IMediaPlayerService::kBatteryDataTrackAudio; + } + if (mVideoSource != NULL) { + params |= IMediaPlayerService::kBatteryDataTrackVideo; + } + addBatteryData(params); + } + if (mFlags & PREPARING) { mFlags |= PREPARE_CANCELLED; if (mConnectingDataSource != NULL) { @@ -779,6 +801,16 @@ status_t AwesomePlayer::play_l() { seekTo_l(0); } + uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted + | IMediaPlayerService::kBatteryDataTrackDecoder; + if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { + params |= IMediaPlayerService::kBatteryDataTrackAudio; + } + if (mVideoSource != NULL) { + params |= IMediaPlayerService::kBatteryDataTrackVideo; + } + addBatteryData(params); + return OK; } @@ -933,6 +965,16 @@ status_t AwesomePlayer::pause_l(bool at_eos) { Playback::PAUSE, 0); } + uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder; + if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { + params |= IMediaPlayerService::kBatteryDataTrackAudio; + } + if (mVideoSource != NULL) { + params |= IMediaPlayerService::kBatteryDataTrackVideo; + } + + addBatteryData(params); + return OK; } diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp index e6fe6186d45b..3689557bbf92 100644 --- a/media/libstagefright/CameraSourceTimeLapse.cpp +++ b/media/libstagefright/CameraSourceTimeLapse.cpp @@ -277,7 +277,7 @@ void CameraSourceTimeLapse::threadTimeLapseEntry() { // this thread as read() will make a copy of this last frame and keep // returning it in the quick stop mode. Mutex::Autolock autoLock(mQuickStopLock); - CHECK_EQ(OK, mCamera->takePicture()); + CHECK_EQ(OK, mCamera->takePicture(CAMERA_MSG_RAW_IMAGE)); if (mQuickStop) { LOGV("threadTimeLapseEntry: Exiting due to mQuickStop = true"); return; diff --git a/media/libstagefright/include/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h index 589d8370e283..4a1c827453e1 100644 --- a/media/libstagefright/include/AMRExtractor.h +++ b/media/libstagefright/include/AMRExtractor.h @@ -18,6 +18,7 @@ #define AMR_EXTRACTOR_H_ +#include <utils/Errors.h> #include <media/stagefright/MediaExtractor.h> namespace android { diff --git a/media/libstagefright/include/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h index 728980e5c281..ef71b8f21e0f 100644 --- a/media/libstagefright/include/MP3Extractor.h +++ b/media/libstagefright/include/MP3Extractor.h @@ -18,6 +18,7 @@ #define MP3_EXTRACTOR_H_ +#include <utils/Errors.h> #include <media/stagefright/MediaExtractor.h> namespace android { diff --git a/media/libstagefright/include/OggExtractor.h b/media/libstagefright/include/OggExtractor.h index a41f681e7af2..e97c8cdef486 100644 --- a/media/libstagefright/include/OggExtractor.h +++ b/media/libstagefright/include/OggExtractor.h @@ -18,6 +18,7 @@ #define OGG_EXTRACTOR_H_ +#include <utils/Errors.h> #include <media/stagefright/MediaExtractor.h> namespace android { diff --git a/media/libstagefright/include/WAVExtractor.h b/media/libstagefright/include/WAVExtractor.h index 9de197f67839..ce1f33ad9ff7 100644 --- a/media/libstagefright/include/WAVExtractor.h +++ b/media/libstagefright/include/WAVExtractor.h @@ -18,6 +18,7 @@ #define WAV_EXTRACTOR_H_ +#include <utils/Errors.h> #include <media/stagefright/MediaExtractor.h> namespace android { diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h index 02187552723a..afff8242a49c 100644 --- a/media/libstagefright/include/avc_utils.h +++ b/media/libstagefright/include/avc_utils.h @@ -19,6 +19,7 @@ #define AVC_UTILS_H_ #include <media/stagefright/foundation/ABuffer.h> +#include <utils/Errors.h> namespace android { diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk index 33c9d97aa319..1f1c68b6eb1c 100644 --- a/media/libstagefright/matroska/Android.mk +++ b/media/libstagefright/matroska/Android.mk @@ -2,11 +2,11 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - MatroskaExtractor.cpp \ - mkvparser.cpp \ + MatroskaExtractor.cpp LOCAL_C_INCLUDES:= \ - $(JNI_H_INCLUDE) \ + $(JNI_H_INCLUDE) \ + $(TOP)/external/libvpx/mkvparser \ $(TOP)/frameworks/base/include/media/stagefright/openmax \ LOCAL_CFLAGS += -Wno-multichar diff --git a/media/libstagefright/matroska/mkvparser.cpp b/media/libstagefright/matroska/mkvparser.cpp deleted file mode 100644 index 7448d96337b2..000000000000 --- a/media/libstagefright/matroska/mkvparser.cpp +++ /dev/null @@ -1,4514 +0,0 @@ -// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-
-#include "mkvparser.hpp"
-#include <cassert>
-#include <cstring>
-#include <new>
-//#include <windows.h>
-//#include "odbgstream.hpp"
-//using std::endl;
-
-mkvparser::IMkvReader::~IMkvReader()
-{
-}
-
-
-void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision)
-{
- major = 1;
- minor = 0;
- build = 0;
- revision = 4;
-}
-
-
-long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len)
-{
- assert(pReader);
- assert(pos >= 0);
-
- long long total, available;
-
- long hr = pReader->Length(&total, &available);
- assert(hr >= 0);
- assert(pos < available);
- assert((available - pos) >= 1); //assume here max u-int len is 8
-
- unsigned char b;
-
- hr = pReader->Read(pos, 1, &b);
- if (hr < 0)
- return hr;
-
- assert(hr == 0L);
-
- if (b & 0x80) //1000 0000
- {
- len = 1;
- b &= 0x7F; //0111 1111
- }
- else if (b & 0x40) //0100 0000
- {
- len = 2;
- b &= 0x3F; //0011 1111
- }
- else if (b & 0x20) //0010 0000
- {
- len = 3;
- b &= 0x1F; //0001 1111
- }
- else if (b & 0x10) //0001 0000
- {
- len = 4;
- b &= 0x0F; //0000 1111
- }
- else if (b & 0x08) //0000 1000
- {
- len = 5;
- b &= 0x07; //0000 0111
- }
- else if (b & 0x04) //0000 0100
- {
- len = 6;
- b &= 0x03; //0000 0011
- }
- else if (b & 0x02) //0000 0010
- {
- len = 7;
- b &= 0x01; //0000 0001
- }
- else
- {
- assert(b & 0x01); //0000 0001
- len = 8;
- b = 0; //0000 0000
- }
-
- assert((available - pos) >= len);
-
- long long result = b;
- ++pos;
- for (long i = 1; i < len; ++i)
- {
- hr = pReader->Read(pos, 1, &b);
-
- if (hr < 0)
- return hr;
-
- assert(hr == 0L);
-
- result <<= 8;
- result |= b;
-
- ++pos;
- }
-
- return result;
-}
-
-
-long long mkvparser::GetUIntLength(
- IMkvReader* pReader,
- long long pos,
- long& len)
-{
- assert(pReader);
- assert(pos >= 0);
-
- long long total, available;
-
- long hr = pReader->Length(&total, &available);
- assert(hr >= 0);
- assert(available <= total);
-
- if (pos >= available)
- return pos; //too few bytes available
-
- unsigned char b;
-
- hr = pReader->Read(pos, 1, &b);
-
- if (hr < 0)
- return hr;
-
- assert(hr == 0L);
-
- if (b == 0) //we can't handle u-int values larger than 8 bytes
- return E_FILE_FORMAT_INVALID;
-
- unsigned char m = 0x80;
- len = 1;
-
- while (!(b & m))
- {
- m >>= 1;
- ++len;
- }
-
- return 0; //success
-}
-
-
-long long mkvparser::SyncReadUInt(
- IMkvReader* pReader,
- long long pos,
- long long stop,
- long& len)
-{
- assert(pReader);
-
- if (pos >= stop)
- return E_FILE_FORMAT_INVALID;
-
- unsigned char b;
-
- long hr = pReader->Read(pos, 1, &b);
-
- if (hr < 0)
- return hr;
-
- if (hr != 0L)
- return E_BUFFER_NOT_FULL;
-
- if (b == 0) //we can't handle u-int values larger than 8 bytes
- return E_FILE_FORMAT_INVALID;
-
- unsigned char m = 0x80;
- len = 1;
-
- while (!(b & m))
- {
- m >>= 1;
- ++len;
- }
-
- if ((pos + len) > stop)
- return E_FILE_FORMAT_INVALID;
-
- long long result = b & (~m);
- ++pos;
-
- for (int i = 1; i < len; ++i)
- {
- hr = pReader->Read(pos, 1, &b);
-
- if (hr < 0)
- return hr;
-
- if (hr != 0L)
- return E_BUFFER_NOT_FULL;
-
- result <<= 8;
- result |= b;
-
- ++pos;
- }
-
- return result;
-}
-
-
-long long mkvparser::UnserializeUInt(
- IMkvReader* pReader,
- long long pos,
- long long size)
-{
- assert(pReader);
- assert(pos >= 0);
- assert(size > 0);
- assert(size <= 8);
-
- long long result = 0;
-
- for (long long i = 0; i < size; ++i)
- {
- unsigned char b;
-
- const long hr = pReader->Read(pos, 1, &b);
-
- if (hr < 0)
- return hr;
- result <<= 8;
- result |= b;
-
- ++pos;
- }
-
- return result;
-}
-
-
-float mkvparser::Unserialize4Float(
- IMkvReader* pReader,
- long long pos)
-{
- assert(pReader);
- assert(pos >= 0);
-
- long long total, available;
-
- long hr = pReader->Length(&total, &available);
- assert(hr >= 0);
- assert(available <= total);
- assert((pos + 4) <= available);
-
- float result;
-
- unsigned char* const p = (unsigned char*)&result;
- unsigned char* q = p + 4;
-
- for (;;)
- {
- hr = pReader->Read(pos, 1, --q);
- assert(hr == 0L);
-
- if (q == p)
- break;
-
- ++pos;
- }
-
- return result;
-}
-
-
-double mkvparser::Unserialize8Double(
- IMkvReader* pReader,
- long long pos)
-{
- assert(pReader);
- assert(pos >= 0);
-
- double result;
-
- unsigned char* const p = (unsigned char*)&result;
- unsigned char* q = p + 8;
-
- for (;;)
- {
- const long hr = pReader->Read(pos, 1, --q);
- assert(hr == 0L);
-
- if (q == p)
- break;
-
- ++pos;
- }
-
- return result;
-}
-
-signed char mkvparser::Unserialize1SInt(
- IMkvReader* pReader,
- long long pos)
-{
- assert(pReader);
- assert(pos >= 0);
-
- long long total, available;
-
- long hr = pReader->Length(&total, &available);
- assert(hr == 0);
- assert(available <= total);
- assert(pos < available);
-
- signed char result;
-
- hr = pReader->Read(pos, 1, (unsigned char*)&result);
- assert(hr == 0);
-
- return result;
-}
-
-short mkvparser::Unserialize2SInt(
- IMkvReader* pReader,
- long long pos)
-{
- assert(pReader);
- assert(pos >= 0);
-
- long long total, available;
-
- long hr = pReader->Length(&total, &available);
- assert(hr >= 0);
- assert(available <= total);
- assert((pos + 2) <= available);
-
- short result;
-
- unsigned char* const p = (unsigned char*)&result;
- unsigned char* q = p + 2;
-
- for (;;)
- {
- hr = pReader->Read(pos, 1, --q);
- assert(hr == 0L);
-
- if (q == p)
- break;
-
- ++pos;
- }
-
- return result;
-}
-
-
-bool mkvparser::Match(
- IMkvReader* pReader,
- long long& pos,
- unsigned long id_,
- long long& val)
-
-{
- assert(pReader);
- assert(pos >= 0);
-
- long long total, available;
-
- long hr = pReader->Length(&total, &available);
- assert(hr >= 0);
- assert(available <= total);
-
- long len;
-
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0);
- assert(len > 0);
- assert(len <= 8);
- assert((pos + len) <= available);
-
- if ((unsigned long)id != id_)
- return false;
-
- pos += len; //consume id
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size >= 0);
- assert(size <= 8);
- assert(len > 0);
- assert(len <= 8);
- assert((pos + len) <= available);
-
- pos += len; //consume length of size of payload
-
- val = UnserializeUInt(pReader, pos, size);
- assert(val >= 0);
-
- pos += size; //consume size of payload
-
- return true;
-}
-
-bool mkvparser::Match(
- IMkvReader* pReader,
- long long& pos,
- unsigned long id_,
- char*& val)
-{
- assert(pReader);
- assert(pos >= 0);
-
- long long total, available;
-
- long hr = pReader->Length(&total, &available);
- assert(hr >= 0);
- assert(available <= total);
-
- long len;
-
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0);
- assert(len > 0);
- assert(len <= 8);
- assert((pos + len) <= available);
-
- if ((unsigned long)id != id_)
- return false;
-
- pos += len; //consume id
-
- const long long size_ = ReadUInt(pReader, pos, len);
- assert(size_ >= 0);
- assert(len > 0);
- assert(len <= 8);
- assert((pos + len) <= available);
-
- pos += len; //consume length of size of payload
- assert((pos + size_) <= available);
-
- const size_t size = static_cast<size_t>(size_);
- val = new char[size+1];
-
- for (size_t i = 0; i < size; ++i)
- {
- char c;
-
- hr = pReader->Read(pos + i, 1, (unsigned char*)&c);
- assert(hr == 0L);
-
- val[i] = c;
-
- if (c == '\0')
- break;
-
- }
-
- val[size] = '\0';
- pos += size_; //consume size of payload
-
- return true;
-}
-
-bool mkvparser::Match(
- IMkvReader* pReader,
- long long& pos,
- unsigned long id_,
- unsigned char*& buf,
- size_t& buflen)
-{
- assert(pReader);
- assert(pos >= 0);
-
- long long total, available;
-
- long hr = pReader->Length(&total, &available);
- assert(hr >= 0);
- assert(available <= total);
-
- long len;
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0);
- assert(len > 0);
- assert(len <= 8);
- assert((pos + len) <= available);
-
- if ((unsigned long)id != id_)
- return false;
-
- pos += len; //consume id
-
- const long long size_ = ReadUInt(pReader, pos, len);
- assert(size_ >= 0);
- assert(len > 0);
- assert(len <= 8);
- assert((pos + len) <= available);
-
- pos += len; //consume length of size of payload
- assert((pos + size_) <= available);
-
- const long buflen_ = static_cast<long>(size_);
-
- buf = new (std::nothrow) unsigned char[buflen_];
- assert(buf); //TODO
-
- hr = pReader->Read(pos, buflen_, buf);
- assert(hr == 0L);
-
- buflen = buflen_;
-
- pos += size_; //consume size of payload
- return true;
-}
-
-
-bool mkvparser::Match(
- IMkvReader* pReader,
- long long& pos,
- unsigned long id_,
- double& val)
-{
- assert(pReader);
- assert(pos >= 0);
-
- long long total, available;
-
- long hr = pReader->Length(&total, &available);
- assert(hr >= 0);
- assert(available <= total);
- long idlen;
- const long long id = ReadUInt(pReader, pos, idlen);
- assert(id >= 0); //TODO
-
- if ((unsigned long)id != id_)
- return false;
-
- long sizelen;
- const long long size = ReadUInt(pReader, pos + idlen, sizelen);
-
- switch (size)
- {
- case 4:
- case 8:
- break;
- default:
- return false;
- }
-
- pos += idlen + sizelen; //consume id and size fields
- assert((pos + size) <= available);
-
- if (size == 4)
- val = Unserialize4Float(pReader, pos);
- else
- {
- assert(size == 8);
- val = Unserialize8Double(pReader, pos);
- }
-
- pos += size; //consume size of payload
-
- return true;
-}
-
-
-bool mkvparser::Match(
- IMkvReader* pReader,
- long long& pos,
- unsigned long id_,
- short& val)
-{
- assert(pReader);
- assert(pos >= 0);
-
- long long total, available;
-
- long hr = pReader->Length(&total, &available);
- assert(hr >= 0);
- assert(available <= total);
-
- long len;
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0);
- assert((pos + len) <= available);
-
- if ((unsigned long)id != id_)
- return false;
-
- pos += len; //consume id
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size <= 2);
- assert((pos + len) <= available);
-
- pos += len; //consume length of size of payload
- assert((pos + size) <= available);
-
- //TODO:
- // Generalize this to work for any size signed int
- if (size == 1)
- val = Unserialize1SInt(pReader, pos);
- else
- val = Unserialize2SInt(pReader, pos);
-
- pos += size; //consume size of payload
-
- return true;
-}
-
-
-namespace mkvparser
-{
-
-EBMLHeader::EBMLHeader():
- m_docType(NULL)
-{
-}
-
-EBMLHeader::~EBMLHeader()
-{
- delete[] m_docType;
-}
-
-long long EBMLHeader::Parse(
- IMkvReader* pReader,
- long long& pos)
-{
- assert(pReader);
-
- long long total, available;
-
- long hr = pReader->Length(&total, &available);
-
- if (hr < 0)
- return hr;
-
- pos = 0;
- long long end = (1024 < available)? 1024: available;
-
- for (;;)
- {
- unsigned char b = 0;
-
- while (pos < end)
- {
- hr = pReader->Read(pos, 1, &b);
-
- if (hr < 0)
- return hr;
-
- if (b == 0x1A)
- break;
-
- ++pos;
- }
-
- if (b != 0x1A)
- {
- if ((pos >= 1024) ||
- (available >= total) ||
- ((total - available) < 5))
- return -1;
-
- return available + 5; //5 = 4-byte ID + 1st byte of size
- }
-
- if ((total - pos) < 5)
- return E_FILE_FORMAT_INVALID;
-
- if ((available - pos) < 5)
- return pos + 5; //try again later
-
- long len;
-
- const long long result = ReadUInt(pReader, pos, len);
-
- if (result < 0) //error
- return result;
-
- if (result == 0x0A45DFA3) //ReadId masks-off length indicator bits
- {
- assert(len == 4);
- pos += len;
- break;
- }
-
- ++pos; //throw away just the 0x1A byte, and try again
- }
-
- long len;
- long long result = GetUIntLength(pReader, pos, len);
-
- if (result < 0) //error
- return result;
-
- if (result > 0) //need more data
- return result;
-
- assert(len > 0);
- assert(len <= 8);
-
- if ((total - pos) < len)
- return E_FILE_FORMAT_INVALID;
- if ((available - pos) < len)
- return pos + len; //try again later
-
- result = ReadUInt(pReader, pos, len);
-
- if (result < 0) //error
- return result;
-
- pos += len; //consume u-int
-
- if ((total - pos) < result)
- return E_FILE_FORMAT_INVALID;
-
- if ((available - pos) < result)
- return pos + result;
-
- end = pos + result;
-
- m_version = 1;
- m_readVersion = 1;
- m_maxIdLength = 4;
- m_maxSizeLength = 8;
- m_docTypeVersion = 1;
- m_docTypeReadVersion = 1;
-
- while (pos < end)
- {
- if (Match(pReader, pos, 0x0286, m_version))
- ;
- else if (Match(pReader, pos, 0x02F7, m_readVersion))
- ;
- else if (Match(pReader, pos, 0x02F2, m_maxIdLength))
- ;
- else if (Match(pReader, pos, 0x02F3, m_maxSizeLength))
- ;
- else if (Match(pReader, pos, 0x0282, m_docType))
- ;
- else if (Match(pReader, pos, 0x0287, m_docTypeVersion))
- ;
- else if (Match(pReader, pos, 0x0285, m_docTypeReadVersion))
- ;
- else
- {
- result = ReadUInt(pReader, pos, len);
- assert(result > 0);
- assert(len > 0);
- assert(len <= 8);
-
- pos += len;
- assert(pos < end);
-
- result = ReadUInt(pReader, pos, len);
- assert(result >= 0);
- assert(len > 0);
- assert(len <= 8);
-
- pos += len + result;
- assert(pos <= end);
- }
- }
-
- assert(pos == end);
-
- return 0;
-}
-
-
-Segment::Segment(
- IMkvReader* pReader,
- long long start,
- long long size) :
- m_pReader(pReader),
- m_start(start),
- m_size(size),
- m_pos(start),
- m_pInfo(NULL),
- m_pTracks(NULL),
- m_pCues(NULL),
- m_clusters(NULL),
- m_clusterCount(0),
- m_clusterPreloadCount(0),
- m_clusterSize(0)
-{
-}
-
-
-Segment::~Segment()
-{
- const long count = m_clusterCount + m_clusterPreloadCount;
-
- Cluster** i = m_clusters;
- Cluster** j = m_clusters + count;
-
- while (i != j)
- {
- Cluster* const p = *i++;
- assert(p);
-
- delete p;
- }
-
- delete[] m_clusters;
-
- delete m_pTracks;
- delete m_pInfo;
- delete m_pCues;
-}
-
-
-long long Segment::CreateInstance(
- IMkvReader* pReader,
- long long pos,
- Segment*& pSegment)
-{
- assert(pReader);
- assert(pos >= 0);
-
- pSegment = NULL;
-
- long long total, available;
-
- long hr = pReader->Length(&total, &available);
- assert(hr >= 0);
- assert(available <= total);
-
- //I would assume that in practice this loop would execute
- //exactly once, but we allow for other elements (e.g. Void)
- //to immediately follow the EBML header. This is fine for
- //the source filter case (since the entire file is available),
- //but in the splitter case over a network we should probably
- //just give up early. We could for example decide only to
- //execute this loop a maximum of, say, 10 times.
-
- while (pos < total)
- {
- //Read ID
-
- long len;
- long long result = GetUIntLength(pReader, pos, len);
-
- if (result) //error, or too few available bytes
- return result;
-
- if ((pos + len) > total)
- return E_FILE_FORMAT_INVALID;
-
- if ((pos + len) > available)
- return pos + len;
-
- //TODO: if we liberalize the behavior of ReadUInt, we can
- //probably eliminate having to use GetUIntLength here.
- const long long id = ReadUInt(pReader, pos, len);
-
- if (id < 0) //error
- return id;
-
- pos += len; //consume ID
-
- //Read Size
-
- result = GetUIntLength(pReader, pos, len);
-
- if (result) //error, or too few available bytes
- return result;
-
- if ((pos + len) > total)
- return E_FILE_FORMAT_INVALID;
-
- if ((pos + len) > available)
- return pos + len;
-
- //TODO: if we liberalize the behavior of ReadUInt, we can
- //probably eliminate having to use GetUIntLength here.
- const long long size = ReadUInt(pReader, pos, len);
-
- if (size < 0)
- return size;
-
- pos += len; //consume length of size of element
-
- //Pos now points to start of payload
-
- if ((pos + size) > total)
- return E_FILE_FORMAT_INVALID;
-
- if (id == 0x08538067) //Segment ID
- {
- pSegment = new Segment(pReader, pos, size);
- assert(pSegment); //TODO
-
- return 0; //success
- }
-
- pos += size; //consume payload
- }
-
- assert(pos == total);
-
- pSegment = new Segment(pReader, pos, 0);
- assert(pSegment); //TODO
-
- return 0; //success (sort of)
-}
-
-
-long long Segment::ParseHeaders()
-{
- //Outermost (level 0) segment object has been constructed,
- //and pos designates start of payload. We need to find the
- //inner (level 1) elements.
- long long total, available;
-
- long hr = m_pReader->Length(&total, &available);
- assert(hr >= 0);
- assert(available <= total);
-
- const long long stop = m_start + m_size;
- assert(stop <= total);
- assert(m_pos <= stop);
-
- bool bQuit = false;
-
- while ((m_pos < stop) && !bQuit)
- {
- long long pos = m_pos;
-
- long len;
- long long result = GetUIntLength(m_pReader, pos, len);
-
- if (result) //error, or too few available bytes
- return result;
-
- if ((pos + len) > stop)
- return E_FILE_FORMAT_INVALID;
-
- if ((pos + len) > available)
- return pos + len;
-
- const long long idpos = pos;
- const long long id = ReadUInt(m_pReader, idpos, len);
-
- if (id < 0) //error
- return id;
-
- pos += len; //consume ID
-
- //Read Size
- result = GetUIntLength(m_pReader, pos, len);
-
- if (result) //error, or too few available bytes
- return result;
-
- if ((pos + len) > stop)
- return E_FILE_FORMAT_INVALID;
-
- if ((pos + len) > available)
- return pos + len;
-
- const long long size = ReadUInt(m_pReader, pos, len);
-
- if (size < 0)
- return size;
-
- pos += len; //consume length of size of element
-
- //Pos now points to start of payload
-
- if ((pos + size) > stop)
- return E_FILE_FORMAT_INVALID;
-
- //We read EBML elements either in total or nothing at all.
-
- if ((pos + size) > available)
- return pos + size;
-
- if (id == 0x0549A966) //Segment Info ID
- {
- assert(m_pInfo == NULL);
-
- m_pInfo = new SegmentInfo(this, pos, size);
- assert(m_pInfo); //TODO
- }
- else if (id == 0x0654AE6B) //Tracks ID
- {
- assert(m_pTracks == NULL);
-
- m_pTracks = new Tracks(this, pos, size);
- assert(m_pTracks); //TODO
- }
- else if (id == 0x0C53BB6B) //Cues ID
- {
- if (m_pCues == NULL)
- {
- m_pCues = new Cues(this, pos, size);
- assert(m_pCues); //TODO
- }
- }
- else if (id == 0x014D9B74) //SeekHead ID
- {
- ParseSeekHead(pos, size);
- }
- else if (id == 0x0F43B675) //Cluster ID
- {
- bQuit = true;
- }
-
- if (!bQuit)
- m_pos = pos + size; //consume payload
- }
-
- assert(m_pos <= stop);
-
- if (m_pInfo == NULL) //TODO: liberalize this behavior
- return E_FILE_FORMAT_INVALID;
-
- if (m_pTracks == NULL)
- return E_FILE_FORMAT_INVALID;
-
- return 0; //success
-}
-
-
-#if 0
-long Segment::ParseCluster(Cluster*& pCluster, long long& pos_) const
-{
- pCluster = NULL;
- pos_ = -1;
-
- const long long stop = m_start + m_size;
- assert(m_pos <= stop);
-
- long long pos = m_pos;
- long long off = -1;
-
- while (pos < stop)
- {
- long len;
- const long long idpos = pos;
-
- const long long id = SyncReadUInt(m_pReader, pos, stop, len);
-
- if (id < 0) //error
- return static_cast<long>(id);
-
- if (id == 0)
- return E_FILE_FORMAT_INVALID;
-
- pos += len; //consume id
- assert(pos < stop);
-
- const long long size = SyncReadUInt(m_pReader, pos, stop, len);
-
- if (size < 0) //error
- return static_cast<long>(size);
-
- pos += len; //consume size
- assert(pos <= stop);
-
- if (size == 0) //weird
- continue;
-
- //pos now points to start of payload
-
- pos += size; //consume payload
- assert(pos <= stop);
-
- if (id == 0x0F43B675) //Cluster ID
- {
- off = idpos - m_start; // >= 0 means we found a cluster
- break;
- }
- }
-
- assert(pos <= stop);
-
- //Indicate to caller how much of file has been consumed. This is
- //used later in AddCluster to adjust the current parse position
- //(the value cached in the segment object itself) to the
- //file position value just past the cluster we parsed.
-
- if (off < 0) //we did not found any more clusters
- {
- pos_ = stop; //pos_ >= 0 here means EOF (cluster is NULL)
- return 0; //TODO: confirm this return value
- }
-
- //We found a cluster. Now read something, to ensure that it is
- //fully loaded in the network cache.
-
- if (pos >= stop) //we parsed the entire segment
- {
- //We did find a cluster, but it was very last element in the segment.
- //Our preference is that the loop above runs 1 1/2 times:
- //the first pass finds the cluster, and the second pass
- //finds the element the follows the cluster. In this case, however,
- //we reached the end of the file without finding another element,
- //so we didn't actually read anything yet associated with "end of the
- //cluster". And we must perform an actual read, in order
- //to guarantee that all of the data that belongs to this
- //cluster has been loaded into the network cache. So instead
- //of reading the next element that follows the cluster, we
- //read the last byte of the cluster (which is also the last
- //byte in the file).
-
- //Read the last byte of the file. (Reading 0 bytes at pos
- //might work too -- it would depend on how the reader is
- //implemented. Here we take the more conservative approach,
- //since this makes fewer assumptions about the network
- //reader abstraction.)
-
- unsigned char b;
-
- const int result = m_pReader->Read(pos - 1, 1, &b);
- assert(result == 0);
-
- pos_ = stop;
- }
- else
- {
- long len;
- const long long idpos = pos;
-
- const long long id = SyncReadUInt(m_pReader, pos, stop, len);
-
- if (id < 0) //error
- return static_cast<long>(id);
-
- if (id == 0)
- return E_BUFFER_NOT_FULL;
-
- pos += len; //consume id
- assert(pos < stop);
-
- const long long size = SyncReadUInt(m_pReader, pos, stop, len);
-
- if (size < 0) //error
- return static_cast<long>(size);
-
- pos_ = idpos;
- }
-
- //We found a cluster, and it has been completely loaded into the
- //network cache. (We can guarantee this because we actually read
- //the EBML tag that follows the cluster, or, if we reached EOF,
- //because we actually read the last byte of the cluster).
-
- Segment* const this_ = const_cast<Segment*>(this);
-
- pCluster = Cluster::Parse(this_, m_clusterCount, off);
- assert(pCluster);
- assert(pCluster->m_index == m_clusterCount);
-
- return 0;
-}
-
-
-bool Segment::AddCluster(Cluster* pCluster, long long pos)
-{
- assert(pos >= m_start);
-
- const long long stop = m_start + m_size;
- assert(pos <= stop);
-
- if (pCluster)
- {
- AppendCluster(pCluster);
- assert(m_clusters);
- assert(m_clusterSize > pCluster->m_index);
- assert(m_clusters[pCluster->m_index] == pCluster);
- }
-
- m_pos = pos; //m_pos >= stop is now we know we have all clusters
-
- return (pos >= stop);
-}
-#endif
-
-
-long Segment::LoadCluster()
-{
- const long long stop = m_start + m_size;
-
- while (m_pos < stop)
- {
- long long pos = m_pos;
-
- long len;
-
- long long result = GetUIntLength(m_pReader, pos, len);
-
- if (result < 0) //error
- return static_cast<long>(result);
-
- if ((pos + len) > stop)
- return E_FILE_FORMAT_INVALID;
-
- const long long idpos = pos;
- const long long id = ReadUInt(m_pReader, idpos, len);
-
- if (id < 0) //error
- return static_cast<long>(id);
-
- pos += len; //consume ID
-
- //Read Size
- result = GetUIntLength(m_pReader, pos, len);
-
- if (result < 0) //error
- return static_cast<long>(result);
-
- if ((pos + len) > stop)
- return E_FILE_FORMAT_INVALID;
-
- const long long size = ReadUInt(m_pReader, pos, len);
-
- if (size < 0) //error
- return static_cast<long>(size);
-
- pos += len; //consume length of size of element
-
- if (size == 0) //weird
- {
- m_pos = pos;
- continue;
- }
-
- //Pos now points to start of payload
-
- if ((pos + size) > stop)
- return E_FILE_FORMAT_INVALID;
-
- if (id == 0x0C53BB6B) //Cues ID
- {
- if (m_pCues == NULL)
- {
- m_pCues = new Cues(this, pos, size);
- assert(m_pCues); //TODO
- }
-
- m_pos = pos + size; //consume payload
- continue;
- }
-
- if (id != 0x0F43B675) //Cluster ID
- {
- m_pos = pos + size; //consume payload
- continue;
- }
-
- const long idx = m_clusterCount;
- const long long idoff = idpos - m_start;
-
- if (m_clusterPreloadCount > 0)
- {
- assert(idx < m_clusterSize);
-
- Cluster* const pCluster = m_clusters[idx];
- assert(pCluster);
- assert(pCluster->m_index < 0);
-
- const long long off_ = pCluster->m_pos;
- assert(off_);
-
- const long long off = off_ * ((off_ >= 0) ? 1 : -1);
- assert(idoff <= off);
-
- if (idoff == off) //cluster has been preloaded already
- {
- pCluster->m_index = idx;
- ++m_clusterCount;
- --m_clusterPreloadCount;
-
- m_pos = pos + size; //consume payload
- break;
- }
- }
-
- Cluster* const pCluster = Cluster::Parse(this, idx, idoff);
- assert(pCluster);
- assert(pCluster->m_index == idx);
-
- AppendCluster(pCluster);
- assert(m_clusters);
- assert(idx < m_clusterSize);
- assert(m_clusters[idx] == pCluster);
-
- m_pos = pos + size; //consume payload
- break;
- }
-
- assert(m_pos <= stop);
- return 0;
-}
-
-
-void Segment::AppendCluster(Cluster* pCluster)
-{
- assert(pCluster);
- assert(pCluster->m_index >= 0);
-
- const long count = m_clusterCount + m_clusterPreloadCount;
-
- long& size = m_clusterSize;
- assert(size >= count);
-
- const long idx = pCluster->m_index;
- assert(idx == m_clusterCount);
-
- if (count >= size)
- {
- long n;
-
- if (size > 0)
- n = 2 * size;
- else if (m_pInfo == 0)
- n = 2048;
- else
- {
- const long long ns = m_pInfo->GetDuration();
-
- if (ns <= 0)
- n = 2048;
- else
- {
- const long long sec = (ns + 999999999LL) / 1000000000LL;
- n = static_cast<long>(sec);
- }
- }
-
- Cluster** const qq = new Cluster*[n];
- Cluster** q = qq;
-
- Cluster** p = m_clusters;
- Cluster** const pp = p + count;
-
- while (p != pp)
- *q++ = *p++;
-
- delete[] m_clusters;
-
- m_clusters = qq;
- size = n;
- }
-
- if (m_clusterPreloadCount > 0)
- {
- assert(m_clusters);
-
- Cluster** const p = m_clusters + m_clusterCount;
- assert(*p);
- assert((*p)->m_index < 0);
-
- Cluster** q = p + m_clusterPreloadCount;
- assert(q < (m_clusters + size));
-
- for (;;)
- {
- Cluster** const qq = q - 1;
- assert((*qq)->m_index < 0);
-
- *q = *qq;
- q = qq;
-
- if (q == p)
- break;
- }
- }
-
- m_clusters[idx] = pCluster;
- ++m_clusterCount;
-}
-
-
-void Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx)
-{
- assert(pCluster);
- assert(pCluster->m_index < 0);
- assert(idx >= m_clusterCount);
-
- const long count = m_clusterCount + m_clusterPreloadCount;
-
- long& size = m_clusterSize;
- assert(size >= count);
-
- if (count >= size)
- {
- long n;
-
- if (size > 0)
- n = 2 * size;
- else if (m_pInfo == 0)
- n = 2048;
- else
- {
- const long long ns = m_pInfo->GetDuration();
-
- if (ns <= 0)
- n = 2048;
- else
- {
- const long long sec = (ns + 999999999LL) / 1000000000LL;
- n = static_cast<long>(sec);
- }
- }
-
- Cluster** const qq = new Cluster*[n];
- Cluster** q = qq;
-
- Cluster** p = m_clusters;
- Cluster** const pp = p + count;
-
- while (p != pp)
- *q++ = *p++;
-
- delete[] m_clusters;
-
- m_clusters = qq;
- size = n;
- }
-
- assert(m_clusters);
-
- Cluster** const p = m_clusters + idx;
-
- Cluster** q = m_clusters + count;
- assert(q >= p);
- assert(q < (m_clusters + size));
-
- while (q > p)
- {
- Cluster** const qq = q - 1;
- assert((*qq)->m_index < 0);
-
- *q = *qq;
- q = qq;
- }
-
- m_clusters[idx] = pCluster;
- ++m_clusterPreloadCount;
-}
-
-
-long Segment::Load()
-{
- assert(m_clusters == NULL);
- assert(m_clusterSize == 0);
- assert(m_clusterCount == 0);
-
- //Outermost (level 0) segment object has been constructed,
- //and pos designates start of payload. We need to find the
- //inner (level 1) elements.
- const long long stop = m_start + m_size;
-
-#ifdef _DEBUG //TODO: this is really Microsoft-specific
- {
- long long total, available;
-
- long hr = m_pReader->Length(&total, &available);
- assert(hr >= 0);
- assert(available >= total);
- assert(stop <= total);
- }
-#endif
-
- while (m_pos < stop)
- {
- long long pos = m_pos;
-
- long len;
-
- long long result = GetUIntLength(m_pReader, pos, len);
-
- if (result < 0) //error
- return static_cast<long>(result);
-
- if ((pos + len) > stop)
- return E_FILE_FORMAT_INVALID;
-
- const long long idpos = pos;
- const long long id = ReadUInt(m_pReader, idpos, len);
-
- if (id < 0) //error
- return static_cast<long>(id);
-
- pos += len; //consume ID
-
- //Read Size
- result = GetUIntLength(m_pReader, pos, len);
-
- if (result < 0) //error
- return static_cast<long>(result);
-
- if ((pos + len) > stop)
- return E_FILE_FORMAT_INVALID;
-
- const long long size = ReadUInt(m_pReader, pos, len);
-
- if (size < 0) //error
- return static_cast<long>(size);
-
- pos += len; //consume length of size of element
-
- //Pos now points to start of payload
-
- if ((pos + size) > stop)
- return E_FILE_FORMAT_INVALID;
-
- if (id == 0x0F43B675) //Cluster ID
- {
- const long idx = m_clusterCount;
- const long long off = idpos - m_start;
-
- Cluster* const pCluster = Cluster::Parse(this, idx, off);
- assert(pCluster);
- assert(pCluster->m_index == idx);
-
- AppendCluster(pCluster);
- assert(m_clusters);
- assert(m_clusterSize > idx);
- assert(m_clusters[idx] == pCluster);
- }
- else if (id == 0x0C53BB6B) //Cues ID
- {
- assert(m_pCues == NULL);
-
- m_pCues = new Cues(this, pos, size);
- assert(m_pCues); //TODO
- }
- else if (id == 0x0549A966) //SegmentInfo ID
- {
- assert(m_pInfo == NULL);
-
- m_pInfo = new SegmentInfo(this, pos, size);
- assert(m_pInfo);
- }
- else if (id == 0x0654AE6B) //Tracks ID
- {
- assert(m_pTracks == NULL);
-
- m_pTracks = new Tracks(this, pos, size);
- assert(m_pTracks); //TODO
- }
-
- m_pos = pos + size; //consume payload
- }
-
- assert(m_pos >= stop);
-
- if (m_pInfo == NULL)
- return E_FILE_FORMAT_INVALID; //TODO: ignore this case?
-
- if (m_pTracks == NULL)
- return E_FILE_FORMAT_INVALID;
-
- if (m_clusters == NULL) //TODO: ignore this case?
- return E_FILE_FORMAT_INVALID;
-
- //TODO: decide whether we require Cues element
- //if (m_pCues == NULL)
- // return E_FILE_FORMAT_INVALID;
-
- return 0;
-}
-
-
-void Segment::ParseSeekHead(long long start, long long size_)
-{
- long long pos = start;
- const long long stop = start + size_;
-
- while (pos < stop)
- {
- long len;
-
- const long long id = ReadUInt(m_pReader, pos, len);
- assert(id >= 0); //TODO
- assert((pos + len) <= stop);
-
- pos += len; //consume ID
-
- const long long size = ReadUInt(m_pReader, pos, len);
- assert(size >= 0);
- assert((pos + len) <= stop);
-
- pos += len; //consume Size field
- assert((pos + size) <= stop);
-
- if (id == 0x0DBB) //SeekEntry ID
- ParseSeekEntry(pos, size);
-
- pos += size; //consume payload
- assert(pos <= stop);
- }
-
- assert(pos == stop);
-}
-
-
-void Segment::ParseCues(long long off)
-{
- if (m_pCues)
- return;
-
- //odbgstream os;
- //os << "Segment::ParseCues (begin)" << endl;
-
- long long pos = m_start + off;
- const long long stop = m_start + m_size;
-
- long len;
-
- long long result = GetUIntLength(m_pReader, pos, len);
- assert(result == 0);
- assert((pos + len) <= stop);
-
- const long long idpos = pos;
-
- const long long id = ReadUInt(m_pReader, idpos, len);
- assert(id == 0x0C53BB6B); //Cues ID
-
- pos += len; //consume ID
- assert(pos < stop);
-
- //Read Size
-
- result = GetUIntLength(m_pReader, pos, len);
- assert(result == 0);
- assert((pos + len) <= stop);
-
- const long long size = ReadUInt(m_pReader, pos, len);
- assert(size >= 0);
-
- pos += len; //consume length of size of element
- assert((pos + size) <= stop);
-
- //Pos now points to start of payload
-
- m_pCues = new Cues(this, pos, size);
- assert(m_pCues); //TODO
-
- //os << "Segment::ParseCues (end)" << endl;
-}
-
-
-void Segment::ParseSeekEntry(
- long long start,
- long long size_)
-{
- long long pos = start;
-
- const long long stop = start + size_;
-
- long len;
-
- const long long seekIdId = ReadUInt(m_pReader, pos, len);
- //seekIdId;
- assert(seekIdId == 0x13AB); //SeekID ID
- assert((pos + len) <= stop);
-
- pos += len; //consume id
-
- const long long seekIdSize = ReadUInt(m_pReader, pos, len);
- assert(seekIdSize >= 0);
- assert((pos + len) <= stop);
-
- pos += len; //consume size
-
- const long long seekId = ReadUInt(m_pReader, pos, len); //payload
- assert(seekId >= 0);
- assert(len == seekIdSize);
- assert((pos + len) <= stop);
-
- pos += seekIdSize; //consume payload
-
- const long long seekPosId = ReadUInt(m_pReader, pos, len);
- //seekPosId;
- assert(seekPosId == 0x13AC); //SeekPos ID
- assert((pos + len) <= stop);
-
- pos += len; //consume id
-
- const long long seekPosSize = ReadUInt(m_pReader, pos, len);
- assert(seekPosSize >= 0);
- assert((pos + len) <= stop);
-
- pos += len; //consume size
- assert((pos + seekPosSize) <= stop);
-
- const long long seekOff = UnserializeUInt(m_pReader, pos, seekPosSize);
- assert(seekOff >= 0);
- assert(seekOff < m_size);
-
- pos += seekPosSize; //consume payload
- assert(pos == stop);
-
- const long long seekPos = m_start + seekOff;
- assert(seekPos < (m_start + m_size));
-
- if (seekId == 0x0C53BB6B) //Cues ID
- ParseCues(seekOff);
-}
-
-
-Cues::Cues(Segment* pSegment, long long start_, long long size_) :
- m_pSegment(pSegment),
- m_start(start_),
- m_size(size_),
- m_cue_points(NULL),
- m_count(0),
- m_preload_count(0),
- m_pos(start_)
-{
-}
-
-
-Cues::~Cues()
-{
- const size_t n = m_count + m_preload_count;
-
- CuePoint** p = m_cue_points;
- CuePoint** const q = p + n;
-
- while (p != q)
- {
- CuePoint* const pCP = *p++;
- assert(pCP);
-
- delete pCP;
- }
-
- delete[] m_cue_points;
-}
-
-
-void Cues::Init() const
-{
- if (m_cue_points)
- return;
-
- assert(m_count == 0);
- assert(m_preload_count == 0);
-
- IMkvReader* const pReader = m_pSegment->m_pReader;
-
- const long long stop = m_start + m_size;
- long long pos = m_start;
-
- size_t cue_points_size = 0;
-
- while (pos < stop)
- {
- const long long idpos = pos;
-
- long len;
-
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0); //TODO
- assert((pos + len) <= stop);
-
- pos += len; //consume ID
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size >= 0);
- assert((pos + len) <= stop);
-
- pos += len; //consume Size field
- assert((pos + size) <= stop);
-
- if (id == 0x3B) //CuePoint ID
- PreloadCuePoint(cue_points_size, idpos);
-
- pos += size; //consume payload
- assert(pos <= stop);
- }
-}
-
-
-void Cues::PreloadCuePoint(
- size_t& cue_points_size,
- long long pos) const
-{
- assert(m_count == 0);
-
- if (m_preload_count >= cue_points_size)
- {
- size_t n;
-
- if (cue_points_size > 0)
- n = static_cast<size_t>(2 * cue_points_size);
- else
- {
- const SegmentInfo* const pInfo = m_pSegment->GetInfo();
-
- if (pInfo == NULL)
- n = 2048;
- else
- {
- const long long ns = pInfo->GetDuration();
-
- if (ns <= 0)
- n = 2048;
- else
- {
- const long long sec = (ns + 999999999LL) / 1000000000LL;
- n = static_cast<size_t>(sec);
- }
- }
- }
-
- CuePoint** const qq = new CuePoint*[n];
- CuePoint** q = qq; //beginning of target
-
- CuePoint** p = m_cue_points; //beginning of source
- CuePoint** const pp = p + m_preload_count; //end of source
-
- while (p != pp)
- *q++ = *p++;
-
- delete[] m_cue_points;
-
- m_cue_points = qq;
- cue_points_size = n;
- }
-
- CuePoint* const pCP = new CuePoint(m_preload_count, pos);
- m_cue_points[m_preload_count++] = pCP;
-}
-
-
-bool Cues::LoadCuePoint() const
-{
- //odbgstream os;
- //os << "Cues::LoadCuePoint" << endl;
-
- const long long stop = m_start + m_size;
-
- if (m_pos >= stop)
- return false; //nothing else to do
-
- Init();
-
- IMkvReader* const pReader = m_pSegment->m_pReader;
-
- while (m_pos < stop)
- {
- const long long idpos = m_pos;
-
- long len;
-
- const long long id = ReadUInt(pReader, m_pos, len);
- assert(id >= 0); //TODO
- assert((m_pos + len) <= stop);
-
- m_pos += len; //consume ID
-
- const long long size = ReadUInt(pReader, m_pos, len);
- assert(size >= 0);
- assert((m_pos + len) <= stop);
-
- m_pos += len; //consume Size field
- assert((m_pos + size) <= stop);
-
- if (id != 0x3B) //CuePoint ID
- {
- m_pos += size; //consume payload
- assert(m_pos <= stop);
-
- continue;
- }
-
- assert(m_preload_count > 0);
-
- CuePoint* const pCP = m_cue_points[m_count];
- assert(pCP);
- assert((pCP->GetTimeCode() >= 0) || (-pCP->GetTimeCode() == idpos));
-
- pCP->Load(pReader);
- ++m_count;
- --m_preload_count;
-
- m_pos += size; //consume payload
- assert(m_pos <= stop);
-
- break;
- }
-
- return (m_pos < stop);
-}
-
-
-bool Cues::Find(
- long long time_ns,
- const Track* pTrack,
- const CuePoint*& pCP,
- const CuePoint::TrackPosition*& pTP) const
-{
- assert(time_ns >= 0);
- assert(pTrack);
-
- LoadCuePoint();
-
- assert(m_cue_points);
- assert(m_count > 0);
-
- CuePoint** const ii = m_cue_points;
- CuePoint** i = ii;
-
- CuePoint** const jj = ii + m_count + m_preload_count;
- CuePoint** j = jj;
-
- pCP = *i;
- assert(pCP);
-
- if (time_ns <= pCP->GetTime(m_pSegment))
- {
- pTP = pCP->Find(pTrack);
- return (pTP != NULL);
- }
-
- IMkvReader* const pReader = m_pSegment->m_pReader;
-
- while (i < j)
- {
- //INVARIANT:
- //[ii, i) <= time_ns
- //[i, j) ?
- //[j, jj) > time_ns
-
- CuePoint** const k = i + (j - i) / 2;
- assert(k < jj);
-
- CuePoint* const pCP = *k;
- assert(pCP);
-
- pCP->Load(pReader);
-
- const long long t = pCP->GetTime(m_pSegment);
-
- if (t <= time_ns)
- i = k + 1;
- else
- j = k;
-
- assert(i <= j);
- }
-
- assert(i == j);
- assert(i <= jj);
- assert(i > ii);
-
- pCP = *--i;
- assert(pCP);
- assert(pCP->GetTime(m_pSegment) <= time_ns);
-
- //TODO: here and elsewhere, it's probably not correct to search
- //for the cue point with this time, and then search for a matching
- //track. In principle, the matching track could be on some earlier
- //cue point, and with our current algorithm, we'd miss it. To make
- //this bullet-proof, we'd need to create a secondary structure,
- //with a list of cue points that apply to a track, and then search
- //that track-based structure for a matching cue point.
-
- pTP = pCP->Find(pTrack);
- return (pTP != NULL);
-}
-
-
-#if 0
-bool Cues::FindNext(
- long long time_ns,
- const Track* pTrack,
- const CuePoint*& pCP,
- const CuePoint::TrackPosition*& pTP) const
-{
- pCP = 0;
- pTP = 0;
-
- if (m_count == 0)
- return false;
-
- assert(m_cue_points);
-
- const CuePoint* const* const ii = m_cue_points;
- const CuePoint* const* i = ii;
-
- const CuePoint* const* const jj = ii + m_count;
- const CuePoint* const* j = jj;
-
- while (i < j)
- {
- //INVARIANT:
- //[ii, i) <= time_ns
- //[i, j) ?
- //[j, jj) > time_ns
-
- const CuePoint* const* const k = i + (j - i) / 2;
- assert(k < jj);
-
- pCP = *k;
- assert(pCP);
-
- const long long t = pCP->GetTime(m_pSegment);
-
- if (t <= time_ns)
- i = k + 1;
- else
- j = k;
-
- assert(i <= j);
- }
-
- assert(i == j);
- assert(i <= jj);
-
- if (i >= jj) //time_ns is greater than max cue point
- return false;
-
- pCP = *i;
- assert(pCP);
- assert(pCP->GetTime(m_pSegment) > time_ns);
-
- pTP = pCP->Find(pTrack);
- return (pTP != NULL);
-}
-#endif
-
-
-const CuePoint* Cues::GetFirst() const
-{
- LoadCuePoint(); //init cues
-
- const size_t count = m_count + m_preload_count;
-
- if (count == 0) //weird
- return NULL;
-
- CuePoint* const* const pp = m_cue_points;
- assert(pp);
-
- CuePoint* const pCP = pp[0];
- assert(pCP);
- assert(pCP->GetTimeCode() >= 0);
-
- return pCP;
-}
-
-
-const CuePoint* Cues::GetLast() const
-{
- LoadCuePoint(); //init cues
-
- const size_t count = m_count + m_preload_count;
-
- if (count == 0) //weird
- return NULL;
-
- const size_t index = count - 1;
-
- CuePoint* const* const pp = m_cue_points;
- assert(pp);
-
- CuePoint* const pCP = pp[index];
- assert(pCP);
-
- pCP->Load(m_pSegment->m_pReader);
- assert(pCP->GetTimeCode() >= 0);
-
- return pCP;
-}
-
-
-const CuePoint* Cues::GetNext(const CuePoint* pCurr) const
-{
- if (pCurr == NULL)
- return NULL;
-
- assert(pCurr->GetTimeCode() >= 0);
- assert(m_cue_points);
- assert(m_count >= 1);
-
- const size_t count = m_count + m_preload_count;
-
- size_t index = pCurr->m_index;
- assert(index < count);
-
- CuePoint* const* const pp = m_cue_points;
- assert(pp);
- assert(pp[index] == pCurr);
-
- ++index;
-
- if (index >= count)
- return NULL;
-
- CuePoint* const pNext = pp[index];
- assert(pNext);
-
- pNext->Load(m_pSegment->m_pReader);
-
- return pNext;
-}
-
-
-const BlockEntry* Cues::GetBlock(
- const CuePoint* pCP,
- const CuePoint::TrackPosition* pTP) const
-{
- if (pCP == NULL)
- return NULL;
-
- if (pTP == NULL)
- return NULL;
-
- return m_pSegment->GetBlock(*pCP, *pTP);
-}
-
-
-const BlockEntry* Segment::GetBlock(
- const CuePoint& cp,
- const CuePoint::TrackPosition& tp)
-{
- Cluster** const ii = m_clusters;
- Cluster** i = ii;
-
- const long count = m_clusterCount + m_clusterPreloadCount;
-
- Cluster** const jj = ii + count;
- Cluster** j = jj;
-
- while (i < j)
- {
- //INVARIANT:
- //[ii, i) < pTP->m_pos
- //[i, j) ?
- //[j, jj) > pTP->m_pos
-
- Cluster** const k = i + (j - i) / 2;
- assert(k < jj);
-
- Cluster* const pCluster = *k;
- assert(pCluster);
-
- const long long pos_ = pCluster->m_pos;
- assert(pos_);
-
- const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
-
- if (pos < tp.m_pos)
- i = k + 1;
- else if (pos > tp.m_pos)
- j = k;
- else
- return pCluster->GetEntry(cp, tp);
- }
-
- assert(i == j);
-
- Cluster* const pCluster = Cluster::Parse(this, -1, tp.m_pos);
- const ptrdiff_t idx = i - m_clusters;
-
- PreloadCluster(pCluster, idx);
- assert(m_clusters);
- assert(m_clusterPreloadCount > 0);
- assert(m_clusters[idx] == pCluster);
-
- return pCluster->GetEntry(cp, tp);
-}
-
-
-
-CuePoint::CuePoint(size_t idx, long long pos) :
- m_index(idx),
- m_timecode(-1 * pos),
- m_track_positions(NULL),
- m_track_positions_count(0)
-{
- assert(pos > 0);
-}
-
-
-CuePoint::~CuePoint()
-{
- delete[] m_track_positions;
-}
-
-
-void CuePoint::Load(IMkvReader* pReader)
-{
- //odbgstream os;
- //os << "CuePoint::Load(begin): timecode=" << m_timecode << endl;
-
- if (m_timecode >= 0) //already loaded
- return;
-
- assert(m_track_positions == NULL);
- assert(m_track_positions_count == 0);
-
- long long pos_ = -m_timecode;
-
- long long stop;
-
- {
- long len;
-
- const long long id = ReadUInt(pReader, pos_, len);
- assert(id == 0x3B); //CuePoint ID
- //assert((pos + len) <= stop);
-
- pos_ += len; //consume ID
-
- const long long size = ReadUInt(pReader, pos_, len);
- assert(size >= 0);
- //assert((pos + len) <= stop);
-
- pos_ += len; //consume Size field
- //assert((pos + size) <= stop);
-
- //pos_ now points to start of payload
-
- stop = pos_ + size;
- }
-
- long long pos = pos_;
-
- //First count number of track positions
-
- while (pos < stop)
- {
- long len;
-
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0); //TODO
- assert((pos + len) <= stop);
-
- pos += len; //consume ID
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size >= 0);
- assert((pos + len) <= stop);
-
- pos += len; //consume Size field
- assert((pos + size) <= stop);
-
- if (id == 0x33) //CueTime ID
- m_timecode = UnserializeUInt(pReader, pos, size);
-
- else if (id == 0x37) //CueTrackPosition(s) ID
- ++m_track_positions_count;
-
- pos += size; //consume payload
- assert(pos <= stop);
- }
-
- assert(m_timecode >= 0);
- assert(m_track_positions_count > 0);
-
- //os << "CuePoint::Load(cont'd): idpos=" << idpos
- // << " timecode=" << m_timecode
- // << endl;
-
- m_track_positions = new TrackPosition[m_track_positions_count];
-
- //Now parse track positions
-
- TrackPosition* p = m_track_positions;
- pos = pos_;
-
- while (pos < stop)
- {
- long len;
-
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0); //TODO
- assert((pos + len) <= stop);
-
- pos += len; //consume ID
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size >= 0);
- assert((pos + len) <= stop);
-
- pos += len; //consume Size field
- assert((pos + size) <= stop);
-
- if (id == 0x37) //CueTrackPosition(s) ID
- {
- TrackPosition& tp = *p++;
- tp.Parse(pReader, pos, size);
- }
-
- pos += size; //consume payload
- assert(pos <= stop);
- }
-
- assert(size_t(p - m_track_positions) == m_track_positions_count);
-}
-
-
-
-void CuePoint::TrackPosition::Parse(
- IMkvReader* pReader,
- long long start_,
- long long size_)
-{
- const long long stop = start_ + size_;
- long long pos = start_;
-
- m_track = -1;
- m_pos = -1;
- m_block = 1; //default
-
- while (pos < stop)
- {
- long len;
-
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0); //TODO
- assert((pos + len) <= stop);
-
- pos += len; //consume ID
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size >= 0);
- assert((pos + len) <= stop);
-
- pos += len; //consume Size field
- assert((pos + size) <= stop);
-
- if (id == 0x77) //CueTrack ID
- m_track = UnserializeUInt(pReader, pos, size);
-
- else if (id == 0x71) //CueClusterPos ID
- m_pos = UnserializeUInt(pReader, pos, size);
-
- else if (id == 0x1378) //CueBlockNumber
- m_block = UnserializeUInt(pReader, pos, size);
-
- pos += size; //consume payload
- assert(pos <= stop);
- }
-
- assert(m_pos >= 0);
- //assert(m_track > 0);
- //assert(m_block > 0);
-}
-
-
-const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const
-{
- assert(pTrack);
-
- const long long n = pTrack->GetNumber();
-
- const TrackPosition* i = m_track_positions;
- const TrackPosition* const j = i + m_track_positions_count;
-
- while (i != j)
- {
- const TrackPosition& p = *i++;
-
- if (p.m_track == n)
- return &p;
- }
-
- return NULL; //no matching track number found
-}
-
-
-long long CuePoint::GetTimeCode() const
-{
- return m_timecode;
-}
-
-long long CuePoint::GetTime(Segment* pSegment) const
-{
- assert(pSegment);
- assert(m_timecode >= 0);
-
- const SegmentInfo* const pInfo = pSegment->GetInfo();
- assert(pInfo);
-
- const long long scale = pInfo->GetTimeCodeScale();
- assert(scale >= 1);
-
- const long long time = scale * m_timecode;
-
- return time;
-}
-
-
-long long Segment::Unparsed() const
-{
- const long long stop = m_start + m_size;
-
- const long long result = stop - m_pos;
- assert(result >= 0);
-
- return result;
-}
-
-
-Cluster* Segment::GetFirst()
-{
- if ((m_clusters == NULL) || (m_clusterCount <= 0))
- return &m_eos;
-
- Cluster* const pCluster = m_clusters[0];
- assert(pCluster);
-
- return pCluster;
-}
-
-
-Cluster* Segment::GetLast()
-{
- if ((m_clusters == NULL) || (m_clusterCount <= 0))
- return &m_eos;
-
- const long idx = m_clusterCount - 1;
-
- Cluster* const pCluster = m_clusters[idx];
- assert(pCluster);
-
- return pCluster;
-}
-
-
-unsigned long Segment::GetCount() const
-{
- return m_clusterCount;
-}
-
-
-Cluster* Segment::GetNext(const Cluster* pCurr)
-{
- assert(pCurr);
- assert(pCurr != &m_eos);
- assert(m_clusters);
-
- long idx = pCurr->m_index;
-
- if (idx >= 0)
- {
- assert(m_clusterCount > 0);
- assert(idx < m_clusterCount);
- assert(pCurr == m_clusters[idx]);
-
- ++idx;
-
- if (idx >= m_clusterCount)
- return &m_eos; //caller will LoadCluster as desired
-
- Cluster* const pNext = m_clusters[idx];
- assert(pNext);
- assert(pNext->m_index >= 0);
- assert(pNext->m_index == idx);
-
- return pNext;
- }
-
- assert(m_clusterPreloadCount > 0);
-
- const long long off_ = pCurr->m_pos;
- const long long off = off_ * ((off_ < 0) ? -1 : 1);
-
- long long pos = m_start + off;
- const long long stop = m_start + m_size; //end of segment
-
- {
- long len;
-
- long long result = GetUIntLength(m_pReader, pos, len);
- assert(result == 0); //TODO
- assert((pos + len) <= stop); //TODO
-
- const long long id = ReadUInt(m_pReader, pos, len);
- assert(id == 0x0F43B675); //Cluster ID //TODO
-
- pos += len; //consume ID
-
- //Read Size
- result = GetUIntLength(m_pReader, pos, len);
- assert(result == 0); //TODO
- assert((pos + len) <= stop); //TODO
-
- const long long size = ReadUInt(m_pReader, pos, len);
- assert(size > 0); //TODO
- assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
-
- pos += len; //consume length of size of element
- assert((pos + size) <= stop); //TODO
-
- //Pos now points to start of payload
-
- pos += size; //consume payload
- }
-
- long long off_next = 0;
-
- while (pos < stop)
- {
- long len;
-
- long long result = GetUIntLength(m_pReader, pos, len);
- assert(result == 0); //TODO
- assert((pos + len) <= stop); //TODO
-
- const long long idpos = pos; //pos of next (potential) cluster
-
- const long long id = ReadUInt(m_pReader, idpos, len);
- assert(id > 0); //TODO
-
- pos += len; //consume ID
-
- //Read Size
- result = GetUIntLength(m_pReader, pos, len);
- assert(result == 0); //TODO
- assert((pos + len) <= stop); //TODO
-
- const long long size = ReadUInt(m_pReader, pos, len);
- assert(size >= 0); //TODO
-
- pos += len; //consume length of size of element
- assert((pos + size) <= stop); //TODO
-
- //Pos now points to start of payload
-
- if (size == 0) //weird
- continue;
-
- if (id == 0x0F43B675) //Cluster ID
- {
- off_next = idpos - m_start;
- break;
- }
-
- pos += size; //consume payload
- }
-
- if (off_next <= 0)
- return 0;
-
- Cluster** const ii = m_clusters + m_clusterCount;
- Cluster** i = ii;
-
- Cluster** const jj = ii + m_clusterPreloadCount;
- Cluster** j = jj;
-
- while (i < j)
- {
- //INVARIANT:
- //[0, i) < pos_next
- //[i, j) ?
- //[j, jj) > pos_next
-
- Cluster** const k = i + (j - i) / 2;
- assert(k < jj);
-
- Cluster* const pNext = *k;
- assert(pNext);
- assert(pNext->m_index < 0);
-
- const long long pos_ = pNext->m_pos;
- assert(pos_);
-
- pos = pos_ * ((pos_ < 0) ? -1 : 1);
-
- if (pos < off_next)
- i = k + 1;
- else if (pos > off_next)
- j = k;
- else
- return pNext;
- }
-
- assert(i == j);
-
- Cluster* const pNext = Cluster::Parse(this, -1, off_next);
- const ptrdiff_t idx_next = i - m_clusters; //insertion position
-
- PreloadCluster(pNext, idx_next);
- assert(m_clusters);
- assert(idx_next < m_clusterSize);
- assert(m_clusters[idx_next] == pNext);
-
- return pNext;
-}
-
-
-Cluster* Segment::FindCluster(long long time_ns)
-{
- if ((m_clusters == NULL) || (m_clusterCount <= 0))
- return &m_eos;
-
- {
- Cluster* const pCluster = m_clusters[0];
- assert(pCluster);
- assert(pCluster->m_index == 0);
-
- if (time_ns <= pCluster->GetTime())
- return pCluster;
- }
-
- //Binary search of cluster array
-
- long i = 0;
- long j = m_clusterCount;
-
- while (i < j)
- {
- //INVARIANT:
- //[0, i) <= time_ns
- //[i, j) ?
- //[j, m_clusterCount) > time_ns
-
- const long k = i + (j - i) / 2;
- assert(k < m_clusterCount);
-
- Cluster* const pCluster = m_clusters[k];
- assert(pCluster);
- assert(pCluster->m_index == k);
-
- const long long t = pCluster->GetTime();
-
- if (t <= time_ns)
- i = k + 1;
- else
- j = k;
-
- assert(i <= j);
- }
-
- assert(i == j);
- assert(i > 0);
- assert(i <= m_clusterCount);
-
- const long k = i - 1;
-
- Cluster* const pCluster = m_clusters[k];
- assert(pCluster);
- assert(pCluster->m_index == k);
- assert(pCluster->GetTime() <= time_ns);
-
- return pCluster;
-}
-
-
-const BlockEntry* Segment::Seek(
- long long time_ns,
- const Track* pTrack)
-{
- assert(pTrack);
-
- if ((m_clusters == NULL) || (m_clusterCount <= 0))
- return pTrack->GetEOS();
-
- Cluster** const i = m_clusters;
- assert(i);
-
- {
- Cluster* const pCluster = *i;
- assert(pCluster);
- assert(pCluster->m_index == 0); //m_clusterCount > 0
- assert(pCluster->m_pSegment == this);
-
- if (time_ns <= pCluster->GetTime())
- return pCluster->GetEntry(pTrack);
- }
-
- Cluster** const j = i + m_clusterCount;
-
- if (pTrack->GetType() == 2) //audio
- {
- //TODO: we could decide to use cues for this, as we do for video.
- //But we only use it for video because looking around for a keyframe
- //can get expensive. Audio doesn't require anything special so a
- //straight cluster search is good enough (we assume).
-
- Cluster** lo = i;
- Cluster** hi = j;
-
- while (lo < hi)
- {
- //INVARIANT:
- //[i, lo) <= time_ns
- //[lo, hi) ?
- //[hi, j) > time_ns
-
- Cluster** const mid = lo + (hi - lo) / 2;
- assert(mid < hi);
-
- Cluster* const pCluster = *mid;
- assert(pCluster);
- assert(pCluster->m_index == long(mid - m_clusters));
- assert(pCluster->m_pSegment == this);
-
- const long long t = pCluster->GetTime();
-
- if (t <= time_ns)
- lo = mid + 1;
- else
- hi = mid;
-
- assert(lo <= hi);
- }
-
- assert(lo == hi);
- assert(lo > i);
- assert(lo <= j);
-
- Cluster* const pCluster = *--lo;
- assert(pCluster);
- assert(pCluster->GetTime() <= time_ns);
-
- return pCluster->GetEntry(pTrack);
- }
-
- assert(pTrack->GetType() == 1); //video
-
- Cluster** lo = i;
- Cluster** hi = j;
-
- while (lo < hi)
- {
- //INVARIANT:
- //[i, lo) <= time_ns
- //[lo, hi) ?
- //[hi, j) > time_ns
-
- Cluster** const mid = lo + (hi - lo) / 2;
- assert(mid < hi);
-
- Cluster* const pCluster = *mid;
- assert(pCluster);
-
- const long long t = pCluster->GetTime();
-
- if (t <= time_ns)
- lo = mid + 1;
- else
- hi = mid;
-
- assert(lo <= hi);
- }
-
- assert(lo == hi);
- assert(lo > i);
- assert(lo <= j);
-
- Cluster* pCluster = *--lo;
- assert(pCluster);
- assert(pCluster->GetTime() <= time_ns);
-
- {
- const BlockEntry* const pBlockEntry = pCluster->GetEntry(pTrack);
- assert(pBlockEntry);
-
- if (!pBlockEntry->EOS()) //found a keyframe
- {
- const Block* const pBlock = pBlockEntry->GetBlock();
- assert(pBlock);
-
- //TODO: this isn't necessarily the keyframe we want,
- //since there might another keyframe on this same
- //cluster with a greater timecode that but that is
- //still less than the requested time. For now we
- //simply return the first keyframe we find.
-
- if (pBlock->GetTime(pCluster) <= time_ns)
- return pBlockEntry;
- }
- }
-
- const VideoTrack* const pVideo = static_cast<const VideoTrack*>(pTrack);
-
- while (lo != i)
- {
- pCluster = *--lo;
- assert(pCluster);
- assert(pCluster->GetTime() <= time_ns);
-
- const BlockEntry* const pBlockEntry = pCluster->GetMaxKey(pVideo);
- assert(pBlockEntry);
-
- if (!pBlockEntry->EOS())
- return pBlockEntry;
- }
-
- //weird: we're on the first cluster, but no keyframe found
- //should never happen but we must return something anyway
-
- return pTrack->GetEOS();
-}
-
-
-#if 0
-bool Segment::SearchCues(
- long long time_ns,
- Track* pTrack,
- Cluster*& pCluster,
- const BlockEntry*& pBlockEntry,
- const CuePoint*& pCP,
- const CuePoint::TrackPosition*& pTP)
-{
- if (pTrack->GetType() != 1) //not video
- return false; //TODO: for now, just handle video stream
-
- if (m_pCues == NULL)
- return false;
-
- if (!m_pCues->Find(time_ns, pTrack, pCP, pTP))
- return false; //weird
-
- assert(pCP);
- assert(pTP);
- assert(pTP->m_track == pTrack->GetNumber());
-
- //We have the cue point and track position we want,
- //so we now need to search for the cluster having
- //the indicated position.
-
- return GetCluster(pCP, pTP, pCluster, pBlockEntry);
-}
-#endif
-
-
-Tracks* Segment::GetTracks() const
-{
- return m_pTracks;
-}
-
-
-const SegmentInfo* Segment::GetInfo() const
-{
- return m_pInfo;
-}
-
-
-const Cues* Segment::GetCues() const
-{
- return m_pCues;
-}
-
-
-long long Segment::GetDuration() const
-{
- assert(m_pInfo);
- return m_pInfo->GetDuration();
-}
-
-
-SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_) :
- m_pSegment(pSegment),
- m_start(start),
- m_size(size_),
- m_pMuxingAppAsUTF8(NULL),
- m_pWritingAppAsUTF8(NULL),
- m_pTitleAsUTF8(NULL)
-{
- IMkvReader* const pReader = m_pSegment->m_pReader;
-
- long long pos = start;
- const long long stop = start + size_;
-
- m_timecodeScale = 1000000;
- m_duration = -1;
-
- while (pos < stop)
- {
- if (Match(pReader, pos, 0x0AD7B1, m_timecodeScale))
- assert(m_timecodeScale > 0);
-
- else if (Match(pReader, pos, 0x0489, m_duration))
- assert(m_duration >= 0);
-
- else if (Match(pReader, pos, 0x0D80, m_pMuxingAppAsUTF8)) //[4D][80]
- assert(m_pMuxingAppAsUTF8);
-
- else if (Match(pReader, pos, 0x1741, m_pWritingAppAsUTF8)) //[57][41]
- assert(m_pWritingAppAsUTF8);
-
- else if (Match(pReader, pos, 0x3BA9, m_pTitleAsUTF8)) //[7B][A9]
- assert(m_pTitleAsUTF8);
-
- else
- {
- long len;
-
- const long long id = ReadUInt(pReader, pos, len);
- //id;
- assert(id >= 0);
- assert((pos + len) <= stop);
-
- pos += len; //consume id
- assert((stop - pos) > 0);
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size >= 0);
- assert((pos + len) <= stop);
-
- pos += len + size; //consume size and payload
- assert(pos <= stop);
- }
- }
-
- assert(pos == stop);
-}
-
-SegmentInfo::~SegmentInfo()
-{
- if (m_pMuxingAppAsUTF8)
- {
- delete[] m_pMuxingAppAsUTF8;
- m_pMuxingAppAsUTF8 = NULL;
- }
-
- if (m_pWritingAppAsUTF8)
- {
- delete[] m_pWritingAppAsUTF8;
- m_pWritingAppAsUTF8 = NULL;
- }
-
- if (m_pTitleAsUTF8)
- {
- delete[] m_pTitleAsUTF8;
- m_pTitleAsUTF8 = NULL;
- }
-}
-
-long long SegmentInfo::GetTimeCodeScale() const
-{
- return m_timecodeScale;
-}
-
-
-long long SegmentInfo::GetDuration() const
-{
- if (m_duration < 0)
- return -1;
-
- assert(m_timecodeScale >= 1);
-
- const double dd = double(m_duration) * double(m_timecodeScale);
- const long long d = static_cast<long long>(dd);
-
- return d;
-}
-
-const char* SegmentInfo::GetMuxingAppAsUTF8() const
-{
- return m_pMuxingAppAsUTF8;
-}
-
-
-const char* SegmentInfo::GetWritingAppAsUTF8() const
-{
- return m_pWritingAppAsUTF8;
-}
-
-const char* SegmentInfo::GetTitleAsUTF8() const
-{
- return m_pTitleAsUTF8;
-}
-
-Track::Track(Segment* pSegment, const Info& i) :
- m_pSegment(pSegment),
- m_info(i)
-{
-}
-
-Track::~Track()
-{
- Info& info = const_cast<Info&>(m_info);
- info.Clear();
-}
-
-Track::Info::Info():
- type(-1),
- number(-1),
- uid(-1),
- nameAsUTF8(NULL),
- codecId(NULL),
- codecPrivate(NULL),
- codecPrivateSize(0),
- codecNameAsUTF8(NULL)
-{
-}
-
-
-void Track::Info::Clear()
-{
- delete[] nameAsUTF8;
- nameAsUTF8 = NULL;
-
- delete[] codecId;
- codecId = NULL;
-
- delete[] codecPrivate;
- codecPrivate = NULL;
-
- codecPrivateSize = 0;
-
- delete[] codecNameAsUTF8;
- codecNameAsUTF8 = NULL;
-}
-
-const BlockEntry* Track::GetEOS() const
-{
- return &m_eos;
-}
-
-long long Track::GetType() const
-{
- return m_info.type;
-}
-
-long long Track::GetNumber() const
-{
- return m_info.number;
-}
-
-const char* Track::GetNameAsUTF8() const
-{
- return m_info.nameAsUTF8;
-}
-
-const char* Track::GetCodecNameAsUTF8() const
-{
- return m_info.codecNameAsUTF8;
-}
-
-
-const char* Track::GetCodecId() const
-{
- return m_info.codecId;
-}
-
-const unsigned char* Track::GetCodecPrivate(size_t& size) const
-{
- size = m_info.codecPrivateSize;
- return m_info.codecPrivate;
-}
-
-
-long Track::GetFirst(const BlockEntry*& pBlockEntry) const
-{
- Cluster* pCluster = m_pSegment->GetFirst();
-
- //If Segment::GetFirst returns NULL, then this must be a network
- //download, and we haven't loaded any clusters yet. In this case,
- //returning NULL from Track::GetFirst means the same thing.
-
- for (int i = 0; i < 100; ++i) //arbitrary upper bound
- {
- if (pCluster == NULL)
- {
- pBlockEntry = GetEOS();
- return 1;
- }
-
- if (pCluster->EOS())
- {
- if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded
- {
- pBlockEntry = GetEOS();
- return 1;
- }
-
- pBlockEntry = 0;
- return E_BUFFER_NOT_FULL;
- }
-
- pBlockEntry = pCluster->GetFirst();
-
- while (pBlockEntry)
- {
- const Block* const pBlock = pBlockEntry->GetBlock();
- assert(pBlock);
-
- if (pBlock->GetTrackNumber() == m_info.number)
- return 0;
-
- pBlockEntry = pCluster->GetNext(pBlockEntry);
- }
-
- pCluster = m_pSegment->GetNext(pCluster);
- }
-
- //NOTE: if we get here, it means that we didn't find a block with
- //a matching track number. We interpret that as an error (which
- //might be too conservative).
-
- pBlockEntry = GetEOS(); //so we can return a non-NULL value
- return 1;
-}
-
-
-long Track::GetNext(
- const BlockEntry* pCurrEntry,
- const BlockEntry*& pNextEntry) const
-{
- assert(pCurrEntry);
- assert(!pCurrEntry->EOS()); //?
-
- const Block* const pCurrBlock = pCurrEntry->GetBlock();
- assert(pCurrBlock->GetTrackNumber() == m_info.number);
-
- Cluster* pCluster = pCurrEntry->GetCluster();
- assert(pCluster);
- assert(!pCluster->EOS());
-
- pNextEntry = pCluster->GetNext(pCurrEntry);
-
- for (int i = 0; i < 100; ++i) //arbitrary upper bound to search
- {
- while (pNextEntry)
- {
- const Block* const pNextBlock = pNextEntry->GetBlock();
- assert(pNextBlock);
-
- if (pNextBlock->GetTrackNumber() == m_info.number)
- return 0;
-
- pNextEntry = pCluster->GetNext(pNextEntry);
- }
-
- pCluster = m_pSegment->GetNext(pCluster);
-
- if (pCluster == NULL)
- {
- pNextEntry = GetEOS();
- return 1;
- }
-
- if (pCluster->EOS())
- {
- if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded
- {
- pNextEntry = GetEOS();
- return 1;
- }
-
- //TODO: there is a potential O(n^2) problem here: we tell the
- //caller to (pre)load another cluster, which he does, but then he
- //calls GetNext again, which repeats the same search. This is
- //a pathological case, since the only way it can happen is if
- //there exists a long sequence of clusters none of which contain a
- // block from this track. One way around this problem is for the
- //caller to be smarter when he loads another cluster: don't call
- //us back until you have a cluster that contains a block from this
- //track. (Of course, that's not cheap either, since our caller
- //would have to scan the each cluster as it's loaded, so that
- //would just push back the problem.)
-
- pNextEntry = NULL;
- return E_BUFFER_NOT_FULL;
- }
-
- pNextEntry = pCluster->GetFirst();
- }
-
- //NOTE: if we get here, it means that we didn't find a block with
- //a matching track number after lots of searching, so we give
- //up trying.
-
- pNextEntry = GetEOS(); //so we can return a non-NULL value
- return 1;
-}
-
-
-Track::EOSBlock::EOSBlock()
-{
-}
-
-
-bool Track::EOSBlock::EOS() const
-{
- return true;
-}
-
-
-Cluster* Track::EOSBlock::GetCluster() const
-{
- return NULL;
-}
-
-
-size_t Track::EOSBlock::GetIndex() const
-{
- return 0;
-}
-
-
-const Block* Track::EOSBlock::GetBlock() const
-{
- return NULL;
-}
-
-
-bool Track::EOSBlock::IsBFrame() const
-{
- return false;
-}
-
-
-VideoTrack::VideoTrack(Segment* pSegment, const Info& i) :
- Track(pSegment, i),
- m_width(-1),
- m_height(-1),
- m_rate(-1)
-{
- assert(i.type == 1);
- assert(i.number > 0);
-
- IMkvReader* const pReader = pSegment->m_pReader;
-
- const Settings& s = i.settings;
- assert(s.start >= 0);
- assert(s.size >= 0);
-
- long long pos = s.start;
- assert(pos >= 0);
-
- const long long stop = pos + s.size;
-
- while (pos < stop)
- {
-#ifdef _DEBUG
- long len;
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0); //TODO: handle error case
- assert((pos + len) <= stop);
-#endif
- if (Match(pReader, pos, 0x30, m_width))
- ;
- else if (Match(pReader, pos, 0x3A, m_height))
- ;
- else if (Match(pReader, pos, 0x0383E3, m_rate))
- ;
- else
- {
- long len;
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0); //TODO: handle error case
- assert((pos + len) <= stop);
-
- pos += len; //consume id
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size >= 0); //TODO: handle error case
- assert((pos + len) <= stop);
-
- pos += len; //consume length of size
- assert((pos + size) <= stop);
-
- //pos now designates start of payload
-
- pos += size; //consume payload
- assert(pos <= stop);
- }
- }
-
- return;
-}
-
-
-bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const
-{
- assert(pBlockEntry);
-
- const Block* const pBlock = pBlockEntry->GetBlock();
- assert(pBlock);
- assert(pBlock->GetTrackNumber() == m_info.number);
-
- return pBlock->IsKey();
-}
-
-
-long long VideoTrack::GetWidth() const
-{
- return m_width;
-}
-
-
-long long VideoTrack::GetHeight() const
-{
- return m_height;
-}
-
-
-double VideoTrack::GetFrameRate() const
-{
- return m_rate;
-}
-
-
-AudioTrack::AudioTrack(Segment* pSegment, const Info& i) :
- Track(pSegment, i),
- m_rate(0.0),
- m_channels(0),
- m_bitDepth(-1)
-{
- assert(i.type == 2);
- assert(i.number > 0);
-
- IMkvReader* const pReader = pSegment->m_pReader;
-
- const Settings& s = i.settings;
- assert(s.start >= 0);
- assert(s.size >= 0);
-
- long long pos = s.start;
- assert(pos >= 0);
-
- const long long stop = pos + s.size;
-
- while (pos < stop)
- {
-#ifdef _DEBUG
- long len;
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0); //TODO: handle error case
- assert((pos + len) <= stop);
-#endif
- if (Match(pReader, pos, 0x35, m_rate))
- ;
- else if (Match(pReader, pos, 0x1F, m_channels))
- ;
- else if (Match(pReader, pos, 0x2264, m_bitDepth))
- ;
- else
- {
- long len;
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0); //TODO: handle error case
- assert((pos + len) <= stop);
-
- pos += len; //consume id
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size >= 0); //TODO: handle error case
- assert((pos + len) <= stop);
-
- pos += len; //consume length of size
- assert((pos + size) <= stop);
-
- //pos now designates start of payload
-
- pos += size; //consume payload
- assert(pos <= stop);
- }
- }
-
- return;
-}
-
-
-bool AudioTrack::VetEntry(const BlockEntry* pBlockEntry) const
-{
- assert(pBlockEntry);
-
- const Block* const pBlock = pBlockEntry->GetBlock();
- assert(pBlock);
- assert(pBlock->GetTrackNumber() == m_info.number);
-
- return true;
-}
-
-
-double AudioTrack::GetSamplingRate() const
-{
- return m_rate;
-}
-
-
-long long AudioTrack::GetChannels() const
-{
- return m_channels;
-}
-
-long long AudioTrack::GetBitDepth() const
-{
- return m_bitDepth;
-}
-
-Tracks::Tracks(Segment* pSegment, long long start, long long size_) :
- m_pSegment(pSegment),
- m_start(start),
- m_size(size_),
- m_trackEntries(NULL),
- m_trackEntriesEnd(NULL)
-{
- long long stop = m_start + m_size;
- IMkvReader* const pReader = m_pSegment->m_pReader;
-
- long long pos1 = m_start;
- int count = 0;
-
- while (pos1 < stop)
- {
- long len;
- const long long id = ReadUInt(pReader, pos1, len);
- assert(id >= 0);
- assert((pos1 + len) <= stop);
-
- pos1 += len; //consume id
-
- const long long size = ReadUInt(pReader, pos1, len);
- assert(size >= 0);
- assert((pos1 + len) <= stop);
-
- pos1 += len; //consume length of size
-
- //pos now desinates start of element
- if (id == 0x2E) //TrackEntry ID
- ++count;
-
- pos1 += size; //consume payload
- assert(pos1 <= stop);
- }
-
- if (count <= 0)
- return;
-
- m_trackEntries = new Track*[count];
- m_trackEntriesEnd = m_trackEntries;
-
- long long pos = m_start;
-
- while (pos < stop)
- {
- long len;
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0);
- assert((pos + len) <= stop);
-
- pos += len; //consume id
-
- const long long size1 = ReadUInt(pReader, pos, len);
- assert(size1 >= 0);
- assert((pos + len) <= stop);
-
- pos += len; //consume length of size
-
- //pos now desinates start of element
-
- if (id == 0x2E) //TrackEntry ID
- ParseTrackEntry(pos, size1, *m_trackEntriesEnd++);
-
- pos += size1; //consume payload
- assert(pos <= stop);
- }
-}
-
-
-unsigned long Tracks::GetTracksCount() const
-{
- const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries;
- assert(result >= 0);
-
- return static_cast<unsigned long>(result);
-}
-
-
-void Tracks::ParseTrackEntry(
- long long start,
- long long size,
- Track*& pTrack)
-{
- IMkvReader* const pReader = m_pSegment->m_pReader;
-
- long long pos = start;
- const long long stop = start + size;
-
- Track::Info i;
-
- Track::Settings videoSettings;
- videoSettings.start = -1;
-
- Track::Settings audioSettings;
- audioSettings.start = -1;
-
- while (pos < stop)
- {
-#ifdef _DEBUG
- long len;
- const long long id = ReadUInt(pReader, pos, len);
- len;
- id;
-#endif
- if (Match(pReader, pos, 0x57, i.number))
- assert(i.number > 0);
- else if (Match(pReader, pos, 0x33C5, i.uid))
- ;
- else if (Match(pReader, pos, 0x03, i.type))
- ;
- else if (Match(pReader, pos, 0x136E, i.nameAsUTF8))
- assert(i.nameAsUTF8);
- else if (Match(pReader, pos, 0x06, i.codecId))
- ;
- else if (Match(pReader,
- pos,
- 0x23A2,
- i.codecPrivate,
- i.codecPrivateSize))
- ;
- else if (Match(pReader, pos, 0x058688, i.codecNameAsUTF8))
- assert(i.codecNameAsUTF8);
- else
- {
- long len;
-
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0); //TODO: handle error case
- assert((pos + len) <= stop);
-
- pos += len; //consume id
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size >= 0); //TODO: handle error case
- assert((pos + len) <= stop);
-
- pos += len; //consume length of size
- const long long start = pos;
-
- pos += size; //consume payload
- assert(pos <= stop);
-
- if (id == 0x60)
- {
- videoSettings.start = start;
- videoSettings.size = size;
- }
- else if (id == 0x61)
- {
- audioSettings.start = start;
- audioSettings.size = size;
- }
- }
- }
-
- assert(pos == stop);
- //TODO: propertly vet info.number, to ensure both its existence,
- //and that it is unique among all tracks.
- assert(i.number > 0);
-
- //TODO: vet settings, to ensure that video settings (0x60)
- //were specified when type = 1, and that audio settings (0x61)
- //were specified when type = 2.
- if (i.type == 1) //video
- {
- assert(audioSettings.start < 0);
- assert(videoSettings.start >= 0);
-
- i.settings = videoSettings;
-
- VideoTrack* const t = new VideoTrack(m_pSegment, i);
- assert(t); //TODO
- pTrack = t;
- }
- else if (i.type == 2) //audio
- {
- assert(videoSettings.start < 0);
- assert(audioSettings.start >= 0);
-
- i.settings = audioSettings;
-
- AudioTrack* const t = new AudioTrack(m_pSegment, i);
- assert(t); //TODO
- pTrack = t;
- }
- else
- {
- // for now we do not support other track types yet.
- // TODO: support other track types
- i.Clear();
-
- pTrack = NULL;
- }
-
- return;
-}
-
-
-Tracks::~Tracks()
-{
- Track** i = m_trackEntries;
- Track** const j = m_trackEntriesEnd;
-
- while (i != j)
- {
- Track* const pTrack = *i++;
- delete pTrack;
- }
-
- delete[] m_trackEntries;
-}
-
-
-Track* Tracks::GetTrackByNumber(unsigned long tn_) const
-{
- const long long tn = tn_;
-
- Track** i = m_trackEntries;
- Track** const j = m_trackEntriesEnd;
-
- while (i != j)
- {
- Track* const pTrack = *i++;
-
- if (pTrack == NULL)
- continue;
-
- if (tn == pTrack->GetNumber())
- return pTrack;
- }
-
- return NULL; //not found
-}
-
-
-Track* Tracks::GetTrackByIndex(unsigned long idx) const
-{
- const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries;
-
- if (idx >= static_cast<unsigned long>(count))
- return NULL;
-
- return m_trackEntries[idx];
-}
-
-
-void Cluster::Load()
-{
- assert(m_pSegment);
- assert(m_pos);
- assert(m_size);
-
- if (m_pos > 0) //loaded
- {
- assert(m_size > 0);
- assert(m_timecode >= 0);
- return;
- }
-
- assert(m_pos < 0); //not loaded yet
- assert(m_size < 0);
- assert(m_timecode < 0);
-
- IMkvReader* const pReader = m_pSegment->m_pReader;
-
- m_pos *= -1; //relative to segment
- long long pos = m_pSegment->m_start + m_pos; //absolute
-
- long len;
-
- const long long id_ = ReadUInt(pReader, pos, len);
- assert(id_ >= 0);
- assert(id_ == 0x0F43B675); //Cluster ID
-
- pos += len; //consume id
-
- const long long size_ = ReadUInt(pReader, pos, len);
- assert(size_ >= 0);
-
- pos += len; //consume size
-
- m_size = size_;
- const long long stop = pos + size_;
-
- long long timecode = -1;
-
- while (pos < stop)
- {
- if (Match(pReader, pos, 0x67, timecode))
- break;
- else
- {
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0); //TODO
- assert((pos + len) <= stop);
-
- pos += len; //consume id
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size >= 0); //TODO
- assert((pos + len) <= stop);
-
- pos += len; //consume size
-
- if (id == 0x20) //BlockGroup ID
- break;
-
- if (id == 0x23) //SimpleBlock ID
- break;
-
- pos += size; //consume payload
- assert(pos <= stop);
- }
- }
-
- assert(pos <= stop);
- assert(timecode >= 0);
-
- m_timecode = timecode;
-}
-
-
-Cluster* Cluster::Parse(
- Segment* pSegment,
- long idx,
- long long off)
-{
- assert(pSegment);
- assert(off >= 0);
- assert(off < pSegment->m_size);
-
- Cluster* const pCluster = new Cluster(pSegment, idx, -off);
- assert(pCluster);
-
- return pCluster;
-}
-
-
-Cluster::Cluster() :
- m_pSegment(NULL),
- m_index(0),
- m_pos(0),
- m_size(0),
- m_timecode(0),
- m_entries(NULL),
- m_entriesCount(0)
-{
-}
-
-
-Cluster::Cluster(
- Segment* pSegment,
- long idx,
- long long off) :
- m_pSegment(pSegment),
- m_index(idx),
- m_pos(off),
- m_size(-1),
- m_timecode(-1),
- m_entries(NULL),
- m_entriesCount(0)
-{
-}
-
-
-Cluster::~Cluster()
-{
- BlockEntry** i = m_entries;
- BlockEntry** const j = m_entries + m_entriesCount;
-
- while (i != j)
- {
- BlockEntry* p = *i++;
- assert(p);
-
- delete p;
- }
-
- delete[] m_entries;
-}
-
-
-bool Cluster::EOS() const
-{
- return (m_pSegment == NULL);
-}
-
-
-void Cluster::LoadBlockEntries()
-{
- if (m_entries)
- return;
-
- assert(m_pSegment);
- assert(m_pos);
- assert(m_size);
- assert(m_entriesCount == 0);
-
- IMkvReader* const pReader = m_pSegment->m_pReader;
-
- if (m_pos < 0)
- m_pos *= -1; //relative to segment
-
- long long pos = m_pSegment->m_start + m_pos; //absolute
-
- {
- long len;
-
- const long long id = ReadUInt(pReader, pos, len);
- id;
- assert(id >= 0);
- assert(id == 0x0F43B675); //Cluster ID
-
- pos += len; //consume id
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size > 0);
-
- pos += len; //consume size
-
- //pos now points to start of payload
-
- if (m_size >= 0)
- assert(size == m_size);
- else
- m_size = size;
- }
-
- const long long stop = pos + m_size;
- long long timecode = -1; //of cluster itself
-
- //First count the number of entries
-
- long long idx = pos; //points to start of payload
- m_entriesCount = 0;
-
- while (idx < stop)
- {
- if (Match(pReader, idx, 0x67, timecode))
- {
- if (m_timecode >= 0)
- assert(timecode == m_timecode);
- else
- m_timecode = timecode;
- }
- else
- {
- long len;
-
- const long long id = ReadUInt(pReader, idx, len);
- assert(id >= 0); //TODO
- assert((idx + len) <= stop);
-
- idx += len; //consume id
-
- const long long size = ReadUInt(pReader, idx, len);
- assert(size >= 0); //TODO
- assert((idx + len) <= stop);
-
- idx += len; //consume size
-
- if (id == 0x20) //BlockGroup ID
- ++m_entriesCount;
- else if (id == 0x23) //SimpleBlock ID
- ++m_entriesCount;
-
- idx += size; //consume payload
- assert(idx <= stop);
- }
- }
-
- assert(idx == stop);
- assert(m_timecode >= 0);
-
- if (m_entriesCount == 0) //TODO: handle empty clusters
- return;
-
- m_entries = new BlockEntry*[m_entriesCount];
- size_t index = 0;
-
- while (pos < stop)
- {
- if (Match(pReader, pos, 0x67, timecode))
- assert(timecode == m_timecode);
- else
- {
- long len;
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0); //TODO
- assert((pos + len) <= stop);
-
- pos += len; //consume id
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size >= 0); //TODO
- assert((pos + len) <= stop);
-
- pos += len; //consume size
-
- if (id == 0x20) //BlockGroup ID
- ParseBlockGroup(pos, size, index++);
- else if (id == 0x23) //SimpleBlock ID
- ParseSimpleBlock(pos, size, index++);
-
- pos += size; //consume payload
- assert(pos <= stop);
- }
- }
-
- assert(pos == stop);
- assert(timecode >= 0);
- assert(index == m_entriesCount);
-}
-
-
-
-long long Cluster::GetTimeCode()
-{
- Load();
- return m_timecode;
-}
-
-
-long long Cluster::GetTime()
-{
- const long long tc = GetTimeCode();
- assert(tc >= 0);
-
- const SegmentInfo* const pInfo = m_pSegment->GetInfo();
- assert(pInfo);
-
- const long long scale = pInfo->GetTimeCodeScale();
- assert(scale >= 1);
-
- const long long t = m_timecode * scale;
-
- return t;
-}
-
-
-long long Cluster::GetFirstTime()
-{
- const BlockEntry* const pEntry = GetFirst();
-
- if (pEntry == NULL) //empty cluster
- return GetTime();
-
- const Block* const pBlock = pEntry->GetBlock();
- assert(pBlock);
-
- return pBlock->GetTime(this);
-}
-
-
-long long Cluster::GetLastTime()
-{
- const BlockEntry* const pEntry = GetLast();
-
- if (pEntry == NULL) //empty cluster
- return GetTime();
-
- const Block* const pBlock = pEntry->GetBlock();
- assert(pBlock);
-
- return pBlock->GetTime(this);
-}
-
-
-void Cluster::ParseBlockGroup(long long start, long long size, size_t index)
-{
- assert(m_entries);
- assert(m_entriesCount);
- assert(index < m_entriesCount);
-
- BlockGroup* const pGroup =
- new (std::nothrow) BlockGroup(this, index, start, size);
- assert(pGroup); //TODO
-
- m_entries[index] = pGroup;
-}
-
-
-
-void Cluster::ParseSimpleBlock(long long start, long long size, size_t index)
-{
- assert(m_entries);
- assert(m_entriesCount);
- assert(index < m_entriesCount);
-
- SimpleBlock* const pSimpleBlock =
- new (std::nothrow) SimpleBlock(this, index, start, size);
- assert(pSimpleBlock); //TODO
-
- m_entries[index] = pSimpleBlock;
-}
-
-
-const BlockEntry* Cluster::GetFirst()
-{
- LoadBlockEntries();
- //assert(m_entries);
- //assert(m_entriesCount >= 1);
-
- if ((m_entries == NULL) || (m_entriesCount == 0))
- return NULL;
-
- const BlockEntry* const pFirst = m_entries[0];
- assert(pFirst);
-
- return pFirst;
-}
-
-
-const BlockEntry* Cluster::GetLast()
-{
- LoadBlockEntries();
- //assert(m_entries);
- //assert(m_entriesCount >= 1);
-
- if ((m_entries == NULL) || (m_entriesCount == 0))
- return NULL;
-
- const size_t idx = m_entriesCount - 1;
-
- const BlockEntry* const pLast = m_entries[idx];
- assert(pLast);
-
- return pLast;
-}
-
-
-const BlockEntry* Cluster::GetNext(const BlockEntry* pEntry) const
-{
- assert(pEntry);
- assert(m_entries);
- assert(m_entriesCount);
-
- size_t idx = pEntry->GetIndex();
- assert(idx < m_entriesCount);
- assert(m_entries[idx] == pEntry);
-
- ++idx;
-
- if (idx >= m_entriesCount)
- return NULL;
-
- return m_entries[idx];
-}
-
-
-const BlockEntry* Cluster::GetEntry(const Track* pTrack)
-{
- assert(pTrack);
-
- if (m_pSegment == NULL) //EOS
- return pTrack->GetEOS();
-
- LoadBlockEntries();
-
- if ((m_entries == NULL) || (m_entriesCount == 0))
- return NULL;
-
- BlockEntry** i = m_entries;
- assert(i);
-
- BlockEntry** const j = i + m_entriesCount;
-
- while (i != j)
- {
- const BlockEntry* const pEntry = *i++;
- assert(pEntry);
- assert(!pEntry->EOS());
-
- const Block* const pBlock = pEntry->GetBlock();
- assert(pBlock);
-
- if (pBlock->GetTrackNumber() != pTrack->GetNumber())
- continue;
-
- if (pTrack->VetEntry(pEntry))
- return pEntry;
- }
-
- return pTrack->GetEOS(); //no satisfactory block found
-}
-
-
-const BlockEntry*
-Cluster::GetEntry(
- const CuePoint& cp,
- const CuePoint::TrackPosition& tp)
-{
- assert(m_pSegment);
-
- LoadBlockEntries();
-
- if (m_entries == NULL)
- return NULL;
-
- const long long count = m_entriesCount;
-
- if (count <= 0)
- return NULL;
-
- const long long tc = cp.GetTimeCode();
-
- if ((tp.m_block > 0) && (tp.m_block <= count))
- {
- const size_t block = static_cast<size_t>(tp.m_block);
- const size_t index = block - 1;
-
- const BlockEntry* const pEntry = m_entries[index];
- assert(pEntry);
- assert(!pEntry->EOS());
-
- const Block* const pBlock = pEntry->GetBlock();
- assert(pBlock);
-
- if ((pBlock->GetTrackNumber() == tp.m_track) &&
- (pBlock->GetTimeCode(this) == tc))
- {
- return pEntry;
- }
- }
-
- const BlockEntry* const* i = m_entries;
- const BlockEntry* const* const j = i + count;
-
- while (i != j)
- {
- const BlockEntry* const pEntry = *i++;
- assert(pEntry);
- assert(!pEntry->EOS());
-
- const Block* const pBlock = pEntry->GetBlock();
- assert(pBlock);
-
- if (pBlock->GetTrackNumber() != tp.m_track)
- continue;
-
- const long long tc_ = pBlock->GetTimeCode(this);
-
- if (tc_ < tc)
- continue;
-
- if (tc_ > tc)
- return NULL;
-
- const Tracks* const pTracks = m_pSegment->GetTracks();
- assert(pTracks);
-
- const long tn = static_cast<long>(tp.m_track);
- const Track* const pTrack = pTracks->GetTrackByNumber(tn);
-
- if (pTrack == NULL)
- return NULL;
-
- const long long type = pTrack->GetType();
-
- if (type == 2) //audio
- return pEntry;
-
- if (type != 1) //not video
- return NULL;
-
- if (!pBlock->IsKey())
- return NULL;
-
- return pEntry;
- }
-
- return NULL;
-}
-
-
-const BlockEntry* Cluster::GetMaxKey(const VideoTrack* pTrack)
-{
- assert(pTrack);
-
- if (m_pSegment == NULL) //EOS
- return pTrack->GetEOS();
-
- LoadBlockEntries();
- //assert(m_entries);
-
- BlockEntry** i = m_entries + m_entriesCount;
- BlockEntry** const j = m_entries;
-
- while (i != j)
- {
- const BlockEntry* const pEntry = *--i;
- assert(pEntry);
- assert(!pEntry->EOS());
-
- const Block* const pBlock = pEntry->GetBlock();
- assert(pBlock);
-
- if (pBlock->GetTrackNumber() != pTrack->GetNumber())
- continue;
-
- if (pBlock->IsKey())
- return pEntry;
- }
-
- return pTrack->GetEOS(); //no satisfactory block found
-}
-
-
-
-BlockEntry::BlockEntry()
-{
-}
-
-
-BlockEntry::~BlockEntry()
-{
-}
-
-
-SimpleBlock::SimpleBlock(
- Cluster* pCluster,
- size_t idx,
- long long start,
- long long size) :
- m_pCluster(pCluster),
- m_index(idx),
- m_block(start, size, pCluster->m_pSegment->m_pReader)
-{
-}
-
-
-bool SimpleBlock::EOS() const
-{
- return false;
-}
-
-
-Cluster* SimpleBlock::GetCluster() const
-{
- return m_pCluster;
-}
-
-
-size_t SimpleBlock::GetIndex() const
-{
- return m_index;
-}
-
-
-const Block* SimpleBlock::GetBlock() const
-{
- return &m_block;
-}
-
-
-bool SimpleBlock::IsBFrame() const
-{
- return false;
-}
-
-
-BlockGroup::BlockGroup(
- Cluster* pCluster,
- size_t idx,
- long long start,
- long long size_) :
- m_pCluster(pCluster),
- m_index(idx),
- m_prevTimeCode(0),
- m_nextTimeCode(0),
- m_pBlock(NULL) //TODO: accept multiple blocks within a block group
-{
- IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader;
-
- long long pos = start;
- const long long stop = start + size_;
-
- bool bSimpleBlock = false;
- bool bReferenceBlock = false;
-
- while (pos < stop)
- {
- short t;
-
- if (Match(pReader, pos, 0x7B, t))
- {
- if (t < 0)
- m_prevTimeCode = t;
- else if (t > 0)
- m_nextTimeCode = t;
- else
- assert(false);
-
- bReferenceBlock = true;
- }
- else
- {
- long len;
- const long long id = ReadUInt(pReader, pos, len);
- assert(id >= 0); //TODO
- assert((pos + len) <= stop);
-
- pos += len; //consume ID
-
- const long long size = ReadUInt(pReader, pos, len);
- assert(size >= 0); //TODO
- assert((pos + len) <= stop);
-
- pos += len; //consume size
-
- switch (id)
- {
- case 0x23: //SimpleBlock ID
- bSimpleBlock = true;
- //YES, FALL THROUGH TO NEXT CASE
-
- case 0x21: //Block ID
- ParseBlock(pos, size);
- break;
-
- default:
- break;
- }
-
- pos += size; //consume payload
- assert(pos <= stop);
- }
- }
-
- assert(pos == stop);
- assert(m_pBlock);
-
- if (!bSimpleBlock)
- m_pBlock->SetKey(!bReferenceBlock);
-}
-
-
-BlockGroup::~BlockGroup()
-{
- delete m_pBlock;
-}
-
-
-void BlockGroup::ParseBlock(long long start, long long size)
-{
- IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader;
-
- Block* const pBlock = new Block(start, size, pReader);
- assert(pBlock); //TODO
-
- //TODO: the Matroska spec says you have multiple blocks within the
- //same block group, with blocks ranked by priority (the flag bits).
-
- assert(m_pBlock == NULL);
- m_pBlock = pBlock;
-}
-
-
-bool BlockGroup::EOS() const
-{
- return false;
-}
-
-
-Cluster* BlockGroup::GetCluster() const
-{
- return m_pCluster;
-}
-
-
-size_t BlockGroup::GetIndex() const
-{
- return m_index;
-}
-
-
-const Block* BlockGroup::GetBlock() const
-{
- return m_pBlock;
-}
-
-
-short BlockGroup::GetPrevTimeCode() const
-{
- return m_prevTimeCode;
-}
-
-
-short BlockGroup::GetNextTimeCode() const
-{
- return m_nextTimeCode;
-}
-
-
-bool BlockGroup::IsBFrame() const
-{
- return (m_nextTimeCode > 0);
-}
-
-
-
-Block::Block(long long start, long long size_, IMkvReader* pReader) :
- m_start(start),
- m_size(size_)
-{
- long long pos = start;
- const long long stop = start + size_;
-
- long len;
-
- m_track = ReadUInt(pReader, pos, len);
- assert(m_track > 0);
- assert((pos + len) <= stop);
-
- pos += len; //consume track number
- assert((stop - pos) >= 2);
-
- m_timecode = Unserialize2SInt(pReader, pos);
-
- pos += 2;
- assert((stop - pos) >= 1);
-
- const long hr = pReader->Read(pos, 1, &m_flags);
- assert(hr == 0L);
-
- ++pos;
- assert(pos <= stop);
-
- m_frameOff = pos;
-
- const long long frame_size = stop - pos;
-
- assert(frame_size <= 2147483647L);
-
- m_frameSize = static_cast<long>(frame_size);
-}
-
-
-long long Block::GetTimeCode(Cluster* pCluster) const
-{
- assert(pCluster);
-
- const long long tc0 = pCluster->GetTimeCode();
- assert(tc0 >= 0);
-
- const long long tc = tc0 + static_cast<long long>(m_timecode);
- assert(tc >= 0);
-
- return tc; //unscaled timecode units
-}
-
-
-long long Block::GetTime(Cluster* pCluster) const
-{
- assert(pCluster);
-
- const long long tc = GetTimeCode(pCluster);
-
- const Segment* const pSegment = pCluster->m_pSegment;
- const SegmentInfo* const pInfo = pSegment->GetInfo();
- assert(pInfo);
-
- const long long scale = pInfo->GetTimeCodeScale();
- assert(scale >= 1);
-
- const long long ns = tc * scale;
-
- return ns;
-}
-
-
-long long Block::GetTrackNumber() const
-{
- return m_track;
-}
-
-
-bool Block::IsKey() const
-{
- return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
-}
-
-unsigned char Block::Flags() const {
- return m_flags;
-}
-
-void Block::SetKey(bool bKey)
-{
- if (bKey)
- m_flags |= static_cast<unsigned char>(1 << 7);
- else
- m_flags &= 0x7F;
-}
-
-
-long long Block::GetOffset() const
-{
- return m_frameOff;
-}
-
-
-long Block::GetSize() const
-{
- return m_frameSize;
-}
-
-
-long Block::Read(IMkvReader* pReader, unsigned char* buf) const
-{
-
- assert(pReader);
- assert(buf);
-
- const long hr = pReader->Read(m_frameOff, m_frameSize, buf);
-
- return hr;
-}
-
-
-} //end namespace mkvparser
diff --git a/media/libstagefright/matroska/mkvparser.hpp b/media/libstagefright/matroska/mkvparser.hpp deleted file mode 100644 index f7d89483bca3..000000000000 --- a/media/libstagefright/matroska/mkvparser.hpp +++ /dev/null @@ -1,556 +0,0 @@ -// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-
-#ifndef MKVPARSER_HPP
-#define MKVPARSER_HPP
-
-#include <cstdlib>
-#include <cstdio>
-
-namespace mkvparser
-{
-
-const int E_FILE_FORMAT_INVALID = -2;
-const int E_BUFFER_NOT_FULL = -3;
-
-class IMkvReader
-{
-public:
- virtual int Read(long long pos, long len, unsigned char* buf) = 0;
- virtual int Length(long long* total, long long* available) = 0;
-protected:
- virtual ~IMkvReader();
-};
-
-long long GetUIntLength(IMkvReader*, long long, long&);
-long long ReadUInt(IMkvReader*, long long, long&);
-long long SyncReadUInt(IMkvReader*, long long pos, long long stop, long&);
-long long UnserializeUInt(IMkvReader*, long long pos, long long size);
-float Unserialize4Float(IMkvReader*, long long);
-double Unserialize8Double(IMkvReader*, long long);
-short Unserialize2SInt(IMkvReader*, long long);
-signed char Unserialize1SInt(IMkvReader*, long long);
-bool Match(IMkvReader*, long long&, unsigned long, long long&);
-bool Match(IMkvReader*, long long&, unsigned long, char*&);
-bool Match(IMkvReader*, long long&, unsigned long,unsigned char*&, size_t&);
-bool Match(IMkvReader*, long long&, unsigned long, double&);
-bool Match(IMkvReader*, long long&, unsigned long, short&);
-
-void GetVersion(int& major, int& minor, int& build, int& revision);
-
-struct EBMLHeader
-{
- EBMLHeader();
- ~EBMLHeader();
- long long m_version;
- long long m_readVersion;
- long long m_maxIdLength;
- long long m_maxSizeLength;
- char* m_docType;
- long long m_docTypeVersion;
- long long m_docTypeReadVersion;
-
- long long Parse(IMkvReader*, long long&);
-};
-
-
-class Segment;
-class Track;
-class Cluster;
-
-class Block
-{
- Block(const Block&);
- Block& operator=(const Block&);
-
-public:
- const long long m_start;
- const long long m_size;
-
- Block(long long start, long long size, IMkvReader*);
-
- long long GetTrackNumber() const;
- long long GetTimeCode(Cluster*) const; //absolute, but not scaled
- long long GetTime(Cluster*) const; //absolute, and scaled (ns units)
- bool IsKey() const;
- void SetKey(bool);
-
- unsigned char Flags() const;
-
- long long GetOffset() const;
- long GetSize() const;
- long Read(IMkvReader*, unsigned char*) const;
-
-private:
- long long m_track; //Track::Number()
- short m_timecode; //relative to cluster
- unsigned char m_flags;
- long long m_frameOff;
- long m_frameSize;
-
-};
-
-
-class BlockEntry
-{
- BlockEntry(const BlockEntry&);
- BlockEntry& operator=(const BlockEntry&);
-
-public:
- virtual ~BlockEntry();
- virtual bool EOS() const = 0;
- virtual Cluster* GetCluster() const = 0;
- virtual size_t GetIndex() const = 0;
- virtual const Block* GetBlock() const = 0;
- virtual bool IsBFrame() const = 0;
-
-protected:
- BlockEntry();
-
-};
-
-
-class SimpleBlock : public BlockEntry
-{
- SimpleBlock(const SimpleBlock&);
- SimpleBlock& operator=(const SimpleBlock&);
-
-public:
- SimpleBlock(Cluster*, size_t, long long start, long long size);
-
- bool EOS() const;
- Cluster* GetCluster() const;
- size_t GetIndex() const;
- const Block* GetBlock() const;
- bool IsBFrame() const;
-
-protected:
- Cluster* const m_pCluster;
- const size_t m_index;
- Block m_block;
-
-};
-
-
-class BlockGroup : public BlockEntry
-{
- BlockGroup(const BlockGroup&);
- BlockGroup& operator=(const BlockGroup&);
-
-public:
- BlockGroup(Cluster*, size_t, long long, long long);
- ~BlockGroup();
-
- bool EOS() const;
- Cluster* GetCluster() const;
- size_t GetIndex() const;
- const Block* GetBlock() const;
- bool IsBFrame() const;
-
- short GetPrevTimeCode() const; //relative to block's time
- short GetNextTimeCode() const; //as above
-
-protected:
- Cluster* const m_pCluster;
- const size_t m_index;
-
-private:
- BlockGroup(Cluster*, size_t, unsigned long);
- void ParseBlock(long long start, long long size);
-
- short m_prevTimeCode;
- short m_nextTimeCode;
-
- //TODO: the Matroska spec says you can have multiple blocks within the
- //same block group, with blocks ranked by priority (the flag bits).
- //For now we just cache a single block.
-#if 0
- typedef std::deque<Block*> blocks_t;
- blocks_t m_blocks; //In practice should contain only a single element.
-#else
- Block* m_pBlock;
-#endif
-
-};
-
-
-class Track
-{
- Track(const Track&);
- Track& operator=(const Track&);
-
-public:
- Segment* const m_pSegment;
- virtual ~Track();
-
- long long GetType() const;
- long long GetNumber() const;
- const char* GetNameAsUTF8() const;
- const char* GetCodecNameAsUTF8() const;
- const char* GetCodecId() const;
- const unsigned char* GetCodecPrivate(size_t&) const;
-
- const BlockEntry* GetEOS() const;
-
- struct Settings
- {
- long long start;
- long long size;
- };
-
- struct Info
- {
- long long type;
- long long number;
- long long uid;
- char* nameAsUTF8;
- char* codecId;
- unsigned char* codecPrivate;
- size_t codecPrivateSize;
- char* codecNameAsUTF8;
- Settings settings;
- Info();
- void Clear();
- };
-
- long GetFirst(const BlockEntry*&) const;
- long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const;
- virtual bool VetEntry(const BlockEntry*) const = 0;
-
-protected:
- Track(Segment*, const Info&);
- const Info m_info;
-
- class EOSBlock : public BlockEntry
- {
- public:
- EOSBlock();
-
- bool EOS() const;
- Cluster* GetCluster() const;
- size_t GetIndex() const;
- const Block* GetBlock() const;
- bool IsBFrame() const;
- };
-
- EOSBlock m_eos;
-
-};
-
-
-class VideoTrack : public Track
-{
- VideoTrack(const VideoTrack&);
- VideoTrack& operator=(const VideoTrack&);
-
-public:
- VideoTrack(Segment*, const Info&);
- long long GetWidth() const;
- long long GetHeight() const;
- double GetFrameRate() const;
-
- bool VetEntry(const BlockEntry*) const;
-
-private:
- long long m_width;
- long long m_height;
- double m_rate;
-
-};
-
-
-class AudioTrack : public Track
-{
- AudioTrack(const AudioTrack&);
- AudioTrack& operator=(const AudioTrack&);
-
-public:
- AudioTrack(Segment*, const Info&);
- double GetSamplingRate() const;
- long long GetChannels() const;
- long long GetBitDepth() const;
- bool VetEntry(const BlockEntry*) const;
-
-private:
- double m_rate;
- long long m_channels;
- long long m_bitDepth;
-};
-
-
-class Tracks
-{
- Tracks(const Tracks&);
- Tracks& operator=(const Tracks&);
-
-public:
- Segment* const m_pSegment;
- const long long m_start;
- const long long m_size;
-
- Tracks(Segment*, long long start, long long size);
- virtual ~Tracks();
-
- Track* GetTrackByNumber(unsigned long tn) const;
- Track* GetTrackByIndex(unsigned long idx) const;
-
-private:
- Track** m_trackEntries;
- Track** m_trackEntriesEnd;
-
- void ParseTrackEntry(long long, long long, Track*&);
-
-public:
- unsigned long GetTracksCount() const;
-};
-
-
-class SegmentInfo
-{
- SegmentInfo(const SegmentInfo&);
- SegmentInfo& operator=(const SegmentInfo&);
-
-public:
- Segment* const m_pSegment;
- const long long m_start;
- const long long m_size;
-
- SegmentInfo(Segment*, long long start, long long size);
- ~SegmentInfo();
- long long GetTimeCodeScale() const;
- long long GetDuration() const; //scaled
- const char* GetMuxingAppAsUTF8() const;
- const char* GetWritingAppAsUTF8() const;
- const char* GetTitleAsUTF8() const;
-
-private:
- long long m_timecodeScale;
- double m_duration;
- char* m_pMuxingAppAsUTF8;
- char* m_pWritingAppAsUTF8;
- char* m_pTitleAsUTF8;
-};
-
-class Cues;
-class CuePoint
-{
- friend class Cues;
-
- CuePoint(size_t, long long);
- ~CuePoint();
-
- CuePoint(const CuePoint&);
- CuePoint& operator=(const CuePoint&);
-
-public:
- void Load(IMkvReader*);
-
- long long GetTimeCode() const; //absolute but unscaled
- long long GetTime(Segment*) const; //absolute and scaled (ns units)
-
- struct TrackPosition
- {
- long long m_track;
- long long m_pos; //of cluster
- long long m_block;
- //codec_state //defaults to 0
- //reference = clusters containing req'd referenced blocks
- // reftime = timecode of the referenced block
-
- void Parse(IMkvReader*, long long, long long);
- };
-
- const TrackPosition* Find(const Track*) const;
-
-private:
- const size_t m_index;
- long long m_timecode;
- TrackPosition* m_track_positions;
- size_t m_track_positions_count;
-
-};
-
-
-class Cues
-{
- friend class Segment;
-
- Cues(Segment*, long long start, long long size);
- ~Cues();
-
- Cues(const Cues&);
- Cues& operator=(const Cues&);
-
-public:
- Segment* const m_pSegment;
- const long long m_start;
- const long long m_size;
-
- bool Find( //lower bound of time_ns
- long long time_ns,
- const Track*,
- const CuePoint*&,
- const CuePoint::TrackPosition*&) const;
-
-#if 0
- bool FindNext( //upper_bound of time_ns
- long long time_ns,
- const Track*,
- const CuePoint*&,
- const CuePoint::TrackPosition*&) const;
-#endif
-
- const CuePoint* GetFirst() const;
- const CuePoint* GetLast() const;
-
- const CuePoint* GetNext(const CuePoint*) const;
-
- const BlockEntry* GetBlock(
- const CuePoint*,
- const CuePoint::TrackPosition*) const;
-
-private:
- void Init() const;
- bool LoadCuePoint() const;
- void PreloadCuePoint(size_t&, long long) const;
-
- mutable CuePoint** m_cue_points;
- mutable size_t m_count;
- mutable size_t m_preload_count;
- mutable long long m_pos;
-
-};
-
-
-class Cluster
-{
- Cluster(const Cluster&);
- Cluster& operator=(const Cluster&);
-
-public:
- Segment* const m_pSegment;
-
-public:
- static Cluster* Parse(Segment*, long, long long off);
-
- Cluster(); //EndOfStream
- ~Cluster();
-
- bool EOS() const;
-
- long long GetTimeCode(); //absolute, but not scaled
- long long GetTime(); //absolute, and scaled (nanosecond units)
- long long GetFirstTime(); //time (ns) of first (earliest) block
- long long GetLastTime(); //time (ns) of last (latest) block
-
- const BlockEntry* GetFirst();
- const BlockEntry* GetLast();
- const BlockEntry* GetNext(const BlockEntry*) const;
- const BlockEntry* GetEntry(const Track*);
- const BlockEntry* GetEntry(
- const CuePoint&,
- const CuePoint::TrackPosition&);
- const BlockEntry* GetMaxKey(const VideoTrack*);
-
-protected:
- Cluster(Segment*, long, long long off);
-
-public:
- //TODO: these should all be private, with public selector functions
- long m_index;
- long long m_pos;
- long long m_size;
-
-private:
- long long m_timecode;
- BlockEntry** m_entries;
- size_t m_entriesCount;
-
- void Load();
- void LoadBlockEntries();
- void ParseBlockGroup(long long, long long, size_t);
- void ParseSimpleBlock(long long, long long, size_t);
-
-};
-
-
-class Segment
-{
- friend class Cues;
-
- Segment(const Segment&);
- Segment& operator=(const Segment&);
-
-private:
- Segment(IMkvReader*, long long pos, long long size);
-
-public:
- IMkvReader* const m_pReader;
- const long long m_start; //posn of segment payload
- const long long m_size; //size of segment payload
- Cluster m_eos; //TODO: make private?
-
- static long long CreateInstance(IMkvReader*, long long, Segment*&);
- ~Segment();
-
- long Load(); //loads headers and all clusters
-
- //for incremental loading (splitter)
- long long Unparsed() const;
- long long ParseHeaders(); //stops when first cluster is found
- long LoadCluster(); //loads one cluster
-
-#if 0
- //This pair parses one cluster, but only changes the state of the
- //segment object when the cluster is actually added to the index.
- long ParseCluster(Cluster*&, long long& newpos) const;
- bool AddCluster(Cluster*, long long);
-#endif
-
- Tracks* GetTracks() const;
- const SegmentInfo* GetInfo() const;
- const Cues* GetCues() const;
-
- long long GetDuration() const;
-
- unsigned long GetCount() const;
- Cluster* GetFirst();
- Cluster* GetLast();
- Cluster* GetNext(const Cluster*);
-
- Cluster* FindCluster(long long time_nanoseconds);
- const BlockEntry* Seek(long long time_nanoseconds, const Track*);
-
-private:
-
- long long m_pos; //absolute file posn; what has been consumed so far
- SegmentInfo* m_pInfo;
- Tracks* m_pTracks;
- Cues* m_pCues;
- Cluster** m_clusters;
- long m_clusterCount; //number of entries for which m_index >= 0
- long m_clusterPreloadCount; //number of entries for which m_index < 0
- long m_clusterSize; //array size
-
- void AppendCluster(Cluster*);
- void PreloadCluster(Cluster*, ptrdiff_t);
-
- void ParseSeekHead(long long pos, long long size);
- void ParseSeekEntry(long long pos, long long size);
- void ParseCues(long long);
-
- const BlockEntry* GetBlock(
- const CuePoint&,
- const CuePoint::TrackPosition&);
-
-};
-
-
-} //end namespace mkvparser
-
-#endif //MKVPARSER_HPP
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h index d08199533188..153cfe67fe98 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.h +++ b/media/libstagefright/mpeg2ts/ESQueue.h @@ -19,6 +19,7 @@ #define ES_QUEUE_H_ #include <media/stagefright/foundation/ABase.h> +#include <utils/Errors.h> #include <utils/List.h> #include <utils/RefBase.h> diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp index 679dcab7c057..6819fefd30cc 100644 --- a/media/libstagefright/rtsp/APacketSource.cpp +++ b/media/libstagefright/rtsp/APacketSource.cpp @@ -20,6 +20,7 @@ #include "APacketSource.h" +#include "ARawAudioAssembler.h" #include "ASessionDescription.h" #include "avc_utils.h" @@ -661,6 +662,8 @@ APacketSource::APacketSource( mFormat->setData( kKeyESDS, 0, codecSpecificData->data(), codecSpecificData->size()); + } else if (ARawAudioAssembler::Supports(desc.c_str())) { + ARawAudioAssembler::MakeFormat(desc.c_str(), mFormat); } else { mInitCheck = ERROR_UNSUPPORTED; } diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp index 84c666f08f64..3aa07cec4c44 100644 --- a/media/libstagefright/rtsp/ARTPSource.cpp +++ b/media/libstagefright/rtsp/ARTPSource.cpp @@ -25,6 +25,7 @@ #include "AH263Assembler.h" #include "AMPEG4AudioAssembler.h" #include "AMPEG4ElementaryAssembler.h" +#include "ARawAudioAssembler.h" #include "ASessionDescription.h" #include <media/stagefright/foundation/ABuffer.h> @@ -70,6 +71,8 @@ ARTPSource::ARTPSource( || !strncasecmp(desc.c_str(), "mpeg4-generic/", 14)) { mAssembler = new AMPEG4ElementaryAssembler(notify, desc, params); mIssueFIRRequests = true; + } else if (ARawAudioAssembler::Supports(desc.c_str())) { + mAssembler = new ARawAudioAssembler(notify, desc.c_str(), params); } else { TRESPASS(); } diff --git a/media/libstagefright/rtsp/ARawAudioAssembler.cpp b/media/libstagefright/rtsp/ARawAudioAssembler.cpp new file mode 100644 index 000000000000..dd47ea3d9068 --- /dev/null +++ b/media/libstagefright/rtsp/ARawAudioAssembler.cpp @@ -0,0 +1,143 @@ +/* + * 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "ARawAudioAssembler" +#include <utils/Log.h> + +#include "ARawAudioAssembler.h" + +#include "ARTPSource.h" +#include "ASessionDescription.h" + +#include <media/stagefright/foundation/ABuffer.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/foundation/hexdump.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/Utils.h> + +namespace android { + +ARawAudioAssembler::ARawAudioAssembler( + const sp<AMessage> ¬ify, const char *desc, const AString ¶ms) + : mNotifyMsg(notify), + mNextExpectedSeqNoValid(false), + mNextExpectedSeqNo(0) { +} + +ARawAudioAssembler::~ARawAudioAssembler() { +} + +ARTPAssembler::AssemblyStatus ARawAudioAssembler::assembleMore( + const sp<ARTPSource> &source) { + return addPacket(source); +} + +ARTPAssembler::AssemblyStatus ARawAudioAssembler::addPacket( + const sp<ARTPSource> &source) { + List<sp<ABuffer> > *queue = source->queue(); + + if (queue->empty()) { + return NOT_ENOUGH_DATA; + } + + if (mNextExpectedSeqNoValid) { + List<sp<ABuffer> >::iterator it = queue->begin(); + while (it != queue->end()) { + if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) { + break; + } + + it = queue->erase(it); + } + + if (queue->empty()) { + return NOT_ENOUGH_DATA; + } + } + + sp<ABuffer> buffer = *queue->begin(); + + if (!mNextExpectedSeqNoValid) { + mNextExpectedSeqNoValid = true; + mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); + } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { + LOGV("Not the sequence number I expected"); + + return WRONG_SEQUENCE_NUMBER; + } + + // hexdump(buffer->data(), buffer->size()); + + if (buffer->size() < 1) { + queue->erase(queue->begin()); + ++mNextExpectedSeqNo; + + LOGV("raw audio packet too short."); + + return MALFORMED_PACKET; + } + + sp<AMessage> msg = mNotifyMsg->dup(); + msg->setObject("access-unit", buffer); + msg->post(); + + queue->erase(queue->begin()); + ++mNextExpectedSeqNo; + + return OK; +} + +void ARawAudioAssembler::packetLost() { + CHECK(mNextExpectedSeqNoValid); + ++mNextExpectedSeqNo; +} + +void ARawAudioAssembler::onByeReceived() { + sp<AMessage> msg = mNotifyMsg->dup(); + msg->setInt32("eos", true); + msg->post(); +} + +// static +bool ARawAudioAssembler::Supports(const char *desc) { + return !strncmp(desc, "PCMU/", 5) + || !strncmp(desc, "PCMA/", 5); +} + +// static +void ARawAudioAssembler::MakeFormat( + const char *desc, const sp<MetaData> &format) { + if (!strncmp(desc, "PCMU/", 5)) { + format->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_MLAW); + } else if (!strncmp(desc, "PCMA/", 5)) { + format->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_ALAW); + } else { + TRESPASS(); + } + + int32_t sampleRate, numChannels; + ASessionDescription::ParseFormatDesc( + desc, &sampleRate, &numChannels); + + format->setInt32(kKeySampleRate, sampleRate); + format->setInt32(kKeyChannelCount, numChannels); +} + +} // namespace android + diff --git a/media/libstagefright/rtsp/ARawAudioAssembler.h b/media/libstagefright/rtsp/ARawAudioAssembler.h new file mode 100644 index 000000000000..ed7af080c575 --- /dev/null +++ b/media/libstagefright/rtsp/ARawAudioAssembler.h @@ -0,0 +1,60 @@ +/* + * 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 A_RAW_AUDIO_ASSEMBLER_H_ + +#define A_RAW_AUDIO_ASSEMBLER_H_ + +#include "ARTPAssembler.h" + +namespace android { + +struct AMessage; +struct AString; +struct MetaData; + +struct ARawAudioAssembler : public ARTPAssembler { + ARawAudioAssembler( + const sp<AMessage> ¬ify, + const char *desc, const AString ¶ms); + + static bool Supports(const char *desc); + + static void MakeFormat( + const char *desc, const sp<MetaData> &format); + +protected: + virtual ~ARawAudioAssembler(); + + virtual AssemblyStatus assembleMore(const sp<ARTPSource> &source); + virtual void onByeReceived(); + virtual void packetLost(); + +private: + bool mIsWide; + + sp<AMessage> mNotifyMsg; + bool mNextExpectedSeqNoValid; + uint32_t mNextExpectedSeqNo; + + AssemblyStatus addPacket(const sp<ARTPSource> &source); + + DISALLOW_EVIL_CONSTRUCTORS(ARawAudioAssembler); +}; + +} // namespace android + +#endif // A_RAW_AUDIO_ASSEMBLER_H_ diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk index fb42de8a01b4..8530ff323408 100644 --- a/media/libstagefright/rtsp/Android.mk +++ b/media/libstagefright/rtsp/Android.mk @@ -9,6 +9,7 @@ LOCAL_SRC_FILES:= \ AMPEG4AudioAssembler.cpp \ AMPEG4ElementaryAssembler.cpp \ APacketSource.cpp \ + ARawAudioAssembler.cpp \ ARTPAssembler.cpp \ ARTPConnection.cpp \ ARTPSource.cpp \ diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png Binary files differnew file mode 100644 index 000000000000..1aea61279908 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png Binary files differnew file mode 100644 index 000000000000..425535eb5d36 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_4g.png Binary files differnew file mode 100644 index 000000000000..fcad3632587d --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_4g.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png Binary files differnew file mode 100644 index 000000000000..4ff7db3b4e61 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_4g.png Binary files differnew file mode 100644 index 000000000000..2c4a07f0ef99 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_4g.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_4g.png Binary files differnew file mode 100644 index 000000000000..879c703f7b1f --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_4g.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inadnout_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inadnout_e.png Binary files differnew file mode 100644 index 000000000000..61a7503f2123 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inadnout_e.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_4g.png Binary files differnew file mode 100644 index 000000000000..c5edf2c19e3f --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_4g.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_4g.png Binary files differnew file mode 100644 index 000000000000..ddf88bedb964 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_4g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png Binary files differindex 78ece9e344f6..c77e61e2deaf 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png Binary files differindex 31fc1b023d00..b9f721aa0bf1 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png Binary files differnew file mode 100644 index 000000000000..cff969e25276 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png Binary files differindex 19adb4b02744..d2d7ab3dae12 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png Binary files differindex fd419ea4d64e..83ce6d09cb41 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png Binary files differindex 94e77ae79e8f..abe511f83c20 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png Binary files differindex 91328c0211c0..d685af8c10e3 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png Binary files differindex 2fee69248af9..8c697a18cf4f 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png Binary files differnew file mode 100644 index 000000000000..9a4b807e9b1e --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png Binary files differindex d0968aa19a5a..eb11d04d2e99 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png Binary files differindex 991228b06a21..6e54de0d4373 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png Binary files differindex ae03e3891a98..5bfb33b3a0b2 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png Binary files differindex 97b011e0bda4..119067b5dc2d 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png Binary files differindex a826866c3bdb..a70cc2ecaa08 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_4g.png Binary files differnew file mode 100644 index 000000000000..ea3dba76e6e8 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_4g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png Binary files differindex f6a68916921b..53221b99b767 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png Binary files differindex 19b98167e602..11d44d00f5bc 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png Binary files differindex f8c09614f216..9defd7919823 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png Binary files differindex 22deb701e357..136576d4a542 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png Binary files differindex c7c1b49227ed..26ca31fedf0e 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png Binary files differnew file mode 100644 index 000000000000..de8c5ee5bc58 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png Binary files differindex d9a0702c7952..64dbf3c60353 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png Binary files differindex 6beed8a1b7fa..34923fb98400 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png Binary files differindex e4179c13f2ff..506b5c61cd65 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png Binary files differindex 4b2f86d3b4a1..163976fd87ad 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png Binary files differindex 6779604782f6..a6af649bac56 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_4g.png Binary files differnew file mode 100644 index 000000000000..0c08e522f935 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_4g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png Binary files differindex 1309a9790ddc..1d02edbc8db4 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png Binary files differindex 2fc1e8ec2865..edc95360027d 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png Binary files differindex 0eef2c10c82c..8376817cd8e6 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png Binary files differindex f8904e2c3fb3..ecef547e84d5 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png Binary files differindex 3ef306e7db26..a7c48b6eaaff 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_4g.png Binary files differnew file mode 100644 index 000000000000..f4bcd9a18169 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_4g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png Binary files differindex 2ff6d90d3b54..b46bb3a65ba8 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png Binary files differindex 8ff49b0f3830..e8b70f298207 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png Binary files differindex f416203aeedc..4e23c4ebae67 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inadnout_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inadnout_e.png Binary files differnew file mode 100644 index 000000000000..ced91751c16e --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inadnout_e.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png Binary files differindex 24b7daacd561..92d4a19f9d52 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png Binary files differindex 5ea91427ef76..a208736046b4 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_4g.png Binary files differnew file mode 100644 index 000000000000..f407bc97ae0a --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_4g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png Binary files differindex 002bf46436f1..b8a65c239720 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png Binary files differindex 924b84f54a7c..a978b680285d 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png Binary files differindex bd0d1caaf772..710dd52e0e26 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png Binary files differindex f583eecac5fc..a7b35e4c2448 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_4g.png Binary files differnew file mode 100644 index 000000000000..bb0544919b0a --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_4g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png Binary files differindex 66940eaf40ea..a14422250d74 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png Binary files differindex 0381f52d4de0..b0eafb66ec1f 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png Binary files differindex 0b84fe8ccbd9..f6b83d0a0093 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index afb73a9033d8..60fb61d91602 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -668,7 +668,7 @@ public class TabletStatusBar extends StatusBar implements } public void updateNotification(IBinder key, StatusBarNotification notification) { - if (DEBUG) Slog.d(TAG, "updateNotification(" + key + " -> " + notification + ") // TODO"); + if (DEBUG) Slog.d(TAG, "updateNotification(" + key + " -> " + notification + ")"); final NotificationData.Entry oldEntry = mNotificationData.findByKey(key); if (oldEntry == null) { @@ -685,7 +685,8 @@ public class TabletStatusBar extends StatusBar implements Slog.d(TAG, "old notification: when=" + oldNotification.notification.when + " ongoing=" + oldNotification.isOngoing() + " expanded=" + oldEntry.expanded - + " contentView=" + oldContentView); + + " contentView=" + oldContentView + + " rowParent=" + oldEntry.row.getParent()); Slog.d(TAG, "new notification: when=" + notification.notification.when + " ongoing=" + oldNotification.isOngoing() + " contentView=" + contentView); @@ -806,16 +807,17 @@ public class TabletStatusBar extends StatusBar implements } } if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { + mNotificationDNDMode = Prefs.read(mContext) + .getBoolean(Prefs.DO_NOT_DISTURB_PREF, Prefs.DO_NOT_DISTURB_DEFAULT); + if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { - Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: yes"); + Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: yes" + (mNotificationDNDMode?" (DND)":"")); mTicker.halt(); } else { - Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: no"); + Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: no" + (mNotificationDNDMode?" (DND)":"")); } + // refresh icons to show either notifications or the DND message - mNotificationDNDMode = Prefs.read(mContext) - .getBoolean(Prefs.DO_NOT_DISTURB_PREF, Prefs.DO_NOT_DISTURB_DEFAULT); - Slog.d(TAG, "DND: " + mNotificationDNDMode); reloadAllNotificationIcons(); } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { if ((state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { @@ -1241,29 +1243,34 @@ public class TabletStatusBar extends StatusBar implements if (mIconLayout == null) return; + // first, populate the main notification panel + loadNotificationPanel(); + final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight); // alternate behavior in DND mode - if (mNotificationDNDMode && mIconLayout.getChildCount() == 0) { - final StatusBarIconView iconView = new StatusBarIconView(mContext, "_dnd"); - iconView.setImageResource(R.drawable.ic_notification_dnd); - iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - iconView.setPadding(mIconHPadding, 0, mIconHPadding, 0); - - final Notification dndNotification = new Notification.Builder(mContext) - .setContentTitle(mContext.getText(R.string.notifications_off_title)) - .setContentText(mContext.getText(R.string.notifications_off_text)) - .setSmallIcon(R.drawable.ic_notification_dnd) - .setOngoing(true) - .getNotification(); - - mNotificationDNDDummyEntry = new NotificationData.Entry( - null, - new StatusBarNotification("", 0, "", 0, 0, dndNotification), - iconView); - - mIconLayout.addView(iconView, params); + if (mNotificationDNDMode) { + if (mIconLayout.getChildCount() == 0) { + final StatusBarIconView iconView = new StatusBarIconView(mContext, "_dnd"); + iconView.setImageResource(R.drawable.ic_notification_dnd); + iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + iconView.setPadding(mIconHPadding, 0, mIconHPadding, 0); + + final Notification dndNotification = new Notification.Builder(mContext) + .setContentTitle(mContext.getText(R.string.notifications_off_title)) + .setContentText(mContext.getText(R.string.notifications_off_text)) + .setSmallIcon(R.drawable.ic_notification_dnd) + .setOngoing(true) + .getNotification(); + + mNotificationDNDDummyEntry = new NotificationData.Entry( + null, + new StatusBarNotification("", 0, "", 0, 0, dndNotification), + iconView); + + mIconLayout.addView(iconView, params); + } return; } @@ -1305,8 +1312,6 @@ public class TabletStatusBar extends StatusBar implements mIconLayout.addView(v, i, params); } } - - loadNotificationPanel(); } private void loadNotificationPanel() { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 84588b78c2a8..f6649fd74af1 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1448,7 +1448,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON)); if (shortcutIntent != null) { shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(shortcutIntent); + try { + mContext.startActivity(shortcutIntent); + } catch (ActivityNotFoundException ex) { + Slog.w(TAG, "Dropping shortcut key combination because " + + "the activity to which it is registered was not found: " + + "META+" + KeyEvent.keyCodeToString(keyCode), ex); + } return null; } } @@ -2564,6 +2570,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private int getCurrentLandscapeRotation(int lastRotation) { + // if the user has locked rotation, we ignore the sensor + if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) { + if (isLandscapeOrSeascape(mUserRotation)) { + return mUserRotation; + } else { + // it seems odd to obey the sensor at all if rotation lock is enabled + return mLandscapeRotation; + } + } + int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation); if (isLandscapeOrSeascape(sensorRotation)) { return sensorRotation; @@ -2581,6 +2597,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private int getCurrentPortraitRotation(int lastRotation) { + // if the user has locked rotation, we ignore the sensor + if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) { + if (isAnyPortrait(mUserRotation)) { + return mUserRotation; + } else { + // it seems odd to obey the sensor at all if rotation lock is enabled + return mPortraitRotation; + } + } + int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation); if (isAnyPortrait(sensorRotation)) { return sensorRotation; diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 3d8ca7a3da13..a09e16b3b412 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -727,17 +727,30 @@ status_t CameraService::Client::cancelAutoFocus() { } // take a picture - image is returned in callback -status_t CameraService::Client::takePicture() { - LOG1("takePicture (pid %d)", getCallingPid()); +status_t CameraService::Client::takePicture(int msgType) { + LOG1("takePicture (pid %d): 0x%x", getCallingPid(), msgType); Mutex::Autolock lock(mLock); status_t result = checkPidAndHardware(); if (result != NO_ERROR) return result; - enableMsgType(CAMERA_MSG_SHUTTER | - CAMERA_MSG_POSTVIEW_FRAME | - CAMERA_MSG_RAW_IMAGE | - CAMERA_MSG_COMPRESSED_IMAGE); + if ((msgType & CAMERA_MSG_RAW_IMAGE) && + (msgType & CAMERA_MSG_RAW_IMAGE_NOTIFY)) { + LOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY" + " cannot be both enabled"); + return BAD_VALUE; + } + + // We only accept picture related message types + // and ignore other types of messages for takePicture(). + int picMsgType = msgType + & (CAMERA_MSG_SHUTTER | + CAMERA_MSG_POSTVIEW_FRAME | + CAMERA_MSG_RAW_IMAGE | + CAMERA_MSG_RAW_IMAGE_NOTIFY | + CAMERA_MSG_COMPRESSED_IMAGE); + + enableMsgType(picMsgType); return mHardware->takePicture(); } diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index ccb9cf7082cc..1c43b00f7ff1 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -108,7 +108,7 @@ private: virtual void releaseRecordingFrame(const sp<IMemory>& mem); virtual status_t autoFocus(); virtual status_t cancelAutoFocus(); - virtual status_t takePicture(); + virtual status_t takePicture(int msgType); virtual status_t setParameters(const String8& params); virtual String8 getParameters() const; virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2); diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index ef984d41cf17..2e3f0bdc9ff7 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -3211,14 +3211,52 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( // be used as modifiers) but it will ensure that fallback keys do not // get stuck. This takes care of the case where the application does not handle // the original DOWN so we generate a fallback DOWN but it does handle - // the original UP in which case we would not generate the fallback UP. + // the original UP in which case we want to send a fallback CANCEL. synthesizeCancelationEventsForConnectionLocked(connection, InputState::CANCEL_FALLBACK_EVENTS, - "application handled a non-fallback event, canceling all fallback events"); + "application handled a non-fallback event, " + "canceling all fallback events"); + connection->originalKeyCodeForFallback = -1; } else { - // If the application did not handle a non-fallback key, then ask - // the policy what to do with it. We might generate a fallback key - // event here. + // If the application did not handle a non-fallback key, first check + // that we are in a good state to handle the fallback key. Then ask + // the policy what to do with it. + if (connection->originalKeyCodeForFallback < 0) { + if (keyEntry->action != AKEY_EVENT_ACTION_DOWN + || keyEntry->repeatCount != 0) { +#if DEBUG_OUTBOUND_EVENT_DETAILS + LOGD("Unhandled key event: Skipping fallback since this " + "is not an initial down. " + "keyCode=%d, action=%d, repeatCount=%d", + keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount); +#endif + goto SkipFallback; + } + + // Start handling the fallback key on DOWN. + connection->originalKeyCodeForFallback = keyEntry->keyCode; + } else { + if (keyEntry->keyCode != connection->originalKeyCodeForFallback) { +#if DEBUG_OUTBOUND_EVENT_DETAILS + LOGD("Unhandled key event: Skipping fallback since there is " + "already a different fallback in progress. " + "keyCode=%d, originalKeyCodeForFallback=%d", + keyEntry->keyCode, connection->originalKeyCodeForFallback); +#endif + goto SkipFallback; + } + + // Finish handling the fallback key on UP. + if (keyEntry->action == AKEY_EVENT_ACTION_UP) { + connection->originalKeyCodeForFallback = -1; + } + } + +#if DEBUG_OUTBOUND_EVENT_DETAILS + LOGD("Unhandled key event: Asking policy to perform fallback action. " + "keyCode=%d, action=%d, repeatCount=%d", + keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount); +#endif KeyEvent event; initializeKeyEvent(&event, keyEntry); @@ -3248,6 +3286,12 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( keyEntry->downTime = event.getDownTime(); keyEntry->syntheticRepeat = false; +#if DEBUG_OUTBOUND_EVENT_DETAILS + LOGD("Unhandled key event: Dispatching fallback key. " + "fallbackKeyCode=%d, fallbackMetaState=%08x", + keyEntry->keyCode, keyEntry->metaState); +#endif + dispatchEntry->inProgress = false; startDispatchCycleLocked(now(), connection); return; @@ -3257,6 +3301,7 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( } } +SkipFallback: startNextDispatchCycleLocked(now(), connection); } @@ -3715,7 +3760,8 @@ InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle) : status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle), inputPublisher(inputChannel), - lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) { + lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX), + originalKeyCodeForFallback(-1) { } InputDispatcher::Connection::~Connection() { diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index 7abe0140f445..304b1bbd92d5 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -682,6 +682,7 @@ private: nsecs_t lastEventTime; // the time when the event was originally captured nsecs_t lastDispatchTime; // the time when the last event was dispatched + int32_t originalKeyCodeForFallback; // original keycode for fallback in progress, -1 if none explicit Connection(const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle); diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index e54e2152f1b6..7af60c5da45a 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -4765,7 +4765,7 @@ class PackageManagerService extends IPackageManager.Stub { final File externalMediaDir = Environment .getExternalStorageAppMediaDirectory(mStats.packageName); mStats.externalMediaSize = mContainerService - .calculateDirectorySize(externalCacheDir.getPath()); + .calculateDirectorySize(externalMediaDir.getPath()); final File externalObbDir = Environment .getExternalStorageAppObbDirectory(mStats.packageName); diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index cc25e8d09996..f9b94a309f25 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -96,6 +96,9 @@ public class WifiService extends IWifiManager.Stub { private boolean mDeviceIdle; private int mPluggedType; + /* Chipset supports background scan */ + private final boolean mBackgroundScanSupported; + // true if the user enabled Wifi while in airplane mode private AtomicBoolean mAirplaneModeOverwridden = new AtomicBoolean(false); @@ -369,6 +372,9 @@ public class WifiService extends IWifiManager.Stub { Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l; mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler()); mNotificationEnabledSettingObserver.register(); + + mBackgroundScanSupported = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_wifi_background_scan_support); } /** @@ -900,6 +906,9 @@ public class WifiService extends IWifiManager.Stub { reportStartWorkSource(); evaluateTrafficStatsPolling(); mWifiStateMachine.enableRssiPolling(true); + if (mBackgroundScanSupported) { + mWifiStateMachine.enableBackgroundScan(false); + } mWifiStateMachine.enableAllNetworks(); updateWifiState(); } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { @@ -909,6 +918,9 @@ public class WifiService extends IWifiManager.Stub { mScreenOff = true; evaluateTrafficStatsPolling(); mWifiStateMachine.enableRssiPolling(false); + if (mBackgroundScanSupported) { + mWifiStateMachine.enableBackgroundScan(true); + } /* * Set a timer to put Wi-Fi to sleep, but only if the screen is off * AND the "stay on while plugged in" setting doesn't match the diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 0f7d6392e496..57af001fabc8 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -341,6 +341,45 @@ void Layer::onDraw(const Region& clip) const drawWithOpenGL(clip, tex); } +// As documented in libhardware header, formats in the range +// 0x100 - 0x1FF are specific to the HAL implementation, and +// are known to have no alpha channel +// TODO: move definition for device-specific range into +// hardware.h, instead of using hard-coded values here. +#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF) + +bool Layer::needsBlending(const sp<GraphicBuffer>& buffer) const +{ + // If buffers where set with eOpaque flag, all buffers are known to + // be opaque without having to check their actual format + if (mNeedsBlending && buffer != NULL) { + PixelFormat format = buffer->getPixelFormat(); + + if (HARDWARE_IS_DEVICE_FORMAT(format)) { + return false; + } + + PixelFormatInfo info; + status_t err = getPixelFormatInfo(format, &info); + if (!err && info.h_alpha <= info.l_alpha) { + return false; + } + } + + // Return opacity as determined from flags and format options + // passed to setBuffers() + return mNeedsBlending; +} + +bool Layer::needsBlending() const +{ + if (mBufferManager.hasActiveBuffer()) { + return needsBlending(mBufferManager.getActiveBuffer()); + } + + return mNeedsBlending; +} + bool Layer::needsFiltering() const { if (!(mFlags & DisplayHardware::SLOW_CONFIG)) { @@ -588,6 +627,9 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) // we retired a buffer, which becomes the new front buffer const bool noActiveBuffer = !mBufferManager.hasActiveBuffer(); + const bool activeBlending = + noActiveBuffer ? true : needsBlending(mBufferManager.getActiveBuffer()); + if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) { LOGE("retireAndLock() buffer index (%d) out of range", int(buf)); mPostedDirtyRegion.clear(); @@ -602,6 +644,12 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) sp<GraphicBuffer> newFrontBuffer(getBuffer(buf)); if (newFrontBuffer != NULL) { + if (!noActiveBuffer && activeBlending != needsBlending(newFrontBuffer)) { + // new buffer has different opacity than previous active buffer, need + // to recompute visible regions accordingly + recomputeVisibleRegions = true; + } + // get the dirty region // compute the posted region const Region dirty(lcblk->getDirtyRegion(buf)); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 2b3841466d70..bccc9004fd99 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -75,7 +75,8 @@ public: virtual uint32_t doTransaction(uint32_t transactionFlags); virtual void lockPageFlip(bool& recomputeVisibleRegions); virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); - virtual bool needsBlending() const { return mNeedsBlending; } + virtual bool needsBlending(const sp<GraphicBuffer>& buffer) const; + virtual bool needsBlending() const; virtual bool needsDithering() const { return mNeedsDithering; } virtual bool needsFiltering() const; virtual bool isSecure() const { return mSecure; } diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java index 21e9e44ddee1..ad21a18adc5b 100644 --- a/telephony/java/com/android/internal/telephony/CommandsInterface.java +++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java @@ -1178,6 +1178,21 @@ public interface CommandsInterface { Message response); /** + * (AsyncResult)response.obj).result will be an Integer representing + * the sum of enabled service classes (sum of SERVICE_CLASS_*) for the + * application with appId. + * + * @param facility one of CB_FACILTY_* + * @param password password or "" if not required + * @param serviceClass is a sum of SERVICE_CLASS_* + * @param appId is application Id or null if none + * @param response is callback message + */ + + void queryFacilityLockForApp(String facility, String password, int serviceClass, String appId, + Message response); + + /** * @param facility one of CB_FACILTY_* * @param lockState true means lock, false means unlock * @param password password or "" if not required @@ -1187,6 +1202,18 @@ public interface CommandsInterface { void setFacilityLock (String facility, boolean lockState, String password, int serviceClass, Message response); + /** + * Set the facility lock for the app with this AID on the ICC card. + * + * @param facility one of CB_FACILTY_* + * @param lockState true means lock, false means unlock + * @param password password or "" if not required + * @param serviceClass is a sum of SERVICE_CLASS_* + * @param appId is application Id or null if none + * @param response is callback message + */ + void setFacilityLockForApp(String facility, boolean lockState, String password, + int serviceClass, String appId, Message response); void sendUSSD (String ussdString, Message response); diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index 76c6229b017d..bccb2194e318 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -1643,27 +1643,44 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } + @Override public void - queryFacilityLock (String facility, String password, int serviceClass, + queryFacilityLock(String facility, String password, int serviceClass, + Message response) { + queryFacilityLockForApp(facility, password, serviceClass, null, response); + } + + @Override + public void + queryFacilityLockForApp(String facility, String password, int serviceClass, String appId, Message response) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_FACILITY_LOCK, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); // count strings - rr.mp.writeInt(3); + rr.mp.writeInt(4); rr.mp.writeString(facility); rr.mp.writeString(password); rr.mp.writeString(Integer.toString(serviceClass)); + rr.mp.writeString(appId); send(rr); } + @Override public void setFacilityLock (String facility, boolean lockState, String password, int serviceClass, Message response) { + setFacilityLockForApp(facility, lockState, password, serviceClass, null, response); + } + + @Override + public void + setFacilityLockForApp(String facility, boolean lockState, String password, + int serviceClass, String appId, Message response) { String lockString; RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_FACILITY_LOCK, response); @@ -1671,13 +1688,14 @@ public final class RIL extends BaseCommands implements CommandsInterface { if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); // count strings - rr.mp.writeInt(4); + rr.mp.writeInt(5); rr.mp.writeString(facility); lockString = (lockState)?"1":"0"; rr.mp.writeString(lockString); rr.mp.writeString(password); rr.mp.writeString(Integer.toString(serviceClass)); + rr.mp.writeString(appId); send(rr); diff --git a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java index b6c3b67a134c..f2ece7fc6234 100644 --- a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java +++ b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java @@ -251,14 +251,26 @@ class SipCommandInterface extends BaseCommands implements CommandsInterface { public void getBasebandVersion (Message response) { } - public void queryFacilityLock (String facility, String password, + @Override + public void queryFacilityLock(String facility, String password, int serviceClass, Message response) { } - public void setFacilityLock (String facility, boolean lockState, + @Override + public void queryFacilityLockForApp(String facility, String password, + int serviceClass, String appId, Message response) { + } + + @Override + public void setFacilityLock(String facility, boolean lockState, String password, int serviceClass, Message response) { } + @Override + public void setFacilityLockForApp(String facility, boolean lockState, + String password, int serviceClass, String appId, Message response) { + } + public void sendUSSD (String ussdString, Message response) { } diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java index 242d44fc6aa3..d9bd7e876189 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java @@ -331,35 +331,31 @@ public final class SimulatedCommands extends BaseCommands mSsnNotifyOn = enable; } - /** - * (AsyncResult)response.obj).result will be an Integer representing - * the sum of enabled service classes (sum of SERVICE_CLASS_*) - * - * @param facility one of CB_FACILTY_* - * @param pin password or "" if not required - * @param serviceClass is a sum of SERVICE_CLASS_* - */ - - public void queryFacilityLock (String facility, String pin, + @Override + public void queryFacilityLock(String facility, String pin, int serviceClass, Message result) { - if (facility != null && - facility.equals(CommandsInterface.CB_FACILITY_BA_SIM)) { + queryFacilityLockForApp(facility, pin, serviceClass, null, result); + } + + @Override + public void queryFacilityLockForApp(String facility, String pin, int serviceClass, + String appId, Message result) { + if (facility != null && facility.equals(CommandsInterface.CB_FACILITY_BA_SIM)) { if (result != null) { int[] r = new int[1]; r[0] = (mSimLockEnabled ? 1 : 0); - Log.i(LOG_TAG, "[SimCmd] queryFacilityLock: SIM is " + - (r[0] == 0 ? "unlocked" : "locked")); + Log.i(LOG_TAG, "[SimCmd] queryFacilityLock: SIM is " + + (r[0] == 0 ? "unlocked" : "locked")); AsyncResult.forMessage(result, r, null); result.sendToTarget(); } return; - } else if (facility != null && - facility.equals(CommandsInterface.CB_FACILITY_BA_FD)) { + } else if (facility != null && facility.equals(CommandsInterface.CB_FACILITY_BA_FD)) { if (result != null) { int[] r = new int[1]; r[0] = (mSimFdnEnabled ? 1 : 0); - Log.i(LOG_TAG, "[SimCmd] queryFacilityLock: FDN is " + - (r[0] == 0 ? "disabled" : "enabled")); + Log.i(LOG_TAG, "[SimCmd] queryFacilityLock: FDN is " + + (r[0] == 0 ? "disabled" : "enabled")); AsyncResult.forMessage(result, r, null); result.sendToTarget(); } @@ -369,14 +365,15 @@ public final class SimulatedCommands extends BaseCommands unimplemented(result); } - /** - * @param facility one of CB_FACILTY_* - * @param lockEnabled true if SIM lock is enabled - * @param pin the SIM pin or "" if not required - * @param serviceClass is a sum of SERVICE_CLASS_* - */ - public void setFacilityLock (String facility, boolean lockEnabled, - String pin, int serviceClass, + @Override + public void setFacilityLock(String facility, boolean lockEnabled, String pin, int serviceClass, + Message result) { + setFacilityLockForApp(facility, lockEnabled, pin, serviceClass, null, result); + } + + @Override + public void setFacilityLockForApp(String facility, boolean lockEnabled, + String pin, int serviceClass, String appId, Message result) { if (facility != null && facility.equals(CommandsInterface.CB_FACILITY_BA_SIM)) { diff --git a/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml b/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml index 5211b0a9b6e0..d3c492eacf43 100644 --- a/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml +++ b/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml @@ -9,5 +9,7 @@ android:layout_width="wrap_content"/> <ImageView android:layout_height="wrap_content" - android:layout_width="wrap_content"/> + android:layout_width="wrap_content" + android:layout_marginLeft="3dip" + android:layout_marginRight="5dip"/> </merge> diff --git a/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java index e1934774f672..a50a2bd039f5 100644 --- a/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java @@ -63,7 +63,7 @@ public class AvoidXfermode_Delegate extends Xfermode_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(int opColor, int tolerance, int nativeMode) { AvoidXfermode_Delegate newDelegate = new AvoidXfermode_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java index c6fde7be289b..9a8cf0462131 100644 --- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java @@ -76,7 +76,7 @@ public class BitmapShader_Delegate extends Shader_Delegate { bitmap.getImage(), Shader_Delegate.getTileMode(shaderTileModeX), Shader_Delegate.getTileMode(shaderTileModeY)); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java index 0c8776628646..b6d5725ab07b 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java @@ -245,12 +245,12 @@ public final class Bitmap_Delegate { @LayoutlibDelegate /*package*/ static void nativeDestructor(int nativeBitmap) { - sManager.removeDelegate(nativeBitmap); + sManager.removeJavaReferenceFor(nativeBitmap); } @LayoutlibDelegate /*package*/ static void nativeRecycle(int nativeBitmap) { - sManager.removeDelegate(nativeBitmap); + sManager.removeJavaReferenceFor(nativeBitmap); } @LayoutlibDelegate @@ -522,7 +522,7 @@ public final class Bitmap_Delegate { private static Bitmap createBitmap(Bitmap_Delegate delegate, boolean isMutable, int density) { // get its native_int - int nativeInt = sManager.addDelegate(delegate); + int nativeInt = sManager.addNewDelegate(delegate); // and create/return a new Bitmap with it return new Bitmap(nativeInt, null /* buffer */, isMutable, null /*ninePatchChunk*/, density); diff --git a/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java index 92d0d0af5d3f..4becba130127 100644 --- a/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java @@ -57,7 +57,7 @@ public class BlurMaskFilter_Delegate extends MaskFilter_Delegate { @LayoutlibDelegate /*package*/ static int nativeConstructor(float radius, int style) { BlurMaskFilter_Delegate newDelegate = new BlurMaskFilter_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index e8a99b5d6711..f0e727febe96 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -64,7 +64,7 @@ public final class Canvas_Delegate { private Bitmap_Delegate mBitmap; private GcSnapshot mSnapshot; - private int mDrawFilter = 0; + private DrawFilter_Delegate mDrawFilter = null; // ---- Public Helper methods ---- @@ -95,7 +95,7 @@ public final class Canvas_Delegate { * @return the delegate or null. */ public DrawFilter_Delegate getDrawFilter() { - return DrawFilter_Delegate.getDelegate(mDrawFilter); + return mDrawFilter; } // ---- native methods ---- @@ -313,12 +313,12 @@ public final class Canvas_Delegate { // create a new Canvas_Delegate with the given bitmap and return its new native int. Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } else { // create a new Canvas_Delegate and return its new native int. Canvas_Delegate newDelegate = new Canvas_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } } @@ -510,26 +510,18 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - /*package*/ static void nativeSetDrawFilter(int nativeCanvas, - int nativeFilter) { + /*package*/ static void nativeSetDrawFilter(int nativeCanvas, int nativeFilter) { Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); if (canvasDelegate == null) { return; } - canvasDelegate.mDrawFilter = nativeFilter; + canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter); - // get the delegate only because we don't support them at all for the moment, so - // we can display the message now. - - DrawFilter_Delegate filterDelegate = DrawFilter_Delegate.getDelegate(nativeFilter); - if (canvasDelegate == null) { - return; - } - - if (filterDelegate.isSupported() == false) { + if (canvasDelegate.mDrawFilter != null && + canvasDelegate.mDrawFilter.isSupported() == false) { Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER, - filterDelegate.getSupportMessage(), null, null /*data*/); + canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/); } } @@ -956,7 +948,7 @@ public final class Canvas_Delegate { draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, new GcSnapshot.Drawable() { public void draw(Graphics2D graphics, Paint_Delegate paint) { - // WARNING: the logic in this method is similar to Paint.measureText. + // WARNING: the logic in this method is similar to Paint_Delegate.measureText. // Any change to this method should be reflected in Paint.measureText // Paint.TextAlign indicates how the text is positioned relative to X. // LEFT is the default and there's nothing to do. @@ -1139,7 +1131,7 @@ public final class Canvas_Delegate { canvasDelegate.dispose(); // remove it from the manager. - sManager.removeDelegate(nativeCanvas); + sManager.removeJavaReferenceFor(nativeCanvas); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java index 789c6e6904bf..e786eb587b1d 100644 --- a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java @@ -57,7 +57,7 @@ public abstract class ColorFilter_Delegate { @LayoutlibDelegate /*package*/ static void finalizer(int native_instance, int nativeColorFilter) { - sManager.removeDelegate(native_instance); + sManager.removeJavaReferenceFor(native_instance); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java index 462b1e640725..2de344b41f8a 100644 --- a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java @@ -57,7 +57,7 @@ public class ColorMatrixColorFilter_Delegate extends ColorFilter_Delegate { @LayoutlibDelegate /*package*/ static int nativeColorMatrixFilter(float[] array) { ColorMatrixColorFilter_Delegate newDelegate = new ColorMatrixColorFilter_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java index 2bdaa5bdbf5c..7c04a8709db2 100644 --- a/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java @@ -64,7 +64,7 @@ public class ComposePathEffect_Delegate extends PathEffect_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(int outerpe, int innerpe) { ComposePathEffect_Delegate newDelegate = new ComposePathEffect_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java index a2ecb8f6a1a6..f6e1d0094925 100644 --- a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java @@ -67,7 +67,7 @@ public class ComposeShader_Delegate extends Shader_Delegate { int native_mode) { // FIXME not supported yet. ComposeShader_Delegate newDelegate = new ComposeShader_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -75,7 +75,7 @@ public class ComposeShader_Delegate extends Shader_Delegate { int porterDuffMode) { // FIXME not supported yet. ComposeShader_Delegate newDelegate = new ComposeShader_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java index c677de83ba7f..b0f8168aa3a0 100644 --- a/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java @@ -64,7 +64,7 @@ public class CornerPathEffect_Delegate extends PathEffect_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(float radius) { CornerPathEffect_Delegate newDelegate = new CornerPathEffect_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java index 12a4d4a348d9..d97c2eccd508 100644 --- a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java @@ -75,7 +75,7 @@ public final class DashPathEffect_Delegate extends PathEffect_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(float intervals[], float phase) { DashPathEffect_Delegate newDelegate = new DashPathEffect_Delegate(intervals, phase); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java index ac6971284583..ec4a810fbda5 100644 --- a/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java @@ -64,7 +64,7 @@ public class DiscretePathEffect_Delegate extends PathEffect_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(float length, float deviation) { DiscretePathEffect_Delegate newDelegate = new DiscretePathEffect_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java index a98f0a941090..37c7359b5814 100644 --- a/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java @@ -57,7 +57,7 @@ public abstract class DrawFilter_Delegate { @LayoutlibDelegate /*package*/ static void nativeDestructor(int nativeDrawFilter) { - sManager.removeDelegate(nativeDrawFilter); + sManager.removeJavaReferenceFor(nativeDrawFilter); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java index 31f8bbfb1f8e..ebc1c1d2eca4 100644 --- a/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java @@ -58,7 +58,7 @@ public class EmbossMaskFilter_Delegate extends MaskFilter_Delegate { /*package*/ static int nativeConstructor(float[] direction, float ambient, float specular, float blurRadius) { EmbossMaskFilter_Delegate newDelegate = new EmbossMaskFilter_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java index fcb62a8a9592..51e0576169c4 100644 --- a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java @@ -57,7 +57,7 @@ public class LayerRasterizer_Delegate extends Rasterizer_Delegate { @LayoutlibDelegate /*package*/ static int nativeConstructor() { LayerRasterizer_Delegate newDelegate = new LayerRasterizer_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java index b2725343b791..0ee883dcd68c 100644 --- a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java @@ -57,7 +57,7 @@ public class LightingColorFilter_Delegate extends ColorFilter_Delegate { @LayoutlibDelegate /*package*/ static int native_CreateLightingFilter(int mul, int add) { LightingColorFilter_Delegate newDelegate = new LightingColorFilter_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java index 80605779fcf9..a2ba758a7e0c 100644 --- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java @@ -59,7 +59,7 @@ public final class LinearGradient_Delegate extends Gradient_Delegate { int colors[], float positions[], int tileMode) { LinearGradient_Delegate newDelegate = new LinearGradient_Delegate(x0, y0, x1, y1, colors, positions, Shader_Delegate.getTileMode(tileMode)); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java index 4adca276a7d8..5a6167dc6a3d 100644 --- a/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java @@ -57,7 +57,7 @@ public abstract class MaskFilter_Delegate { @LayoutlibDelegate /*package*/ static void nativeDestructor(int native_filter) { - sManager.removeDelegate(native_filter); + sManager.removeJavaReferenceFor(native_filter); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java index 68a476f170ef..251aa16ba48b 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java @@ -189,7 +189,7 @@ public final class Matrix_Delegate { } } - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -765,7 +765,7 @@ public final class Matrix_Delegate { @LayoutlibDelegate /*package*/ static void finalizer(int native_instance) { - sManager.removeDelegate(native_instance); + sManager.removeJavaReferenceFor(native_instance); } // ---- Private helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java index dfcb5916b8cc..71d346a93553 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java @@ -57,7 +57,7 @@ public class PaintFlagsDrawFilter_Delegate extends DrawFilter_Delegate { @LayoutlibDelegate /*package*/ static int nativeConstructor(int clearBits, int setBits) { PaintFlagsDrawFilter_Delegate newDelegate = new PaintFlagsDrawFilter_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java index f5d2547799d8..51b3efe12cd7 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -32,6 +32,7 @@ import java.awt.Stroke; import java.awt.Toolkit; import java.awt.font.FontRenderContext; import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -75,19 +76,19 @@ public class Paint_Delegate { private int mCap; private int mJoin; private int mTextAlign; - private int mTypeface; + private Typeface_Delegate mTypeface; private float mStrokeWidth; private float mStrokeMiter; private float mTextSize; private float mTextScaleX; private float mTextSkewX; - private int mXfermode; - private int mColorFilter; - private int mShader; - private int mPathEffect; - private int mMaskFilter; - private int mRasterizer; + private Xfermode_Delegate mXfermode; + private ColorFilter_Delegate mColorFilter; + private Shader_Delegate mShader; + private PathEffect_Delegate mPathEffect; + private MaskFilter_Delegate mMaskFilter; + private Rasterizer_Delegate mRasterizer; // ---- Public Helper methods ---- @@ -172,17 +173,16 @@ public class Paint_Delegate { } public Stroke getJavaStroke() { - PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(mPathEffect); - if (effectDelegate != null) { - if (effectDelegate.isSupported()) { - Stroke stroke = effectDelegate.getStroke(this); + if (mPathEffect != null) { + if (mPathEffect.isSupported()) { + Stroke stroke = mPathEffect.getStroke(this); assert stroke != null; if (stroke != null) { return stroke; } } else { Bridge.getLog().fidelityWarning(LayoutLog.TAG_PATHEFFECT, - effectDelegate.getSupportMessage(), + mPathEffect.getSupportMessage(), null, null /*data*/); } } @@ -201,7 +201,7 @@ public class Paint_Delegate { * @return the delegate or null. */ public Xfermode_Delegate getXfermode() { - return Xfermode_Delegate.getDelegate(mXfermode); + return mXfermode; } /** @@ -210,7 +210,7 @@ public class Paint_Delegate { * @return the delegate or null. */ public ColorFilter_Delegate getColorFilter() { - return ColorFilter_Delegate.getDelegate(mColorFilter); + return mColorFilter; } /** @@ -219,7 +219,7 @@ public class Paint_Delegate { * @return the delegate or null. */ public Shader_Delegate getShader() { - return Shader_Delegate.getDelegate(mShader); + return mShader; } /** @@ -228,7 +228,7 @@ public class Paint_Delegate { * @return the delegate or null. */ public MaskFilter_Delegate getMaskFilter() { - return MaskFilter_Delegate.getDelegate(mMaskFilter); + return mMaskFilter; } /** @@ -237,7 +237,7 @@ public class Paint_Delegate { * @return the delegate or null. */ public Rasterizer_Delegate getRasterizer() { - return Rasterizer_Delegate.getDelegate(mRasterizer); + return mRasterizer; } // ---- native methods ---- @@ -542,9 +542,6 @@ public class Paint_Delegate { @LayoutlibDelegate /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index, int count) { - // WARNING: the logic in this method is similar to Canvas.drawText. - // Any change to this method should be reflected in Canvas.drawText - // get the delegate Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); if (delegate == null) { @@ -567,25 +564,57 @@ public class Paint_Delegate { @LayoutlibDelegate /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count, float maxWidth, float[] measuredWidth) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Paint.native_breakText is not supported.", null, null /*data*/); - return 0; + + // get the delegate + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + return 0; + } + + int inc = count > 0 ? 1 : -1; + + int measureIndex = 0; + float measureAcc = 0; + for (int i = index; i != index + count; i += inc, measureIndex++) { + int start, end; + if (i < index) { + start = i; + end = index; + } else { + start = index; + end = i; + } + + // measure from start to end + float res = delegate.measureText(text, start, end - start + 1); + + if (measuredWidth != null) { + measuredWidth[measureIndex] = res; + } + + measureAcc += res; + if (res > maxWidth) { + // we should not return this char index, but since it's 0-based + // and we need to return a count, we simply return measureIndex; + return measureIndex; + } + + } + + return measureIndex; } @LayoutlibDelegate /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards, float maxWidth, float[] measuredWidth) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Paint.native_breakText is not supported.", null, null /*data*/); - return 0; + return native_breakText(thisPaint, text.toCharArray(), 0, text.length(), maxWidth, + measuredWidth); } @LayoutlibDelegate /*package*/ static int native_init() { Paint_Delegate newDelegate = new Paint_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -597,7 +626,7 @@ public class Paint_Delegate { } Paint_Delegate newDelegate = new Paint_Delegate(delegate); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -728,7 +757,9 @@ public class Paint_Delegate { return shader; } - return delegate.mShader = shader; + delegate.mShader = Shader_Delegate.getDelegate(shader); + + return shader; } @LayoutlibDelegate @@ -739,13 +770,12 @@ public class Paint_Delegate { return filter; } - delegate.mColorFilter = filter; + delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter);; // since none of those are supported, display a fidelity warning right away - ColorFilter_Delegate filterDelegate = delegate.getColorFilter(); - if (filterDelegate != null && filterDelegate.isSupported() == false) { + if (delegate.mColorFilter != null && delegate.mColorFilter.isSupported() == false) { Bridge.getLog().fidelityWarning(LayoutLog.TAG_COLORFILTER, - filterDelegate.getSupportMessage(), null, null /*data*/); + delegate.mColorFilter.getSupportMessage(), null, null /*data*/); } return filter; @@ -759,7 +789,9 @@ public class Paint_Delegate { return xfermode; } - return delegate.mXfermode = xfermode; + delegate.mXfermode = Xfermode_Delegate.getDelegate(xfermode); + + return xfermode; } @LayoutlibDelegate @@ -770,7 +802,9 @@ public class Paint_Delegate { return effect; } - return delegate.mPathEffect = effect; + delegate.mPathEffect = PathEffect_Delegate.getDelegate(effect); + + return effect; } @LayoutlibDelegate @@ -781,13 +815,12 @@ public class Paint_Delegate { return maskfilter; } - delegate.mMaskFilter = maskfilter; + delegate.mMaskFilter = MaskFilter_Delegate.getDelegate(maskfilter); // since none of those are supported, display a fidelity warning right away - MaskFilter_Delegate filterDelegate = delegate.getMaskFilter(); - if (filterDelegate != null && filterDelegate.isSupported() == false) { + if (delegate.mMaskFilter != null && delegate.mMaskFilter.isSupported() == false) { Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER, - filterDelegate.getSupportMessage(), null, null /*data*/); + delegate.mMaskFilter.getSupportMessage(), null, null /*data*/); } return maskfilter; @@ -801,9 +834,9 @@ public class Paint_Delegate { return 0; } - delegate.mTypeface = typeface; + delegate.mTypeface = Typeface_Delegate.getDelegate(typeface); delegate.updateFontObject(); - return delegate.mTypeface; + return typeface; } @LayoutlibDelegate @@ -814,13 +847,12 @@ public class Paint_Delegate { return rasterizer; } - delegate.mRasterizer = rasterizer; + delegate.mRasterizer = Rasterizer_Delegate.getDelegate(rasterizer); // since none of those are supported, display a fidelity warning right away - Rasterizer_Delegate rasterizerDelegate = delegate.getRasterizer(); - if (rasterizerDelegate != null && rasterizerDelegate.isSupported() == false) { + if (delegate.mRasterizer != null && delegate.mRasterizer.isSupported() == false) { Bridge.getLog().fidelityWarning(LayoutLog.TAG_RASTERIZER, - rasterizerDelegate.getSupportMessage(), null, null /*data*/); + delegate.mRasterizer.getSupportMessage(), null, null /*data*/); } return rasterizer; @@ -862,19 +894,49 @@ public class Paint_Delegate { @LayoutlibDelegate /*package*/ static int native_getTextWidths(int native_object, char[] text, int index, int count, float[] widths) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Paint.getTextWidths is not supported.", null, null /*data*/); + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + return 0; + } + + if (delegate.mFonts.size() > 0) { + // FIXME: handle multi-char characters (see measureText) + float totalAdvance = 0; + for (int i = 0; i < count; i++) { + char c = text[i + index]; + boolean found = false; + for (FontInfo info : delegate.mFonts) { + if (info.mFont.canDisplay(c)) { + float adv = info.mMetrics.charWidth(c); + totalAdvance += adv; + if (widths != null) { + widths[i] = adv; + } + + found = true; + break; + } + } + + if (found == false) { + // no advance for this char. + if (widths != null) { + widths[i] = 0.f; + } + } + } + + return (int) totalAdvance; + } + return 0; } @LayoutlibDelegate /*package*/ static int native_getTextWidths(int native_object, String text, int start, int end, float[] widths) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Paint.getTextWidths is not supported.", null, null /*data*/); - return 0; + return native_getTextWidths(native_object, text.toCharArray(), start, end - start, widths); } @LayoutlibDelegate @@ -971,22 +1033,33 @@ public class Paint_Delegate { @LayoutlibDelegate /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start, int end, Rect bounds) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Paint.getStringBounds is not supported.", null, null /*data*/); + nativeGetCharArrayBounds(nativePaint, text.toCharArray(), start, end - start, bounds); } @LayoutlibDelegate /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index, int count, Rect bounds) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Paint.getCharArrayBounds is not supported.", null, null /*data*/); + + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(nativePaint); + if (delegate == null) { + return; + } + + // FIXME should test if the main font can display all those characters. + // See MeasureText + if (delegate.mFonts.size() > 0) { + FontInfo mainInfo = delegate.mFonts.get(0); + + Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count, + delegate.mFontContext); + bounds.set(0, 0, (int) rect.getWidth(), (int) rect.getHeight()); + } } @LayoutlibDelegate /*package*/ static void finalizer(int nativePaint) { - sManager.removeDelegate(nativePaint); + sManager.removeJavaReferenceFor(nativePaint); } // ---- Private delegate/helper methods ---- @@ -1028,18 +1101,18 @@ public class Paint_Delegate { mCap = Paint.Cap.BUTT.nativeInt; mJoin = Paint.Join.MITER.nativeInt; mTextAlign = 0; - mTypeface = Typeface.sDefaults[0].native_instance; + mTypeface = Typeface_Delegate.getDelegate(Typeface.sDefaults[0].native_instance); mStrokeWidth = 1.f; mStrokeMiter = 4.f; mTextSize = 20.f; mTextScaleX = 1.f; mTextSkewX = 0.f; - mXfermode = 0; - mColorFilter = 0; - mShader = 0; - mPathEffect = 0; - mMaskFilter = 0; - mRasterizer = 0; + mXfermode = null; + mColorFilter = null; + mShader = null; + mPathEffect = null; + mMaskFilter = null; + mRasterizer = null; updateFontObject(); } @@ -1048,9 +1121,9 @@ public class Paint_Delegate { */ @SuppressWarnings("deprecation") private void updateFontObject() { - if (mTypeface != 0) { + if (mTypeface != null) { // Get the fonts from the TypeFace object. - List<Font> fonts = Typeface_Delegate.getFonts(mTypeface); + List<Font> fonts = mTypeface.getFonts(); // create new font objects as well as FontMetrics, based on the current text size // and skew info. @@ -1073,6 +1146,10 @@ public class Paint_Delegate { } /*package*/ float measureText(char[] text, int index, int count) { + + // WARNING: the logic in this method is similar to Canvas_Delegate.native_drawText + // Any change to this method should be reflected there as well + if (mFonts.size() > 0) { FontInfo mainFont = mFonts.get(0); int i = index; @@ -1120,6 +1197,8 @@ public class Paint_Delegate { i += size; } } + + return total; } return 0; diff --git a/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java index 98a5386067a7..c448f0ec0f20 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java @@ -65,7 +65,7 @@ public class PathDashPathEffect_Delegate extends PathEffect_Delegate { /*package*/ static int nativeCreate(int native_path, float advance, float phase, int native_style) { PathDashPathEffect_Delegate newDelegate = new PathDashPathEffect_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java index bbbebdd8df2f..4d5311af42ae 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java @@ -61,7 +61,7 @@ public abstract class PathEffect_Delegate { @LayoutlibDelegate /*package*/ static void nativeDestructor(int native_patheffect) { - sManager.removeDelegate(native_patheffect); + sManager.removeJavaReferenceFor(native_patheffect); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java index 9510ce00e214..c29e9b6a0142 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java @@ -90,7 +90,7 @@ public final class Path_Delegate { // create the delegate Path_Delegate newDelegate = new Path_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -104,7 +104,7 @@ public final class Path_Delegate { newDelegate.set(pathDelegate); } - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -440,7 +440,7 @@ public final class Path_Delegate { @LayoutlibDelegate /*package*/ static void finalizer(int nPath) { - sManager.removeDelegate(nPath); + sManager.removeJavaReferenceFor(nPath); } diff --git a/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java index bbb20e956163..4ab044bd107a 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java @@ -63,7 +63,7 @@ public class PixelXorXfermode_Delegate extends Xfermode_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(int opColor) { PixelXorXfermode_Delegate newDelegate = new PixelXorXfermode_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java index 33f6c4465527..c45dbaad344d 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java @@ -57,7 +57,7 @@ public class PorterDuffColorFilter_Delegate extends ColorFilter_Delegate { @LayoutlibDelegate /*package*/ static int native_CreatePorterDuffFilter(int srcColor, int porterDuffMode) { PorterDuffColorFilter_Delegate newDelegate = new PorterDuffColorFilter_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java index 116a773c9832..4301c1a2c5d7 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java @@ -129,7 +129,7 @@ public class PorterDuffXfermode_Delegate extends Xfermode_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreateXfermode(int mode) { PorterDuffXfermode_Delegate newDelegate = new PorterDuffXfermode_Delegate(mode); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java index 8723ed1a6584..9bf78b4c7249 100644 --- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java @@ -58,7 +58,7 @@ public class RadialGradient_Delegate extends Gradient_Delegate { int colors[], float positions[], int tileMode) { RadialGradient_Delegate newDelegate = new RadialGradient_Delegate(x, y, radius, colors, positions, Shader_Delegate.getTileMode(tileMode)); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java index 28262787f9ba..e388bd9fc1b0 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java @@ -57,7 +57,7 @@ public abstract class Rasterizer_Delegate { @LayoutlibDelegate /*package*/ static void finalizer(int native_instance) { - sManager.removeDelegate(native_instance); + sManager.removeJavaReferenceFor(native_instance); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java index 7b912154930f..91f4347482ab 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java @@ -266,12 +266,12 @@ public class Region_Delegate { @LayoutlibDelegate /*package*/ static int nativeConstructor() { Region_Delegate newDelegate = new Region_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate /*package*/ static void nativeDestructor(int native_region) { - sManager.removeDelegate(native_region); + sManager.removeJavaReferenceFor(native_region); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java index a1b8bdd12fdf..a008d151c6ae 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java @@ -45,7 +45,7 @@ public abstract class Shader_Delegate { // ---- delegate helper data ---- // ---- delegate data ---- - private int mLocalMatrix = 0; + private Matrix_Delegate mLocalMatrix = null; // ---- Public Helper methods ---- @@ -77,7 +77,7 @@ public abstract class Shader_Delegate { @LayoutlibDelegate /*package*/ static void nativeDestructor(int native_shader, int native_skiaShader) { - sManager.removeDelegate(native_shader); + sManager.removeJavaReferenceFor(native_shader); } @LayoutlibDelegate @@ -89,15 +89,14 @@ public abstract class Shader_Delegate { return; } - shaderDelegate.mLocalMatrix = matrix_instance; + shaderDelegate.mLocalMatrix = Matrix_Delegate.getDelegate(matrix_instance); } // ---- Private delegate/helper methods ---- protected java.awt.geom.AffineTransform getLocalMatrix() { - Matrix_Delegate localMatrixDelegate = Matrix_Delegate.getDelegate(mLocalMatrix); - if (localMatrixDelegate != null) { - return localMatrixDelegate.getAffineTransform(); + if (mLocalMatrix != null) { + return mLocalMatrix.getAffineTransform(); } return new java.awt.geom.AffineTransform(); diff --git a/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java index 0c9ee48ebd64..410df0cf72f5 100644 --- a/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java @@ -64,7 +64,7 @@ public class SumPathEffect_Delegate extends PathEffect_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(int first, int second) { SumPathEffect_Delegate newDelegate = new SumPathEffect_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java index 382e34c41ad4..966e06e4a8b2 100644 --- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java @@ -54,7 +54,7 @@ public class SweepGradient_Delegate extends Gradient_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate1(float x, float y, int colors[], float positions[]) { SweepGradient_Delegate newDelegate = new SweepGradient_Delegate(x, y, colors, positions); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java index 1992341d1423..5af16aeb5fb3 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java @@ -74,6 +74,10 @@ public final class Typeface_Delegate { sPostInitDelegate.clear(); } + public static Typeface_Delegate getDelegate(int nativeTypeface) { + return sManager.getDelegate(nativeTypeface); + } + public static List<Font> getFonts(Typeface typeface) { return getFonts(typeface.native_instance); } @@ -84,7 +88,11 @@ public final class Typeface_Delegate { return null; } - return delegate.mFonts; + return delegate.getFonts(); + } + + public List<Font> getFonts() { + return mFonts; } // ---- native methods ---- @@ -105,7 +113,7 @@ public final class Typeface_Delegate { sPostInitDelegate.add(newDelegate); } - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -125,7 +133,7 @@ public final class Typeface_Delegate { sPostInitDelegate.add(newDelegate); } - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -144,7 +152,7 @@ public final class Typeface_Delegate { @LayoutlibDelegate /*package*/ static void nativeUnref(int native_instance) { - sManager.removeDelegate(native_instance); + sManager.removeJavaReferenceFor(native_instance); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java index 88df02739c6e..f3401fcadb65 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java @@ -61,7 +61,7 @@ public abstract class Xfermode_Delegate { @LayoutlibDelegate /*package*/ static void finalizer(int native_instance) { - sManager.removeDelegate(native_instance); + sManager.removeJavaReferenceFor(native_instance); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java index 04d06e4bb45e..9fab51a61092 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java @@ -30,7 +30,7 @@ import android.widget.TextView; public class PhoneSystemBar extends CustomBar { public PhoneSystemBar(Context context, Density density) throws XmlPullParserException { - super(context, density, "/bars/tablet_system_bar.xml"); + super(context, density, "/bars/phone_system_bar.xml"); setGravity(mGravity | Gravity.RIGHT); setBackgroundColor(0xFF000000); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java index 05a258d56c66..295c98c3eafa 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java @@ -16,8 +16,14 @@ package com.android.layoutlib.bridge.impl; +import com.android.layoutlib.bridge.util.SparseWeakArray; + import android.util.SparseArray; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; + /** * Manages native delegates. * @@ -44,13 +50,32 @@ import android.util.SparseArray; * will do is call {@link #getDelegate(int)} to get the Java object matching the int. * * Typical native init methods are returning a new int back to the Java class, so - * {@link #addDelegate(Object)} does the same. + * {@link #addNewDelegate(Object)} does the same. + * + * The JNI references are counted, so we do the same through a {@link WeakReference}. Because + * the Java object needs to count as a reference (even though it only holds an int), we use the + * following mechanism: + * + * - {@link #addNewDelegate(Object)} and {@link #removeJavaReferenceFor(int)} adds and removes + * the delegate to/from a list. This list hold the reference and prevents the GC from reclaiming + * the delegate. + * + * - {@link #addNewDelegate(Object)} also adds the delegate to a {@link SparseArray} that holds a + * {@link WeakReference} to the delegate. This allows the delegate to be deleted automatically + * when nothing references it. This means that any class that holds a delegate (except for the + * Java main class) must not use the int but the Delegate class instead. The integers must + * only be used in the API between the main Java class and the Delegate. * * @param <T> the delegate class to manage */ public final class DelegateManager<T> { - - private final SparseArray<T> mDelegates = new SparseArray<T>(); + private final SparseWeakArray<T> mDelegates = new SparseWeakArray<T>(); + /** list used to store delegates when their main object holds a reference to them. + * This is to ensure that the WeakReference in the SparseWeakArray doesn't get GC'ed + * @see #addNewDelegate(Object) + * @see #removeJavaReferenceFor(int) + */ + private final List<T> mJavaReferences = new ArrayList<T>(); private int mDelegateCounter = 0; /** @@ -77,17 +102,20 @@ public final class DelegateManager<T> { * @param newDelegate the delegate to add * @return a unique native int to identify the delegate */ - public int addDelegate(T newDelegate) { + public int addNewDelegate(T newDelegate) { int native_object = ++mDelegateCounter; mDelegates.put(native_object, newDelegate); + assert !mJavaReferences.contains(newDelegate); + mJavaReferences.add(newDelegate); return native_object; } /** - * Removes the delegate matching the given native int. - * @param native_object the native int. + * Removes the main reference on the given delegate. + * @param native_object the native integer representing the delegate. */ - public void removeDelegate(int native_object) { - mDelegates.remove(native_object); + public void removeJavaReferenceFor(int native_object) { + T delegate = getDelegate(native_object); + mJavaReferences.remove(delegate); } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java new file mode 100644 index 000000000000..22f1609e6dc6 --- /dev/null +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java @@ -0,0 +1,368 @@ +/* + * 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.layoutlib.bridge.util; + + +import com.android.internal.util.ArrayUtils; + +import android.util.SparseArray; + +import java.lang.ref.WeakReference; + +/** + * This is a custom {@link SparseArray} that uses {@link WeakReference} around the objects added + * to it. When the array is compacted, not only deleted indices but also empty references + * are removed, making the array efficient at removing references that were reclaimed. + * + * The code is taken from {@link SparseArray} directly and adapted to use weak references. + * + * Because our usage means that we never actually call {@link #remove(int)} or {@link #delete(int)}, + * we must manually check if there are reclaimed references to trigger an internal compact step + * (which is normally only triggered when an item is manually removed). + * + * SparseArrays map integers to Objects. Unlike a normal array of Objects, + * there can be gaps in the indices. It is intended to be more efficient + * than using a HashMap to map Integers to Objects. + */ +@SuppressWarnings("unchecked") +public class SparseWeakArray<E> { + + private static final Object DELETED_REF = new Object(); + private static final WeakReference<?> DELETED = new WeakReference(DELETED_REF); + private boolean mGarbage = false; + + /** + * Creates a new SparseArray containing no mappings. + */ + public SparseWeakArray() { + this(10); + } + + /** + * Creates a new SparseArray containing no mappings that will not + * require any additional memory allocation to store the specified + * number of mappings. + */ + public SparseWeakArray(int initialCapacity) { + initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity); + + mKeys = new int[initialCapacity]; + mValues = new WeakReference[initialCapacity]; + mSize = 0; + } + + /** + * Gets the Object mapped from the specified key, or <code>null</code> + * if no such mapping has been made. + */ + public E get(int key) { + return get(key, null); + } + + /** + * Gets the Object mapped from the specified key, or the specified Object + * if no such mapping has been made. + */ + public E get(int key, E valueIfKeyNotFound) { + int i = binarySearch(mKeys, 0, mSize, key); + + if (i < 0 || mValues[i] == DELETED || mValues[i].get() == null) { + return valueIfKeyNotFound; + } else { + return (E) mValues[i].get(); + } + } + + /** + * Removes the mapping from the specified key, if there was any. + */ + public void delete(int key) { + int i = binarySearch(mKeys, 0, mSize, key); + + if (i >= 0) { + if (mValues[i] != DELETED) { + mValues[i] = DELETED; + mGarbage = true; + } + } + } + + /** + * Alias for {@link #delete(int)}. + */ + public void remove(int key) { + delete(key); + } + + /** + * Removes the mapping at the specified index. + */ + public void removeAt(int index) { + if (mValues[index] != DELETED) { + mValues[index] = DELETED; + mGarbage = true; + } + } + + private void gc() { + // Log.e("SparseArray", "gc start with " + mSize); + + int n = mSize; + int o = 0; + int[] keys = mKeys; + WeakReference<?>[] values = mValues; + + for (int i = 0; i < n; i++) { + WeakReference<?> val = values[i]; + + // Don't keep any non DELETED values, but only the one that still have a valid + // reference. + if (val != DELETED && val.get() != null) { + if (i != o) { + keys[o] = keys[i]; + values[o] = val; + } + + o++; + } + } + + mGarbage = false; + mSize = o; + + // Log.e("SparseArray", "gc end with " + mSize); + } + + /** + * Adds a mapping from the specified key to the specified value, + * replacing the previous mapping from the specified key if there + * was one. + */ + public void put(int key, E value) { + int i = binarySearch(mKeys, 0, mSize, key); + + if (i >= 0) { + mValues[i] = new WeakReference(value); + } else { + i = ~i; + + if (i < mSize && (mValues[i] == DELETED || mValues[i].get() == null)) { + mKeys[i] = key; + mValues[i] = new WeakReference(value); + return; + } + + if (mSize >= mKeys.length && (mGarbage || hasReclaimedRefs())) { + gc(); + + // Search again because indices may have changed. + i = ~binarySearch(mKeys, 0, mSize, key); + } + + if (mSize >= mKeys.length) { + int n = ArrayUtils.idealIntArraySize(mSize + 1); + + int[] nkeys = new int[n]; + WeakReference<?>[] nvalues = new WeakReference[n]; + + // Log.e("SparseArray", "grow " + mKeys.length + " to " + n); + System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length); + System.arraycopy(mValues, 0, nvalues, 0, mValues.length); + + mKeys = nkeys; + mValues = nvalues; + } + + if (mSize - i != 0) { + // Log.e("SparseArray", "move " + (mSize - i)); + System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i); + System.arraycopy(mValues, i, mValues, i + 1, mSize - i); + } + + mKeys[i] = key; + mValues[i] = new WeakReference(value); + mSize++; + } + } + + /** + * Returns the number of key-value mappings that this SparseArray + * currently stores. + */ + public int size() { + if (mGarbage) { + gc(); + } + + return mSize; + } + + /** + * Given an index in the range <code>0...size()-1</code>, returns + * the key from the <code>index</code>th key-value mapping that this + * SparseArray stores. + */ + public int keyAt(int index) { + if (mGarbage) { + gc(); + } + + return mKeys[index]; + } + + /** + * Given an index in the range <code>0...size()-1</code>, returns + * the value from the <code>index</code>th key-value mapping that this + * SparseArray stores. + */ + public E valueAt(int index) { + if (mGarbage) { + gc(); + } + + return (E) mValues[index].get(); + } + + /** + * Given an index in the range <code>0...size()-1</code>, sets a new + * value for the <code>index</code>th key-value mapping that this + * SparseArray stores. + */ + public void setValueAt(int index, E value) { + if (mGarbage) { + gc(); + } + + mValues[index] = new WeakReference(value); + } + + /** + * Returns the index for which {@link #keyAt} would return the + * specified key, or a negative number if the specified + * key is not mapped. + */ + public int indexOfKey(int key) { + if (mGarbage) { + gc(); + } + + return binarySearch(mKeys, 0, mSize, key); + } + + /** + * Returns an index for which {@link #valueAt} would return the + * specified key, or a negative number if no keys map to the + * specified value. + * Beware that this is a linear search, unlike lookups by key, + * and that multiple keys can map to the same value and this will + * find only one of them. + */ + public int indexOfValue(E value) { + if (mGarbage) { + gc(); + } + + for (int i = 0; i < mSize; i++) + if (mValues[i].get() == value) + return i; + + return -1; + } + + /** + * Removes all key-value mappings from this SparseArray. + */ + public void clear() { + int n = mSize; + WeakReference<?>[] values = mValues; + + for (int i = 0; i < n; i++) { + values[i] = null; + } + + mSize = 0; + mGarbage = false; + } + + /** + * Puts a key/value pair into the array, optimizing for the case where + * the key is greater than all existing keys in the array. + */ + public void append(int key, E value) { + if (mSize != 0 && key <= mKeys[mSize - 1]) { + put(key, value); + return; + } + + if (mSize >= mKeys.length && (mGarbage || hasReclaimedRefs())) { + gc(); + } + + int pos = mSize; + if (pos >= mKeys.length) { + int n = ArrayUtils.idealIntArraySize(pos + 1); + + int[] nkeys = new int[n]; + WeakReference<?>[] nvalues = new WeakReference[n]; + + // Log.e("SparseArray", "grow " + mKeys.length + " to " + n); + System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length); + System.arraycopy(mValues, 0, nvalues, 0, mValues.length); + + mKeys = nkeys; + mValues = nvalues; + } + + mKeys[pos] = key; + mValues[pos] = new WeakReference(value); + mSize = pos + 1; + } + + private boolean hasReclaimedRefs() { + for (int i = 0 ; i < mSize ; i++) { + if (mValues[i].get() == null) { // DELETED.get() never returns null. + return true; + } + } + + return false; + } + + private static int binarySearch(int[] a, int start, int len, int key) { + int high = start + len, low = start - 1, guess; + + while (high - low > 1) { + guess = (high + low) / 2; + + if (a[guess] < key) + low = guess; + else + high = guess; + } + + if (high == start + len) + return ~(start + len); + else if (a[high] == key) + return high; + else + return ~high; + } + + private int[] mKeys; + private WeakReference<?>[] mValues; + private int mSize; +} diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java index 39676b044001..909605dc55d4 100644 --- a/wifi/java/android/net/wifi/WifiNative.java +++ b/wifi/java/android/net/wifi/WifiNative.java @@ -170,4 +170,6 @@ public class WifiNative { * @return the event string sent by the supplicant. */ public native static String waitForEvent(); + + public native static void enableBackgroundScan(boolean enable); } diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index fc42ab8bdad9..676218e9eb4c 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -112,9 +112,11 @@ public class WifiStateMachine extends HierarchicalStateMachine { private String mLastBssid; private int mLastNetworkId; private boolean mEnableRssiPolling = false; + private boolean mEnableBackgroundScan = false; private int mRssiPollToken = 0; private int mReconnectCount = 0; private boolean mIsScanMode = false; + private boolean mScanResultIsPending = false; private boolean mBluetoothConnectionActive = false; @@ -300,6 +302,8 @@ public class WifiStateMachine extends HierarchicalStateMachine { static final int CMD_START_WPS = 89; /* Set the frequency band */ static final int CMD_SET_FREQUENCY_BAND = 90; + /* Enable background scan for configured networks */ + static final int CMD_ENABLE_BACKGROUND_SCAN = 91; /* Commands from/to the SupplicantStateTracker */ /* Reset the supplicant state tracker */ @@ -823,6 +827,10 @@ public class WifiStateMachine extends HierarchicalStateMachine { sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0)); } + public void enableBackgroundScan(boolean enabled) { + sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0)); + } + public void enableAllNetworks() { sendMessage(CMD_ENABLE_ALL_NETWORKS); } @@ -1538,6 +1546,9 @@ public class WifiStateMachine extends HierarchicalStateMachine { case CMD_ENABLE_RSSI_POLL: mEnableRssiPolling = (message.arg1 == 1); break; + case CMD_ENABLE_BACKGROUND_SCAN: + mEnableBackgroundScan = (message.arg1 == 1); + break; /* Discard */ case CMD_LOAD_DRIVER: case CMD_UNLOAD_DRIVER: @@ -1973,6 +1984,7 @@ public class WifiStateMachine extends HierarchicalStateMachine { eventLoggingEnabled = false; setScanResults(WifiNative.scanResultsCommand()); sendScanResultsAvailableBroadcast(); + mScanResultIsPending = false; break; case CMD_PING_SUPPLICANT: boolean ok = WifiNative.pingCommand(); @@ -2180,6 +2192,7 @@ public class WifiStateMachine extends HierarchicalStateMachine { case CMD_START_SCAN: eventLoggingEnabled = false; WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE); + mScanResultIsPending = true; break; case CMD_SET_HIGH_PERF_MODE: setHighPerfModeEnabledNative(message.arg1 == 1); @@ -2681,8 +2694,8 @@ public class WifiStateMachine extends HierarchicalStateMachine { * back to CONNECT_MODE. */ WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE); - WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE); - break; + /* Have the parent state handle the rest */ + return NOT_HANDLED; /* Ignore connection to same network */ case CMD_CONNECT_NETWORK: int netId = message.arg1; @@ -2771,21 +2784,35 @@ public class WifiStateMachine extends HierarchicalStateMachine { } class DisconnectedState extends HierarchicalState { + private boolean mAlarmEnabled = false; @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - /** - * In a disconnected state, an infrequent scan that wakes - * up the device is needed to ensure a user connects to - * an access point on the move + /* + * We initiate background scanning if it is enabled, otherwise we + * initiate an infrequent scan that wakes up the device to ensure + * a user connects to an access point on the move */ - long scanMs = Settings.Secure.getLong(mContext.getContentResolver(), + if (mEnableBackgroundScan) { + /* If a regular scan result is pending, do not initiate background + * scan until the scan results are returned. This is needed because + * initiating a background scan will cancel the regular scan and + * scan results will not be returned until background scanning is + * cleared + */ + if (!mScanResultIsPending) { + WifiNative.enableBackgroundScan(true); + } + } else { + long scanMs = Settings.Secure.getLong(mContext.getContentResolver(), Settings.Secure.WIFI_SCAN_INTERVAL_MS, DEFAULT_SCAN_INTERVAL_MS); - mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, + mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + scanMs, scanMs, mScanIntent); + mAlarmEnabled = true; + } } @Override public boolean processMessage(Message message) { @@ -2800,6 +2827,10 @@ public class WifiStateMachine extends HierarchicalStateMachine { transitionTo(mScanModeState); } break; + case CMD_ENABLE_BACKGROUND_SCAN: + mEnableBackgroundScan = (message.arg1 == 1); + WifiNative.enableBackgroundScan(mEnableBackgroundScan); + break; /* Ignore network disconnect */ case NETWORK_DISCONNECTION_EVENT: break; @@ -2808,6 +2839,20 @@ public class WifiStateMachine extends HierarchicalStateMachine { setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); /* DriverStartedState does the rest of the handling */ return NOT_HANDLED; + case CMD_START_SCAN: + /* Disable background scan temporarily during a regular scan */ + if (mEnableBackgroundScan) { + WifiNative.enableBackgroundScan(false); + } + /* Handled in parent state */ + return NOT_HANDLED; + case SCAN_RESULTS_EVENT: + /* Re-enable background scan when a pending scan result is received */ + if (mEnableBackgroundScan && mScanResultIsPending) { + WifiNative.enableBackgroundScan(true); + } + /* Handled in parent state */ + return NOT_HANDLED; default: return NOT_HANDLED; } @@ -2817,7 +2862,14 @@ public class WifiStateMachine extends HierarchicalStateMachine { @Override public void exit() { - mAlarmManager.cancel(mScanIntent); + /* No need for a background scan upon exit from a disconnected state */ + if (mEnableBackgroundScan) { + WifiNative.enableBackgroundScan(false); + } + if (mAlarmEnabled) { + mAlarmManager.cancel(mScanIntent); + mAlarmEnabled = false; + } } } |