Merge "Apply values set in "dropDownWidth" attribute of Spinner styles."
diff --git a/api/current.xml b/api/current.xml
index 4ecaf53..b51242b 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -29358,6 +29358,17 @@
visibility="public"
>
</field>
+<field name="COLUMN_MEDIAPROVIDER_URI"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""mediaprovider_uri""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="COLUMN_MEDIA_TYPE"
type="java.lang.String"
transient="false"
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index b9a541d..fd96cf0 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -28,7 +28,6 @@
import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns;
import android.provider.Downloads;
-import android.util.Log;
import android.util.Pair;
import java.io.File;
@@ -141,6 +140,12 @@
*/
public final static String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
+ /**
+ * The URI to the corresponding entry in MediaProvider for this downloaded entry. It is
+ * used to delete the entries from MediaProvider database when it is deleted from the
+ * downloaded list.
+ */
+ public static final String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
/**
* Value of {@link #COLUMN_STATUS} when the download is waiting to start.
@@ -271,6 +276,7 @@
// this array must contain all public columns
private static final String[] COLUMNS = new String[] {
COLUMN_ID,
+ COLUMN_MEDIAPROVIDER_URI,
COLUMN_TITLE,
COLUMN_DESCRIPTION,
COLUMN_URI,
@@ -287,6 +293,7 @@
// columns to request from DownloadProvider
private static final String[] UNDERLYING_COLUMNS = new String[] {
Downloads.Impl._ID,
+ Downloads.Impl.COLUMN_MEDIAPROVIDER_URI,
Downloads.COLUMN_TITLE,
Downloads.COLUMN_DESCRIPTION,
Downloads.COLUMN_URI,
@@ -683,6 +690,9 @@
selectionParts.add(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI + " != '0'");
}
+ // only return rows which are not marked 'deleted = 1'
+ selectionParts.add(Downloads.Impl.COLUMN_DELETED + " != '1'");
+
String selection = joinStrings(" AND ", selectionParts);
String orderDirection = (mOrderDirection == ORDER_ASCENDING ? "ASC" : "DESC");
String orderBy = mOrderByColumn + " " + orderDirection;
@@ -749,6 +759,26 @@
}
/**
+ * Marks the specified download as 'to be deleted'. This is done when a completed download
+ * is to be removed but the row was stored without enough info to delete the corresponding
+ * metadata from Mediaprovider database. Actual cleanup of this row is done in DownloadService.
+ *
+ * @param ids the IDs of the downloads to be marked 'deleted'
+ * @return the number of downloads actually updated
+ * @hide
+ */
+ public int markRowDeleted(long... ids) {
+ if (ids == null || ids.length == 0) {
+ // called with nothing to remove!
+ throw new IllegalArgumentException("input param 'ids' can't be null");
+ }
+ ContentValues values = new ContentValues();
+ values.put(Downloads.Impl.COLUMN_DELETED, 1);
+ return mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
+ getWhereArgsForIds(ids));
+ }
+
+ /**
* Cancel downloads and remove them from the download manager. Each download will be stopped if
* it was running, and it will no longer be accessible through the download manager. If a file
* was already downloaded to external storage, it will not be deleted.
@@ -959,6 +989,9 @@
if (column.equals(COLUMN_LOCAL_FILENAME)) {
return getUnderlyingString(Downloads.Impl._DATA);
}
+ if (column.equals(COLUMN_MEDIAPROVIDER_URI)) {
+ return getUnderlyingString(Downloads.Impl.COLUMN_MEDIAPROVIDER_URI);
+ }
assert column.equals(COLUMN_LOCAL_URI);
return getLocalUri();
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index ce511bd..41ec3cc 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -156,6 +156,10 @@
Message msg = new Message();
msg.what = AUTO_CONNECT_PROFILES;
sendMessageDelayed(msg, AUTO_CONNECT_DELAY);
+ } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
+ // This is technically not needed, but we can get stuck sometimes.
+ // For example, if incoming A2DP fails, we are not informed by Bluez
+ sendMessage(TRANSITION_TO_STABLE);
}
}
};
@@ -198,6 +202,7 @@
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED);
+ filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
mContext.registerReceiver(mBroadcastReceiver, filter);
@@ -348,7 +353,11 @@
Log.e(TAG, "Error: OutgoingHandsfree state with command:" + mCommand);
}
mStatus = processCommand(mCommand);
- if (!mStatus) sendMessage(TRANSITION_TO_STABLE);
+ if (!mStatus) {
+ sendMessage(TRANSITION_TO_STABLE);
+ mService.sendProfileStateMessage(BluetoothProfileState.HFP,
+ BluetoothProfileState.TRANSITION_TO_STABLE);
+ }
}
@Override
@@ -456,7 +465,11 @@
Log.e(TAG, "Error: IncomingHandsfree state with command:" + mCommand);
}
mStatus = processCommand(mCommand);
- if (!mStatus) sendMessage(TRANSITION_TO_STABLE);
+ if (!mStatus) {
+ sendMessage(TRANSITION_TO_STABLE);
+ mService.sendProfileStateMessage(BluetoothProfileState.HFP,
+ BluetoothProfileState.TRANSITION_TO_STABLE);
+ }
}
@Override
@@ -531,7 +544,11 @@
Log.e(TAG, "Error: OutgoingA2DP state with command:" + mCommand);
}
mStatus = processCommand(mCommand);
- if (!mStatus) sendMessage(TRANSITION_TO_STABLE);
+ if (!mStatus) {
+ sendMessage(TRANSITION_TO_STABLE);
+ mService.sendProfileStateMessage(BluetoothProfileState.A2DP,
+ BluetoothProfileState.TRANSITION_TO_STABLE);
+ }
}
@Override
@@ -636,7 +653,11 @@
Log.e(TAG, "Error: IncomingA2DP state with command:" + mCommand);
}
mStatus = processCommand(mCommand);
- if (!mStatus) sendMessage(TRANSITION_TO_STABLE);
+ if (!mStatus) {
+ sendMessage(TRANSITION_TO_STABLE);
+ mService.sendProfileStateMessage(BluetoothProfileState.A2DP,
+ BluetoothProfileState.TRANSITION_TO_STABLE);
+ }
}
@Override
diff --git a/core/java/android/bluetooth/BluetoothProfileState.java b/core/java/android/bluetooth/BluetoothProfileState.java
index 7f42baf..584008b 100644
--- a/core/java/android/bluetooth/BluetoothProfileState.java
+++ b/core/java/android/bluetooth/BluetoothProfileState.java
@@ -47,7 +47,7 @@
public static final int A2DP = 1;
public static final int HID = 2;
- private static int TRANSITION_TO_STABLE = 100;
+ static final int TRANSITION_TO_STABLE = 100;
private int mProfile;
private BluetoothDevice mPendingDevice;
@@ -58,6 +58,7 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
+ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
@@ -77,6 +78,10 @@
newState == BluetoothInputDevice.STATE_DISCONNECTED)) {
sendMessage(TRANSITION_TO_STABLE);
}
+ } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
+ if (device.equals(mPendingDevice)) {
+ sendMessage(TRANSITION_TO_STABLE);
+ }
}
}
};
@@ -92,6 +97,7 @@
filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED);
+ filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
context.registerReceiver(mBroadcastReceiver, filter);
}
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 8fd0e0a..72bf6b0 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -300,6 +300,15 @@
*/
public static final String COLUMN_DESCRIPTION = "description";
+ /**
+ * Set to true if this download is deleted. It is completely removed from the database
+ * when MediaProvider database also deletes the metadata asociated with this downloaded file.
+ * <P>Type: BOOLEAN</P>
+ * <P>Owner can Read</P>
+ * @hide
+ */
+ public static final String COLUMN_DELETED = "deleted";
+
/*
* Lists the destinations that an application can specify for a download.
*/
@@ -881,6 +890,23 @@
public static final String COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT =
"bypass_recommended_size_limit";
+ /**
+ * Set to true if this download is deleted. It is completely removed from the database
+ * when MediaProvider database also deletes the metadata asociated with this downloaded file.
+ * <P>Type: BOOLEAN</P>
+ * <P>Owner can Read</P>
+ */
+ public static final String COLUMN_DELETED = "deleted";
+
+ /**
+ * The URI to the corresponding entry in MediaProvider for this downloaded entry. It is
+ * used to delete the entries from MediaProvider database when it is deleted from the
+ * downloaded list.
+ * <P>Type: TEXT</P>
+ * <P>Owner can Read</P>
+ */
+ public static final String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
+
/*
* Lists the destinations that an application can specify for a download.
*/
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 4edc01f..cfbc2bd 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -596,7 +596,14 @@
authorized = mA2dp.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
if (authorized) {
Log.i(TAG, "Allowing incoming A2DP / AVRCP connection from " + address);
- mBluetoothService.notifyIncomingA2dpConnection(address);
+ // Some headsets try to connect AVCTP before AVDTP - against the recommendation
+ // If AVCTP connection fails, we get stuck in IncomingA2DP state in the state
+ // machine. We don't handle AVCTP signals currently. We only send
+ // intents for AVDTP state changes. We need to handle both of them in
+ // some cases. For now, just don't move to incoming state in this case.
+ if (!BluetoothUuid.isAvrcpTarget(uuid)) {
+ mBluetoothService.notifyIncomingA2dpConnection(address);
+ }
} else {
Log.i(TAG, "Rejecting incoming A2DP / AVRCP connection from " + address);
}
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index f8caa2c..f8a39f7 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -2717,6 +2717,16 @@
mA2dpService = a2dpService;
}
+ public void sendProfileStateMessage(int profile, int cmd) {
+ Message msg = new Message();
+ msg.what = cmd;
+ if (profile == BluetoothProfileState.HFP) {
+ mHfpProfileState.sendMessage(msg);
+ } else if (profile == BluetoothProfileState.A2DP) {
+ mA2dpProfileState.sendMessage(msg);
+ }
+ }
+
private static void log(String msg) {
Log.d(TAG, msg);
}
diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp
index e4b07c4..46b1750 100644
--- a/libs/rs/rsObjectBase.cpp
+++ b/libs/rs/rsObjectBase.cpp
@@ -93,9 +93,8 @@
if (mRSC && mRSC->props.mLogObjects) {
dumpLOGV("checkDelete");
}
- delete this;
-
unlockUserRef();
+ delete this;
return true;
}
return false;
@@ -170,9 +169,7 @@
void ObjectBase::remove() const
{
- // Should be within gObjectInitMutex lock
- // lock will be from checkDelete a few levels up in the stack.
-
+ lockUserRef();
//LOGV("calling remove rsc %p", mRSC);
if (!mRSC) {
rsAssert(!mPrev);
@@ -191,12 +188,11 @@
}
mPrev = NULL;
mNext = NULL;
+ unlockUserRef();
}
void ObjectBase::zeroAllUserRef(Context *rsc)
{
- lockUserRef();
-
if (rsc->props.mLogObjects) {
LOGV("Forcing release of all outstanding user refs.");
}
@@ -219,8 +215,6 @@
LOGV("Objects remaining.");
dumpAll(rsc);
}
-
- unlockUserRef();
}
void ObjectBase::dumpAll(Context *rsc)