Merge change 24764 into eclair
* changes:
Add @Widget annotation to GestureOverlayView to make it usable in ADT.
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 4550d1a..39ed769 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -1,3 +1,5 @@
+ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
+
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -38,3 +40,5 @@
LOCAL_MODULE:= record
include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8c422a2..03346fe 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -185,7 +185,7 @@
private final HandlerCaller mCaller;
- private AccessibilityService mTarget;
+ private final AccessibilityService mTarget;
public IEventListenerWrapper(AccessibilityService context) {
mTarget = context;
@@ -211,9 +211,9 @@
switch (message.what) {
case DO_ON_ACCESSIBILITY_EVENT :
AccessibilityEvent event = (AccessibilityEvent) message.obj;
- if (event != null){
- mTarget.onAccessibilityEvent(event);
- event.recycle();
+ if (event != null) {
+ mTarget.onAccessibilityEvent(event);
+ event.recycle();
}
return;
case DO_ON_INTERRUPT :
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index a9cec50..b1861ac 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -250,7 +250,7 @@
* @hide */
public static final int BOND_SUCCESS = 0;
/** A bond attempt failed because pins did not match, or remote device did
- * not respond to pin request in time
+ * not respond to pin request in time
* @hide */
public static final int UNBOND_REASON_AUTH_FAILED = 1;
/** A bond attempt failed because the other side explicilty rejected
@@ -266,9 +266,15 @@
/** A bond attempt failed because a discovery is in progress
* @hide */
public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
+ /** A bond attempt failed because of authentication timeout
+ * @hide */
+ public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
+ /** A bond attempt failed because of repeated attempts
+ * @hide */
+ public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
/** An existing bond was explicitly revoked
* @hide */
- public static final int UNBOND_REASON_REMOVED = 6;
+ public static final int UNBOND_REASON_REMOVED = 8;
/** The user will be prompted to enter a pin
* @hide */
@@ -278,7 +284,13 @@
public static final int PAIRING_VARIANT_PASSKEY = 1;
/** The user will be prompted to confirm the passkey displayed on the screen
* @hide */
- public static final int PAIRING_VARIANT_CONFIRMATION = 2;
+ public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
+ /** The user will be prompted to accept or deny the incoming pairing request
+ * @hide */
+ public static final int PAIRING_VARIANT_CONSENT = 3;
+ /** The user will be prompted to enter the passkey displayed on remote device
+ * @hide */
+ public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
private static IBluetooth sService; /* Guarenteed constant after first object constructed */
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 0bc8a9d..0d43b2a 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -24,7 +24,6 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.util.Locale;
/**
* Provides access to an application's raw asset files; see {@link Resources}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 7d412a7..ba5c9ed 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -66,8 +66,6 @@
= new SparseArray<ColorStateList>();
private static boolean mPreloaded;
- private final LongSparseArray<Drawable.ConstantState> mPreloadedDrawables;
-
/*package*/ final TypedValue mTmpValue = new TypedValue();
// These are protected by the mTmpValue lock.
@@ -158,11 +156,6 @@
}
updateConfiguration(config, metrics);
assets.ensureStringBlocks();
- if (mCompatibilityInfo.isScalingRequired()) {
- mPreloadedDrawables = emptySparseArray();
- } else {
- mPreloadedDrawables = sPreloadedDrawables;
- }
}
/**
@@ -1669,7 +1662,7 @@
return dr;
}
- Drawable.ConstantState cs = mPreloadedDrawables.get(key);
+ Drawable.ConstantState cs = sPreloadedDrawables.get(key);
if (cs != null) {
dr = cs.newDrawable();
} else {
@@ -1976,7 +1969,6 @@
mMetrics.setToDefaults();
updateConfiguration(null, null);
mAssets.ensureStringBlocks();
- mPreloadedDrawables = sPreloadedDrawables;
mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
}
}
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 4c24c50..1ed5c49 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -17,8 +17,8 @@
package android.server;
import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
@@ -53,6 +53,7 @@
private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
private static final int EVENT_RESTART_BLUETOOTH = 2;
+ private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 3;
// The time (in millisecs) to delay the pairing attempt after the first
// auto pairing attempt fails. We use an exponential delay with
@@ -67,9 +68,10 @@
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
+ String address = null;
switch (msg.what) {
case EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
- String address = (String)msg.obj;
+ address = (String)msg.obj;
if (address != null) {
mBluetoothService.createBond(address);
return;
@@ -78,6 +80,12 @@
case EVENT_RESTART_BLUETOOTH:
mBluetoothService.restart();
break;
+ case EVENT_PAIRING_CONSENT_DELAYED_ACCEPT:
+ address = (String)msg.obj;
+ if (address != null) {
+ mBluetoothService.setPairingConfirmation(address, true);
+ }
+ break;
}
}
};
@@ -166,6 +174,17 @@
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
+ private void onDeviceDisconnectRequested(String deviceObjectPath) {
+ String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
+ if (address == null) {
+ Log.e(TAG, "onDeviceDisconnectRequested: Address of the remote device in null");
+ return;
+ }
+ Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ }
+
private void onCreatePairedDeviceResult(String address, int result) {
address = address.toUpperCase();
if (result == BluetoothDevice.BOND_SUCCESS) {
@@ -228,6 +247,7 @@
addDevice(address, properties);
}
}
+ mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDING);
return;
}
@@ -379,7 +399,32 @@
return address;
}
- private void onRequestConfirmation(String objectPath, int passkey, int nativeData) {
+ private void onRequestPairingConsent(String objectPath, int nativeData) {
+ String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
+ if (address == null) return;
+
+ /* The link key will not be stored if the incoming request has MITM
+ * protection switched on. Unfortunately, some devices have MITM
+ * switched on even though their capabilities are NoInputNoOutput,
+ * so we may get this request many times. Also if we respond immediately,
+ * the other end is unable to handle it. Delay sending the message.
+ */
+ if (mBluetoothService.getBondState().getBondState(address) == BluetoothDevice.BOND_BONDED) {
+ Message message = mHandler.obtainMessage(EVENT_PAIRING_CONSENT_DELAYED_ACCEPT);
+ message.obj = address;
+ mHandler.sendMessageDelayed(message, 1500);
+ return;
+ }
+
+ Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+ intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
+ BluetoothDevice.PAIRING_VARIANT_CONSENT);
+ mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+ return;
+ }
+
+ private void onRequestPasskeyConfirmation(String objectPath, int passkey, int nativeData) {
String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
if (address == null) return;
@@ -387,7 +432,7 @@
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey);
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
- BluetoothDevice.PAIRING_VARIANT_CONFIRMATION);
+ BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
return;
}
@@ -436,6 +481,18 @@
return;
}
+ private void onDisplayPasskey(String objectPath, int passkey, int nativeData) {
+ String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
+ if (address == null) return;
+
+ Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+ intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey);
+ intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
+ BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY);
+ mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+ }
+
private boolean onAgentAuthorize(String objectPath, String deviceUuid) {
String address = mBluetoothService.getAddressFromObjectPath(objectPath);
if (address == null) {
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 53fb03c..6ce0f5f 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -1266,5 +1266,4 @@
private native boolean setPairingConfirmationNative(String address, boolean confirm,
int nativeData);
private native boolean setDevicePropertyBooleanNative(String objectPath, String key, int value);
-
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2f17bbc..f63c2f1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6038,16 +6038,23 @@
* some form of this public, but should think about the API.
*/
Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor) {
- final int width = mRight - mLeft;
- final int height = mBottom - mTop;
+ int width = mRight - mLeft;
+ int height = mBottom - mTop;
- Bitmap bitmap = Bitmap.createBitmap(width, height, quality);
+ final AttachInfo attachInfo = mAttachInfo;
+ final float scale = attachInfo.mApplicationScale;
+ width = (int) ((width * scale) + 0.5f);
+ height = (int) ((height * scale) + 0.5f);
+
+ Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1,
+ height > 0 ? height : 1, quality);
if (bitmap == null) {
throw new OutOfMemoryError();
}
+ bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
+
Canvas canvas;
- final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
canvas = attachInfo.mCanvas;
if (canvas == null) {
@@ -6070,6 +6077,7 @@
computeScroll();
final int restoreCount = canvas.save();
+ canvas.scale(scale, scale);
canvas.translate(-mScrollX, -mScrollY);
// Temporarily remove the dirty mask
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a611d5a..e98fd13 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -732,7 +732,11 @@
}
} else if (digits != null) {
mInput = DigitsKeyListener.getInstance(digits.toString());
- mInputType = inputType;
+ // If no input type was specified, we will default to generic
+ // text, since we can't tell the IME about the set of digits
+ // that was selected.
+ mInputType = inputType != EditorInfo.TYPE_NULL
+ ? inputType : EditorInfo.TYPE_CLASS_TEXT;
} else if (inputType != EditorInfo.TYPE_NULL) {
setInputType(inputType, true);
singleLine = (inputType&(EditorInfo.TYPE_MASK_CLASS
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index fd5271e..50df0f7 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -1,4 +1,25 @@
+/*
+**
+** Copyright 2006, 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_TAG "9patch"
+#define LOG_NDEBUG 1
+
#include <utils/ResourceTypes.h>
+#include <utils/Log.h>
#include "SkCanvas.h"
#include "SkRegion.h"
@@ -62,6 +83,9 @@
if (destDensity == srcDensity || destDensity == 0
|| srcDensity == 0) {
+ LOGV("Drawing unscaled 9-patch: (%g,%g)-(%g,%g)",
+ SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
+ SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom));
NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
} else {
canvas->save();
@@ -74,6 +98,11 @@
bounds.fBottom = SkScalarDiv(bounds.fBottom-bounds.fTop, scale);
bounds.fLeft = bounds.fTop = 0;
+ LOGV("Drawing scaled 9-patch: (%g,%g)-(%g,%g) srcDensity=%d destDensity=%d",
+ SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
+ SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom),
+ srcDensity, destDensity);
+
NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
canvas->restore();
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
index f82053c..ff24a87 100644
--- a/core/jni/android/graphics/NinePatchImpl.cpp
+++ b/core/jni/android/graphics/NinePatchImpl.cpp
@@ -16,8 +16,10 @@
*/
#define LOG_TAG "NinePatch"
+#define LOG_NDEBUG 1
#include <utils/ResourceTypes.h>
+#include <utils/Log.h>
#include "SkBitmap.h"
#include "SkCanvas.h"
@@ -25,7 +27,7 @@
#include "SkPaint.h"
#include "SkUnPreMultiply.h"
-#define USE_TRACEx
+#define USE_TRACE
#ifdef USE_TRACE
static bool gTrace;
@@ -106,6 +108,13 @@
if (canvas && canvas->quickReject(bounds, SkCanvas::kBW_EdgeType)) {
return;
}
+
+ SkPaint defaultPaint;
+ if (NULL == paint) {
+ // matches default dither in NinePatchDrawable.java.
+ defaultPaint.setDither(true);
+ paint = &defaultPaint;
+ }
// if our canvas is GL, draw this as a mesh, which will be faster than
// in parts (which is faster for raster)
@@ -123,10 +132,10 @@
SkASSERT(canvas || outRegion);
-#if 0
+#ifdef USE_TRACE
if (canvas) {
const SkMatrix& m = canvas->getTotalMatrix();
- SkDebugf("ninepatch [%g %g %g] [%g %g %g]\n",
+ LOGV("ninepatch [%g %g %g] [%g %g %g]\n",
SkScalarToFloat(m[0]), SkScalarToFloat(m[1]), SkScalarToFloat(m[2]),
SkScalarToFloat(m[3]), SkScalarToFloat(m[4]), SkScalarToFloat(m[5]));
}
@@ -134,10 +143,10 @@
#ifdef USE_TRACE
if (gTrace) {
- SkDEBUGF(("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height())));
- SkDEBUGF(("======== ninepatch paint bm [%d,%d]\n", bitmap.width(), bitmap.height()));
- SkDEBUGF(("======== ninepatch xDivs [%d,%d]\n", chunk.xDivs[0], chunk.xDivs[1]));
- SkDEBUGF(("======== ninepatch yDivs [%d,%d]\n", chunk.yDivs[0], chunk.yDivs[1]));
+ LOGV("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()));
+ LOGV("======== ninepatch paint bm [%d,%d]\n", bitmap.width(), bitmap.height());
+ LOGV("======== ninepatch xDivs [%d,%d]\n", chunk.xDivs[0], chunk.xDivs[1]);
+ LOGV("======== ninepatch yDivs [%d,%d]\n", chunk.yDivs[0], chunk.yDivs[1]);
}
#endif
@@ -146,7 +155,7 @@
(paint && paint->getXfermode() == NULL && paint->getAlpha() == 0))
{
#ifdef USE_TRACE
- if (gTrace) SkDEBUGF(("======== abort ninepatch draw\n"));
+ if (gTrace) LOGV("======== abort ninepatch draw\n");
#endif
return;
}
@@ -158,11 +167,6 @@
if (bitmap.getPixels() == NULL)
return;
- SkPaint defaultPaint;
- if (NULL == paint) {
- paint = &defaultPaint;
- }
-
const bool hasXfer = paint->getXfermode() != NULL;
SkRect dst;
SkIRect src;
@@ -196,8 +200,8 @@
}
int numFixedYPixelsRemaining = bitmapHeight - numStretchyYPixelsRemaining;
-#if 0
- SkDebugf("NinePatch [%d %d] bounds [%g %g %g %g] divs [%d %d]\n",
+#ifdef USE_TRACE
+ LOGV("NinePatch [%d %d] bounds [%g %g %g %g] divs [%d %d]\n",
bitmap.width(), bitmap.height(),
SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()),
@@ -300,13 +304,13 @@
goto nextDiv;
}
if (canvas) {
-#if 0
- SkDebugf("-- src [%d %d %d %d] dst [%g %g %g %g]\n",
+#ifdef USE_TRACE
+ LOGV("-- src [%d %d %d %d] dst [%g %g %g %g]\n",
src.fLeft, src.fTop, src.width(), src.height(),
SkScalarToFloat(dst.fLeft), SkScalarToFloat(dst.fTop),
SkScalarToFloat(dst.width()), SkScalarToFloat(dst.height()));
if (2 == src.width() && SkIntToScalar(5) == dst.width()) {
- SkDebugf("--- skip patch\n");
+ LOGV("--- skip patch\n");
}
#endif
drawStretchyPatch(canvas, src, dst, bitmap, *paint, initColor,
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 8fe7487..e703ed8 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -45,13 +45,16 @@
static jmethodID method_onDeviceDisappeared;
static jmethodID method_onDeviceCreated;
static jmethodID method_onDeviceRemoved;
+static jmethodID method_onDeviceDisconnectRequested;
static jmethodID method_onCreatePairedDeviceResult;
static jmethodID method_onGetDeviceServiceChannelResult;
static jmethodID method_onRequestPinCode;
static jmethodID method_onRequestPasskey;
-static jmethodID method_onRequestConfirmation;
+static jmethodID method_onRequestPasskeyConfirmation;
+static jmethodID method_onRequestPairingConsent;
+static jmethodID method_onDisplayPasskey;
static jmethodID method_onAgentAuthorize;
static jmethodID method_onAgentCancel;
@@ -84,6 +87,8 @@
"(Ljava/lang/String;)V");
method_onDeviceCreated = env->GetMethodID(clazz, "onDeviceCreated", "(Ljava/lang/String;)V");
method_onDeviceRemoved = env->GetMethodID(clazz, "onDeviceRemoved", "(Ljava/lang/String;)V");
+ method_onDeviceDisconnectRequested = env->GetMethodID(clazz, "onDeviceDisconnectRequested",
+ "(Ljava/lang/String;)V");
method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult",
"(Ljava/lang/String;I)V");
@@ -95,7 +100,11 @@
"(Ljava/lang/String;I)V");
method_onRequestPasskey = env->GetMethodID(clazz, "onRequestPasskey",
"(Ljava/lang/String;I)V");
- method_onRequestConfirmation = env->GetMethodID(clazz, "onRequestConfirmation",
+ method_onRequestPasskeyConfirmation = env->GetMethodID(clazz, "onRequestPasskeyConfirmation",
+ "(Ljava/lang/String;II)V");
+ method_onRequestPairingConsent = env->GetMethodID(clazz, "onRequestPairingConsent",
+ "(Ljava/lang/String;I)V");
+ method_onDisplayPasskey = env->GetMethodID(clazz, "onDisplayPasskey",
"(Ljava/lang/String;II)V");
field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
@@ -227,7 +236,7 @@
const char * get_adapter_path(DBusConnection *conn) {
- DBusMessage *msg, *reply = NULL;
+ DBusMessage *msg = NULL, *reply = NULL;
DBusError err;
const char *device_path = NULL;
int attempt = 0;
@@ -815,6 +824,14 @@
str_array);
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
goto success;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Device",
+ "DisconnectRequested")) {
+ const char *remote_device_path = dbus_message_get_path(msg);
+ env->CallVoidMethod(nat->me,
+ method_onDeviceDisconnectRequested,
+ env->NewStringUTF(remote_device_path));
+ goto success;
}
ret = a2dp_event_filter(msg, env);
@@ -845,9 +862,7 @@
if (dbus_message_is_method_call(msg,
"org.bluez.Agent", "Cancel")) {
-
env->CallVoidMethod(nat->me, method_onAgentCancel);
-
// reply
DBusMessage *reply = dbus_message_new_method_return(msg);
if (!reply) {
@@ -928,6 +943,24 @@
int(msg));
goto success;
} else if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "DisplayPasskey")) {
+ char *object_path;
+ uint32_t passkey;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_UINT32, &passkey,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
+ goto failure;
+ }
+
+ dbus_message_ref(msg); // increment refcount because we pass to java
+ env->CallVoidMethod(nat->me, method_onDisplayPasskey,
+ env->NewStringUTF(object_path),
+ passkey,
+ int(msg));
+ goto success;
+ } else if (dbus_message_is_method_call(msg,
"org.bluez.Agent", "RequestConfirmation")) {
char *object_path;
uint32_t passkey;
@@ -940,12 +973,27 @@
}
dbus_message_ref(msg); // increment refcount because we pass to java
- env->CallVoidMethod(nat->me, method_onRequestConfirmation,
+ env->CallVoidMethod(nat->me, method_onRequestPasskeyConfirmation,
env->NewStringUTF(object_path),
passkey,
int(msg));
goto success;
} else if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "RequestPairingConsent")) {
+ char *object_path;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for RequestPairingConsent() method", __FUNCTION__);
+ goto failure;
+ }
+
+ dbus_message_ref(msg); // increment refcount because we pass to java
+ env->CallVoidMethod(nat->me, method_onRequestPairingConsent,
+ env->NewStringUTF(object_path),
+ int(msg));
+ goto success;
+ } else if (dbus_message_is_method_call(msg,
"org.bluez.Agent", "Release")) {
// reply
DBusMessage *reply = dbus_message_new_method_return(msg);
@@ -981,6 +1029,8 @@
#define BOND_RESULT_AUTH_CANCELED 3
#define BOND_RESULT_REMOTE_DEVICE_DOWN 4
#define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
+#define BOND_RESULT_AUTH_TIMEOUT 6
+#define BOND_RESULT_REPEATED_ATTEMPTS 7
void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
LOGV(__FUNCTION__);
@@ -1026,6 +1076,12 @@
!strcmp(err.message, "Discover in progress")) {
LOGV("... error = %s (%s)\n", err.name, err.message);
result = BOND_RESULT_DISCOVERY_IN_PROGRESS;
+ } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.RepeatedAttempts")) {
+ LOGV("... error = %s (%s)\n", err.name, err.message);
+ result = BOND_RESULT_REPEATED_ATTEMPTS;
+ } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationTimeout")) {
+ LOGV("... error = %s (%s)\n", err.name, err.message);
+ result = BOND_RESULT_AUTH_TIMEOUT;
} else {
LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
result = BOND_RESULT_ERROR;
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index de921f1..0b71acb 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -455,8 +455,8 @@
}
if (!reply) {
- LOGE("%s: Cannot create message reply to RequestConfirmation to "
- "D-Bus\n", __FUNCTION__);
+ LOGE("%s: Cannot create message reply to RequestPasskeyConfirmation or"
+ "RequestPairingConsent to D-Bus\n", __FUNCTION__);
dbus_message_unref(msg);
return JNI_FALSE;
}
diff --git a/docs/html/sdk/android-1.6-highlights.jd b/docs/html/sdk/android-1.6-highlights.jd
index 882f117..74dcd9f 100644
--- a/docs/html/sdk/android-1.6-highlights.jd
+++ b/docs/html/sdk/android-1.6-highlights.jd
@@ -5,7 +5,8 @@
<style type="text/css">
-#jd-content div.screenshot {
+#jd-content div.screenshot,
+#jd-content div.video {
float:right;
clear:right;
padding:15px 70px;
@@ -13,11 +14,25 @@
font-weight:bold;
line-height:1.7em;
}
+#jd-content div.video {
+ padding-top:0;
+ margin-top:-15px;
+}
#jd-content div.screenshot img {
margin:0;
}
</style>
+<div class="video">
+<object width="293" height="180">
+<param name="movie" value="http://www.youtube.com/v/MBRFkLKRwFw&hl=en&fs=1&"></param>
+<param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param>
+<embed src="http://www.youtube.com/v/MBRFkLKRwFw&hl=en&fs=1&" type="application/x-shockwave-flash"
+allowscriptaccess="always" allowfullscreen="true" width="293" height="180"></embed>
+</object>
+</div>
+
+
<p>The Android 1.6 platform introduces new features for users and developers.
This page provides an overview of some new features and technologies.</p>
@@ -29,7 +44,7 @@
-<h2 id="UserFeatures">New User Features</h2>
+<h2 id="UserFeatures" style="clear:right">New User Features</h2>
<!-- screenshots float right -->
diff --git a/docs/html/videos/index.jd b/docs/html/videos/index.jd
index c9c88cf..ddb9f86 100644
--- a/docs/html/videos/index.jd
+++ b/docs/html/videos/index.jd
@@ -37,10 +37,12 @@
* Each playlist ID is paired with a custom video description.
*/
var featured = {
+// Android 1.6 Release
+ 'MBRFkLKRwFw' : "The Android 1.6 release includes new features and improvements to the Android platform. Here's an introduction to what's new in Android 1.6.",
// How to Make your Android UI Fast..
'N6YdwzAvwOA' : "Make your user interface fast, with more efficient AdapterViews, better bitmap scaling, faster redrawing, ViewStub layouts, fewer Views, and more.",
// Coding for Life: Battery Life
- 'OUemfrKe65c' : "Learn what kinds of operations consume the most battery and how you can reduce your usage, with tips for parsing and zipping data, using wakelocks, and running a Service.",
+// 'OUemfrKe65c' : "Learn what kinds of operations consume the most battery and how you can reduce your usage, with tips for parsing and zipping data, using wakelocks, and running a Service.",
// How Do I Code Thee?
'GARMe7Km_gk' : "If you'd like to augment your Android applications with pieces written in JavaScript or native code, watch this video."
};
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 1755d4f..30cef67 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -56,7 +56,8 @@
*/
public class BitmapDrawable extends Drawable {
- private static final int DEFAULT_PAINT_FLAGS = Paint.FILTER_BITMAP_FLAG;
+ private static final int DEFAULT_PAINT_FLAGS =
+ Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
private BitmapState mBitmapState;
private Bitmap mBitmap;
private final Rect mDstRect = new Rect(); // Gravity.apply() sets this
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 6b50406..af1a289 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -19,12 +19,23 @@
import android.graphics.*;
public class DrawableContainer extends Drawable implements Drawable.Callback {
-
+
+ /**
+ * To be proper, we should have a getter for dither (and alpha, etc.)
+ * so that proxy classes like this can save/restore their delegates'
+ * values, but we don't have getters. Since we do have setters
+ * (e.g. setDither), which this proxy forwards on, we have to have some
+ * default/initial setting.
+ *
+ * The initial setting for dither is now true, since it almost always seems
+ * to improve the quality at negligible cost.
+ */
+ private static final boolean DEFAULT_DITHER = true;
private DrawableContainerState mDrawableContainerState;
private Drawable mCurrDrawable;
private int mAlpha = 0xFF;
private ColorFilter mColorFilter;
- private boolean mDither;
+ private boolean mDither = DEFAULT_DITHER;
private int mCurIndex = -1;
private boolean mMutated;
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 1b1ea94..997efb8 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -21,6 +21,7 @@
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.TypedValue;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -36,6 +37,8 @@
*
*/
public class NinePatchDrawable extends Drawable {
+ // dithering helps a lot, and is pretty cheap, so default is true
+ private static final boolean DEFAULT_DITHER = true;
private NinePatchState mNinePatchState;
private NinePatch mNinePatch;
private Rect mPadding;
@@ -101,7 +104,11 @@
mNinePatch = state.mNinePatch;
mPadding = state.mPadding;
mTargetDensity = state.mTargetDensity;
- if (state.mDither) setDither(state.mDither);
+ if (DEFAULT_DITHER != state.mDither) {
+ // avoid calling the setter unless we need to, since it does a
+ // lazy allocation of a paint
+ setDither(state.mDither);
+ }
if (mNinePatch != null) {
computeBitmapSize();
}
@@ -164,6 +171,11 @@
@Override
public void draw(Canvas canvas) {
+ if (false) {
+ float[] pts = new float[2];
+ canvas.getMatrix().mapPoints(pts);
+ Log.v("9patch", "Drawing 9-patch @ " + pts[0] + "," + pts[1] + ": " + getBounds());
+ }
mNinePatch.draw(canvas, getBounds(), mPaint);
}
@@ -215,7 +227,8 @@
}
final boolean dither = a.getBoolean(
- com.android.internal.R.styleable.NinePatchDrawable_dither, false);
+ com.android.internal.R.styleable.NinePatchDrawable_dither,
+ DEFAULT_DITHER);
final BitmapFactory.Options options = new BitmapFactory.Options();
if (dither) {
options.inDither = false;
@@ -251,12 +264,10 @@
a.recycle();
}
-
public Paint getPaint() {
if (mPaint == null) {
mPaint = new Paint();
- // dithering helps a lot, and is pretty cheap, so default on
- mPaint.setDither(true);
+ mPaint.setDither(DEFAULT_DITHER);
}
return mPaint;
}
@@ -327,7 +338,7 @@
int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
NinePatchState(NinePatch ninePatch, Rect padding) {
- this(ninePatch, padding, false);
+ this(ninePatch, padding, DEFAULT_DITHER);
}
NinePatchState(NinePatch ninePatch, Rect rect, boolean dither) {
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index a8274b1..59cb226 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -50,6 +50,17 @@
* @attr ref android.R.styleable#DrawableStates_state_pressed
*/
public class StateListDrawable extends DrawableContainer {
+ /**
+ * To be proper, we should have a getter for dither (and alpha, etc.)
+ * so that proxy classes like this can save/restore their delegates'
+ * values, but we don't have getters. Since we do have setters
+ * (e.g. setDither), which this proxy forwards on, we have to have some
+ * default/initial setting.
+ *
+ * The initial setting for dither is now true, since it almost always seems
+ * to improve the quality at negligible cost.
+ */
+ private static final boolean DEFAULT_DITHER = true;
private final StateListState mStateListState;
private boolean mMutated;
@@ -105,7 +116,8 @@
mStateListState.setConstantSize(a.getBoolean(
com.android.internal.R.styleable.StateListDrawable_constantSize, false));
- setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither, false));
+ setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither,
+ DEFAULT_DITHER));
a.recycle();
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 59ecde6..93b7a3a 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -10,13 +10,21 @@
MediaRecorderClient.cpp \
MediaPlayerService.cpp \
MetadataRetrieverClient.cpp \
- StagefrightPlayer.cpp \
TestPlayerStub.cpp \
VorbisPlayer.cpp \
VorbisMetadataRetriever.cpp \
MidiMetadataRetriever.cpp \
MidiFile.cpp
+ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
+
+LOCAL_SRC_FILES += \
+ StagefrightPlayer.cpp
+
+LOCAL_CFLAGS += -DBUILD_WITH_FULL_STAGEFRIGHT=1
+
+endif
+
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
LOCAL_LDLIBS += -ldl -lpthread
endif
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 8998f10..8b1c9dc 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -602,11 +602,13 @@
}
static player_type getDefaultPlayerType() {
+#if BUILD_WITH_FULL_STAGEFRIGHT
char value[PROPERTY_VALUE_MAX];
if (property_get("media.stagefright.enable-player", value, NULL)
&& (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
return STAGEFRIGHT_PLAYER;
}
+#endif
return PV_PLAYER;
}
@@ -684,10 +686,12 @@
LOGV(" create VorbisPlayer");
p = new VorbisPlayer();
break;
+#if BUILD_WITH_FULL_STAGEFRIGHT
case STAGEFRIGHT_PLAYER:
LOGV(" create StagefrightPlayer");
p = new StagefrightPlayer;
break;
+#endif
case TEST_PLAYER:
LOGV("Create Test Player stub");
p = new TestPlayerStub();
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 22769ba..79a32b5 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -2,6 +2,19 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ ESDS.cpp \
+ MediaBuffer.cpp \
+ MediaBufferGroup.cpp \
+ MediaDefs.cpp \
+ MediaSource.cpp \
+ MetaData.cpp \
+ OMXCodec.cpp \
+ Utils.cpp \
+ OMXClient.cpp
+
+ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
+
+LOCAL_SRC_FILES += \
AMRExtractor.cpp \
CachingDataSource.cpp \
DataSource.cpp \
@@ -9,28 +22,21 @@
HTTPDataSource.cpp \
HTTPStream.cpp \
JPEGSource.cpp \
+ MediaExtractor.cpp \
MP3Extractor.cpp \
MPEG4Extractor.cpp \
MPEG4Writer.cpp \
- MediaBuffer.cpp \
- MediaBufferGroup.cpp \
- MediaDefs.cpp \
- MediaExtractor.cpp \
MediaPlayerImpl.cpp \
- MediaSource.cpp \
- MetaData.cpp \
MmapSource.cpp \
- OMXCodec.cpp \
SampleTable.cpp \
ShoutcastSource.cpp \
TimeSource.cpp \
TimedEventQueue.cpp \
- Utils.cpp \
AudioPlayer.cpp \
- ESDS.cpp \
- OMXClient.cpp \
string.cpp
+endif
+
LOCAL_C_INCLUDES:= \
$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
$(TOP)/external/opencore/android
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 56a279a..13db005 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -16,33 +16,31 @@
package com.android.providers.settings;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
+import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
-import java.io.EOFException;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.zip.CRC32;
import android.backup.BackupDataInput;
import android.backup.BackupDataOutput;
import android.backup.BackupHelperAgent;
-import android.bluetooth.BluetoothAdapter;
-import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
-import android.media.AudioManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@@ -72,7 +70,6 @@
private static final String TAG = "SettingsBackupAgent";
- private static final int COLUMN_ID = 0;
private static final int COLUMN_NAME = 1;
private static final int COLUMN_VALUE = 2;
@@ -83,12 +80,12 @@
};
private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
+ private static final String FILE_WIFI_SUPPLICANT_TEMPLATE =
+ "/system/etc/wifi/wpa_supplicant.conf";
// the key to store the WIFI data under, should be sorted as last, so restore happens last.
// use very late unicode character to quasi-guarantee last sort position.
- private static final String KEY_WIFI_SUPPLICANT = "\uffeeWIFI";
-
- private static final String FILE_BT_ROOT = "/data/misc/hcid/";
+ private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
private SettingsHelper mSettingsHelper;
@@ -105,7 +102,7 @@
byte[] secureSettingsData = getSecureSettings();
byte[] syncProviders = mSettingsHelper.getSyncProviders();
byte[] locale = mSettingsHelper.getLocaleData();
- byte[] wifiData = getFileData(FILE_WIFI_SUPPLICANT);
+ byte[] wifiData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
long[] stateChecksums = readOldChecksums(oldState);
@@ -127,9 +124,6 @@
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
-
- enableBluetooth(false);
-
while (data.readNextHeader()) {
final String key = data.getKey();
final int size = data.getDataSize();
@@ -140,7 +134,7 @@
restoreSettings(data, Settings.Secure.CONTENT_URI);
} else if (KEY_WIFI_SUPPLICANT.equals(key)) {
int retainedWifiState = enableWifi(false);
- restoreFile(FILE_WIFI_SUPPLICANT, data);
+ restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, data);
FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
FileUtils.S_IRUSR | FileUtils.S_IWUSR |
FileUtils.S_IRGRP | FileUtils.S_IWGRP,
@@ -319,19 +313,27 @@
return result;
}
- private byte[] getFileData(String filename) {
+ private byte[] getWifiSupplicant(String filename) {
try {
File file = new File(filename);
if (file.exists()) {
- byte[] bytes = new byte[(int) file.length()];
- FileInputStream fis = new FileInputStream(file);
- int offset = 0;
- int got = 0;
- do {
- got = fis.read(bytes, offset, bytes.length - offset);
- if (got > 0) offset += got;
- } while (offset < bytes.length && got > 0);
- return bytes;
+ BufferedReader br = new BufferedReader(new FileReader(file));
+ StringBuffer relevantLines = new StringBuffer();
+ boolean started = false;
+ String line;
+ while ((line = br.readLine()) != null) {
+ if (!started && line.startsWith("network")) {
+ started = true;
+ }
+ if (started) {
+ relevantLines.append(line).append("\n");
+ }
+ }
+ if (relevantLines.length() > 0) {
+ return relevantLines.toString().getBytes();
+ } else {
+ return EMPTY_DATA;
+ }
} else {
return EMPTY_DATA;
}
@@ -341,18 +343,39 @@
}
}
- private void restoreFile(String filename, BackupDataInput data) {
+ private void restoreWifiSupplicant(String filename, BackupDataInput data) {
byte[] bytes = new byte[data.getDataSize()];
if (bytes.length <= 0) return;
try {
data.readEntityData(bytes, 0, bytes.length);
- FileOutputStream fos = new FileOutputStream(filename);
+ File supplicantFile = new File(FILE_WIFI_SUPPLICANT);
+ if (supplicantFile.exists()) supplicantFile.delete();
+ copyWifiSupplicantTemplate();
+
+ FileOutputStream fos = new FileOutputStream(filename, true);
+ fos.write("\n".getBytes());
fos.write(bytes);
} catch (IOException ioe) {
Log.w(TAG, "Couldn't restore " + filename);
}
}
+ private void copyWifiSupplicantTemplate() {
+ try {
+ BufferedReader br = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT_TEMPLATE));
+ BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_WIFI_SUPPLICANT));
+ char[] temp = new char[1024];
+ int size;
+ while ((size = br.read(temp)) > 0) {
+ bw.write(temp, 0, size);
+ }
+ bw.close();
+ br.close();
+ } catch (IOException ioe) {
+ Log.w(TAG, "Couldn't copy wpa_supplicant file");
+ }
+ }
+
/**
* Write an int in BigEndian into the byte array.
* @param out byte array
@@ -391,15 +414,4 @@
}
return WifiManager.WIFI_STATE_UNKNOWN;
}
-
- private void enableBluetooth(boolean enable) {
- BluetoothAdapter bt = (BluetoothAdapter) getSystemService(Context.BLUETOOTH_SERVICE);
- if (bt != null) {
- if (!enable) {
- bt.disable();
- } else {
- bt.enable();
- }
- }
- }
}