OSDN Git Service

auto import from //branches/cupcake/...@127101
authorThe Android Open Source Project <initial-contribution@android.com>
Tue, 20 Jan 2009 22:03:58 +0000 (14:03 -0800)
committerThe Android Open Source Project <initial-contribution@android.com>
Tue, 20 Jan 2009 22:03:58 +0000 (14:03 -0800)
130 files changed:
Android.mk
api/current.xml
camera/libcameraservice/CameraService.cpp
core/java/android/app/SearchDialog.java
core/java/android/bluetooth/BluetoothA2dp.java
core/java/android/bluetooth/BluetoothHeadset.java
core/java/android/bluetooth/IBluetoothA2dp.aidl
core/java/android/bluetooth/IBluetoothHeadset.aidl
core/java/android/content/Context.java
core/java/android/gadget/GadgetHost.java [new file with mode: 0644]
core/java/android/gadget/GadgetHostView.java [new file with mode: 0644]
core/java/android/gadget/GadgetInfo.aidl [moved from core/java/android/bluetooth/IBluetoothHeadsetCallback.aidl with 55% similarity]
core/java/android/gadget/GadgetInfo.java [new file with mode: 0644]
core/java/android/gadget/GadgetManager.java [new file with mode: 0644]
core/java/android/gadget/package.html [new file with mode: 0644]
core/java/android/hardware/Camera.java
core/java/android/inputmethodservice/InputMethodService.java
core/java/android/provider/Settings.java
core/java/android/provider/UserDictionary.java [new file with mode: 0644]
core/java/android/server/BluetoothA2dpService.java
core/java/android/speech/srec/Recognizer.java
core/java/android/speech/srec/WaveHeader.java
core/java/android/view/ViewRoot.java
core/java/android/view/inputmethod/InputMethodManager.java
core/java/android/webkit/CallbackProxy.java
core/java/android/webkit/TextDialog.java
core/java/android/webkit/WebView.java
core/java/android/widget/AutoCompleteTextView.java
core/java/android/widget/MediaController.java
core/java/android/widget/VideoView.java
core/java/com/android/internal/gadget/IGadgetService.aidl [new file with mode: 0644]
core/java/com/android/internal/gadget/package.html [new file with mode: 0644]
core/java/com/android/internal/os/HandlerCaller.java
core/java/com/android/internal/view/menu/IconMenuItemView.java
core/java/com/android/internal/view/menu/ListMenuItemView.java
core/java/com/android/internal/view/menu/MenuBuilder.java
core/java/com/android/internal/widget/NumberPicker.java
core/jni/android_hardware_Camera.cpp
core/res/AndroidManifest.xml
core/res/res/drawable/btn_check_off_longpress.png [deleted file]
core/res/res/drawable/btn_check_on_longpress.png [deleted file]
core/res/res/drawable/emo_im_angel.png [new file with mode: 0644]
core/res/res/drawable/emo_im_cool.png [new file with mode: 0644]
core/res/res/drawable/emo_im_crying.png [new file with mode: 0644]
core/res/res/drawable/emo_im_embarrassed.png [new file with mode: 0644]
core/res/res/drawable/emo_im_foot_in_mouth.png [new file with mode: 0644]
core/res/res/drawable/emo_im_happy.png [new file with mode: 0644]
core/res/res/drawable/emo_im_kissing.png [new file with mode: 0644]
core/res/res/drawable/emo_im_laughing.png [new file with mode: 0644]
core/res/res/drawable/emo_im_lips_are_sealed.png [new file with mode: 0644]
core/res/res/drawable/emo_im_money_mouth.png [new file with mode: 0644]
core/res/res/drawable/emo_im_sad.png [new file with mode: 0644]
core/res/res/drawable/emo_im_surprised.png [new file with mode: 0644]
core/res/res/drawable/emo_im_tongue_sticking_out.png [new file with mode: 0644]
core/res/res/drawable/emo_im_undecided.png [new file with mode: 0644]
core/res/res/drawable/emo_im_winking.png [new file with mode: 0644]
core/res/res/drawable/emo_im_wtf.png [new file with mode: 0644]
core/res/res/drawable/emo_im_yelling.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_account_list.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_allfriends.png [new file with mode: 0755]
core/res/res/drawable/ic_menu_archive.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_attachment.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_back.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_block.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_blocked_user.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_cc.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_chat_dashboard.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_clear_playlist.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_compose.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_emoticons.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_end_conversation.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_forward.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_friendslist.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_goto.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_home.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_invite.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_mark.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_play_clip.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_star.png [new file with mode: 0755]
core/res/res/drawable/ic_menu_start_conversation.png [new file with mode: 0644]
core/res/res/drawable/ic_menu_stop.png [new file with mode: 0644]
core/res/res/drawable/ic_power.png [deleted file]
core/res/res/layout/js_prompt.xml [new file with mode: 0644]
core/res/res/layout/zoom_controls.xml
core/res/res/layout/zoom_magnify.xml
core/res/res/values-cs/strings.xml
core/res/res/values-de/strings.xml
core/res/res/values-es/strings.xml
core/res/res/values-fr/strings.xml
core/res/res/values-it/strings.xml
core/res/res/values-ja/strings.xml
core/res/res/values-nl/strings.xml
core/res/res/values-pl/strings.xml
core/res/res/values-ru/strings.xml
core/res/res/values-zh-rCN/strings.xml
core/res/res/values-zh-rTW/strings.xml
core/res/res/values/attrs.xml
core/res/res/values/public.xml
core/res/res/values/strings.xml
core/res/res/values/styles.xml
core/res/waitingroom/screen_background_blue-land.png [deleted file]
core/res/waitingroom/screen_background_green-land.png [deleted file]
core/res/waitingroom/screen_background_white-land.png [deleted file]
include/media/AudioRecord.h
include/media/AudioTrack.h
include/media/ToneGenerator.h
include/private/media/AudioTrackShared.h
include/ui/Overlay.h
include/utils/Parcel.h
libs/audioflinger/A2dpAudioInterface.cpp
libs/surfaceflinger/LayerBuffer.h
libs/ui/Camera.cpp
libs/ui/Overlay.cpp
libs/utils/Parcel.cpp
media/libmedia/AudioRecord.cpp
media/libmedia/AudioTrack.cpp
services/java/com/android/server/GadgetService.java [new file with mode: 0644]
services/java/com/android/server/SystemServer.java
services/java/com/android/server/WifiWatchdogService.java
tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java
tests/GadgetHost/Android.mk [new file with mode: 0644]
tests/GadgetHost/AndroidManifest.xml [new file with mode: 0644]
tests/GadgetHost/res/layout/gadget_host.xml [new file with mode: 0644]
tests/GadgetHost/res/layout/test_gadget.xml [new file with mode: 0644]
tests/GadgetHost/res/values/strings.xml [new file with mode: 0644]
tests/GadgetHost/src/com/android/gadgethost/GadgetContainerView.java [new file with mode: 0644]
tests/GadgetHost/src/com/android/gadgethost/GadgetHostActivity.java [new file with mode: 0644]
tests/GadgetHost/src/com/android/gadgethost/GadgetPickActivity.java [new file with mode: 0644]
tests/GadgetHost/src/com/android/gadgethost/TestGadgetProvider.java [new file with mode: 0644]
tools/aapt/ResourceTable.cpp

index 18051aa..d67a21e 100644 (file)
@@ -71,7 +71,6 @@ LOCAL_SRC_FILES += \
        core/java/android/bluetooth/IBluetoothDevice.aidl \
        core/java/android/bluetooth/IBluetoothDeviceCallback.aidl \
        core/java/android/bluetooth/IBluetoothHeadset.aidl \
-       core/java/android/bluetooth/IBluetoothHeadsetCallback.aidl \
        core/java/android/content/ISyncAdapter.aidl \
        core/java/android/content/ISyncContext.aidl \
        core/java/android/content/pm/IPackageDataObserver.aidl \
@@ -98,6 +97,7 @@ LOCAL_SRC_FILES += \
        core/java/android/view/IWindowManager.aidl \
        core/java/android/view/IWindowSession.aidl \
        core/java/com/android/internal/app/IBatteryStats.aidl \
+       core/java/com/android/internal/gadget/IGadgetService.aidl \
        core/java/com/android/internal/view/IInputContext.aidl \
        core/java/com/android/internal/view/IInputContextCallback.aidl \
        core/java/com/android/internal/view/IInputMethod.aidl \
@@ -165,6 +165,7 @@ aidl_files := \
        frameworks/base/core/java/android/content/Intent.aidl \
        frameworks/base/core/java/android/content/SyncStats.aidl \
        frameworks/base/core/java/android/content/res/Configuration.aidl \
+       frameworks/base/core/java/android/gadget/GadgetInfo.aidl \
        frameworks/base/core/java/android/net/Uri.aidl \
        frameworks/base/core/java/android/os/Bundle.aidl \
        frameworks/base/core/java/android/os/ParcelFileDescriptor.aidl \
@@ -421,4 +422,8 @@ include $(BUILD_JAVA_LIBRARY)
 # Include subdirectory makefiles
 # ============================================================
 
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
 include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
index f6fa67d..e183217 100644 (file)
  visibility="public"
 >
 </field>
-<field name="gallery_thumb"
+<field name="emo_im_angel"
  type="int"
  transient="false"
  volatile="false"
- value="17301532"
+ value="17301668"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_cool"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301669"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_crying"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301670"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_embarrassed"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301671"
  static="true"
  final="true"
  deprecated="not deprecated"
  visibility="public"
 >
 </field>
-<field name="ic_btn_search"
+<field name="emo_im_foot_in_mouth"
  type="int"
  transient="false"
  volatile="false"
- value="17301662"
+ value="17301672"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_happy"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301673"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_kissing"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301674"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_laughing"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301675"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_lips_are_sealed"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301676"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_money_mouth"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301677"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_sad"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301678"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_surprised"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301679"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_tongue_sticking_out"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301680"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_undecided"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301681"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_winking"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301682"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_wtf"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301683"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="emo_im_yelling"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301684"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="gallery_thumb"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301532"
  static="true"
  final="true"
  deprecated="not deprecated"
  visibility="public"
 >
 </field>
-<field name="ic_dialog_menu_generic"
- type="int"
- transient="false"
- volatile="false"
- value="17301664"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="ic_input_add"
  type="int"
  transient="false"
  visibility="public"
 >
 </field>
-<field name="ic_menu_login"
- type="int"
- transient="false"
- volatile="false"
- value="17301665"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="ic_menu_manage"
  type="int"
  transient="false"
  visibility="public"
 >
 </field>
-<field name="ic_menu_notifications"
- type="int"
- transient="false"
- volatile="false"
- value="17301667"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="ic_menu_preferences"
  type="int"
  transient="false"
  visibility="public"
 >
 </field>
-<field name="ic_menu_refresh"
- type="int"
- transient="false"
- volatile="false"
- value="17301666"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="ic_menu_report_image"
  type="int"
  transient="false"
 <parameter name="cb" type="android.hardware.Camera.ErrorCallback">
 </parameter>
 </method>
+<method name="setOneShotPreviewCallback"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cb" type="android.hardware.Camera.PreviewCallback">
+</parameter>
+</method>
 <method name="setParameters"
  return="void"
  abstract="false"
  visibility="public"
 >
 </method>
+<method name="getMaxWidth"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getWindow"
  return="android.app.Dialog"
  abstract="false"
 <parameter name="outInsets" type="android.inputmethodservice.InputMethodService.Insets">
 </parameter>
 </method>
+<method name="onConfigureWindow"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="win" type="android.view.Window">
+</parameter>
+<parameter name="isFullscreen" type="boolean">
+</parameter>
+<parameter name="isCandidatesOnly" type="boolean">
+</parameter>
+</method>
 <method name="onCreateBackgroundDrawable"
  return="android.graphics.drawable.Drawable"
  abstract="false"
 <parameter name="restarting" type="boolean">
 </parameter>
 </method>
+<method name="onUnbindInput"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onUpdateCursor"
  return="void"
  abstract="false"
index 33987c3..36c5ada 100644 (file)
@@ -166,22 +166,26 @@ CameraService::Client::Client(const sp<CameraService>& cameraService,
 
 status_t CameraService::Client::checkPid()
 {
-    // zero means the interface is not locked down
-    if (mClientPid == 0) return NO_ERROR;
-    return (int) mClientPid == IPCThreadState::self()->getCallingPid() ? NO_ERROR : -EBUSY;
+    if (mClientPid == IPCThreadState::self()->getCallingPid()) return NO_ERROR;
+    LOGW("Attempt to use locked camera from different process");
+    return -EBUSY;
 }
 
 status_t CameraService::Client::lock()
 {
-    // lock camera to this client
-    status_t result = checkPid();
-    if (result == NO_ERROR) mClientPid = IPCThreadState::self()->getCallingPid();
-    return result;
+    // lock camera to this client if the the camera is unlocked
+    if (mClientPid == 0) {
+        mClientPid = IPCThreadState::self()->getCallingPid();
+        return NO_ERROR;
+    }
+    // returns NO_ERROR if the client already owns the camera, -EBUSY otherwise
+    return checkPid();
 }
 
 status_t CameraService::Client::unlock()
 {
     // allow anyone to use camera
+    LOGV("unlock");
     status_t result = checkPid();
     if (result == NO_ERROR) mClientPid = 0;
     return result;
@@ -189,12 +193,29 @@ status_t CameraService::Client::unlock()
 
 status_t CameraService::Client::connect(const sp<ICameraClient>& client)
 {
-    // remove old client
-    LOGV("connect new client to existing camera");
-    Mutex::Autolock _l(mLock);
-    mCameraClient = client;
-    mClientPid = IPCThreadState::self()->getCallingPid();
-    mFrameCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+    // connect a new process to the camera
+    LOGV("connect");
+
+    // hold a reference to the old client or we will deadlock if the client is
+    // in the same process and we hold the lock when we remove the reference
+    sp<ICameraClient> oldClient;
+    {
+        Mutex::Autolock _l(mLock);
+        if (mClientPid != 0) {
+            LOGW("Tried to connect to locked camera");
+            return -EBUSY;
+        }
+        oldClient = mCameraClient;
+
+        // did the client actually change?
+        if (client->asBinder() == mCameraClient->asBinder()) return NO_ERROR;
+
+        LOGV("connect new process to existing camera client");
+        mCameraClient = client;
+        mClientPid = IPCThreadState::self()->getCallingPid();
+        mFrameCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+    }
+
     return NO_ERROR;
 }
 
@@ -210,7 +231,7 @@ static void *unregister_surface(void *arg)
 
 CameraService::Client::~Client()
 {
-    // spin down hardware
+    // tear down client
     LOGD("Client E destructor");
     if (mSurface != 0) {
 #if HAVE_ANDROID_OS
@@ -227,6 +248,8 @@ CameraService::Client::~Client()
 #endif
     }
 
+    // make sure we tear down the hardware
+    mClientPid = IPCThreadState::self()->getCallingPid();
     disconnect();
     LOGD("Client X destructor");
 }
@@ -235,7 +258,12 @@ void CameraService::Client::disconnect()
 {
     LOGD("Client E disconnect");
     Mutex::Autolock lock(mLock);
+    if (mClientPid == 0) {
+        LOGV("camera is unlocked, don't tear down hardware");
+        return;
+    }
     if (checkPid() != NO_ERROR) return;
+
     mCameraService->removeClient(mCameraClient);
     if (mHardware != 0) {
         // Before destroying mHardware, we must make sure it's in the
index 495156e..5af08f7 100644 (file)
@@ -1129,6 +1129,15 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
         }
         
         /**
+         * We never allow ACTV to automatically replace the text, since we use "jamSuggestionQuery"
+         * to do that.  There's no point in letting ACTV do this here, because in the search UI,
+         * as soon as we click a suggestion, we're going to start shutting things down.
+         */
+        @Override
+        public void replaceText(CharSequence text) {
+        }
+        
+        /**
          * We always return true, so that the effective threshold is "zero".  This allows us
          * to provide "null" suggestions such as "just show me some recent entries".
          */
index 022a87c..b0b0154 100644 (file)
@@ -72,6 +72,12 @@ public class BluetoothA2dp {
     /** Playing implies connected */
     public static final int STATE_PLAYING    = 4;
 
+    /** Default priority for a2dp devices that should allow incoming
+     * connections */
+    public static final int PRIORITY_AUTO = 100;
+    /** Default priority for a2dp devices that should not allow incoming
+     * connections */
+    public static final int PRIORITY_OFF = 0;
     private final IBluetoothA2dp mService;
     private final Context mContext;
 
@@ -158,6 +164,66 @@ public class BluetoothA2dp {
         }
     }
 
+    /**
+     * Set priority of a2dp sink.
+     * Priority is a non-negative integer. By default paired sinks will have
+     * a priority of PRIORITY_AUTO, and unpaired headset PRIORITY_NONE (0).
+     * Sinks with priority greater than zero will accept incoming connections
+     * (if no sink is currently connected).
+     * Priority for unpaired sink must be PRIORITY_NONE.
+     * @param address Paired sink
+     * @param priority Integer priority, for example PRIORITY_AUTO or
+     *                 PRIORITY_NONE
+     * @return Result code, negative indicates an error
+     */
+    public int setSinkPriority(String address, int priority) {
+        try {
+            return mService.setSinkPriority(address, priority);
+        } catch (RemoteException e) {
+            Log.w(TAG, "", e);
+            return BluetoothError.ERROR_IPC;
+        }
+    }
+
+    /**
+     * Get priority of a2dp sink.
+     * @param address Sink
+     * @return non-negative priority, or negative error code on error.
+     */
+    public int getSinkPriority(String address) {
+        try {
+            return mService.getSinkPriority(address);
+        } catch (RemoteException e) {
+            Log.w(TAG, "", e);
+            return BluetoothError.ERROR_IPC;
+        }
+    }
+
+    /**
+     * Check class bits for possible A2DP Sink support.
+     * This is a simple heuristic that tries to guess if a device with the
+     * given class bits might be a A2DP Sink. It is not accurate for all
+     * devices. It tries to err on the side of false positives.
+     * @return True if this device might be a A2DP sink
+     */
+    public static boolean doesClassMatchSink(int btClass) {
+        if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
+            return true;
+        }
+        // By the A2DP spec, sinks must indicate the RENDER service.
+        // However we found some that do not (Chordette). So lets also
+        // match on some other class bits.
+        switch (BluetoothClass.Device.getDevice(btClass)) {
+        case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
+        case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
+        case BluetoothClass.Device.AUDIO_VIDEO_LOUDSPEAKER:
+        case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+            return true;
+        default:
+            return false;
+        }
+    }
+
     /** Helper for converting a state to a string.
      * For debug use only - strings are not internationalized.
      * @hide
index 905173e..c315271 100644 (file)
@@ -57,7 +57,6 @@ public class BluetoothHeadset {
     private IBluetoothHeadset mService;
     private final Context mContext;
     private final ServiceListener mServiceListener;
-    private ConnectHeadsetCallback mConnectHeadsetCallback;
 
     /** There was an error trying to obtain the state */
     public static final int STATE_ERROR        = -1;
@@ -73,6 +72,11 @@ public class BluetoothHeadset {
     /** Connection cancelled before completetion. */
     public static final int RESULT_CANCELLED = 2;
 
+    /** Default priority for headsets that should be auto-connected */
+    public static final int PRIORITY_AUTO = 100;
+    /** Default priority for headsets that should not be auto-connected */
+    public static final int PRIORITY_OFF = 0;
+
     /**
      * An interface for notifying BluetoothHeadset IPC clients when they have
      * been connected to the BluetoothHeadset service.
@@ -97,14 +101,6 @@ public class BluetoothHeadset {
     }
 
     /**
-     * Interface for connectHeadset() callback.
-     * This callback can occur in the Binder thread.
-     */
-    public interface ConnectHeadsetCallback {
-        public void onConnectHeadsetResult(String address, int resultCode);
-    }
-
-    /**
      * Create a BluetoothHeadset proxy object.
      */
     public BluetoothHeadset(Context context, ServiceListener l) {
@@ -175,24 +171,18 @@ public class BluetoothHeadset {
      * Request to initiate a connection to a headset.
      * This call does not block. Fails if a headset is already connecting
      * or connected.
-     * Will connect to the last connected headset if address is null.
-     * onConnectHeadsetResult() of your ConnectHeadsetCallback will be called
-     * on completition.
-     * @param address The Bluetooth Address to connect to, or null to connect
-     *                to the last connected headset.
-     * @param callback Callback on result. Not called if false is returned. Can
-     *                be null.
-     *                to the last connected headset.
+     * Initiates auto-connection if address is null. Tries to connect to all
+     * devices with priority greater than PRIORITY_AUTO in descending order.
+     * @param address The Bluetooth Address to connect to, or null to
+     *                auto-connect to the last connected headset.
      * @return        False if there was a problem initiating the connection
-     *                procedure, and your callback will not be used. True if
-     *                the connection procedure was initiated, in which case
-     *                your callback is guarenteed to be called.
+     *                procedure, and no further HEADSET_STATE_CHANGED intents
+     *                will be expected.
      */
-    public boolean connectHeadset(String address, ConnectHeadsetCallback callback) {
+    public boolean connectHeadset(String address) {
         if (mService != null) {
             try {
-                if (mService.connectHeadset(address, mHeadsetCallback)) {
-                    mConnectHeadsetCallback = callback;
+                if (mService.connectHeadset(address)) {
                     return true;
                 }
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
@@ -273,6 +263,71 @@ public class BluetoothHeadset {
         return false;
     }
 
+    /**
+     * Set priority of headset.
+     * Priority is a non-negative integer. By default paired headsets will have
+     * a priority of PRIORITY_AUTO, and unpaired headset PRIORITY_NONE (0).
+     * Headsets with priority greater than zero will be auto-connected, and
+     * incoming connections will be accepted (if no other headset is
+     * connected).
+     * Auto-connection occurs at the following events: boot, incoming phone
+     * call, outgoing phone call.
+     * Headsets with priority equal to zero, or that are unpaired, are not
+     * auto-connected.
+     * Incoming connections are ignored regardless of priority if there is
+     * already a headset connected.
+     * @param address Paired headset
+     * @param priority Integer priority, for example PRIORITY_AUTO or
+     *                 PRIORITY_NONE
+     * @return True if successful, false if there was some error.
+     */
+    public boolean setPriority(String address, int priority) {
+        if (mService != null) {
+            try {
+                return mService.setPriority(address, priority);
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+        }
+        return false;
+    }
+
+    /**
+     * Get priority of headset.
+     * @param address Headset
+     * @return non-negative priority, or negative error code on error.
+     */
+    public int getPriority(String address) {
+        if (mService != null) {
+            try {
+                return mService.getPriority(address);
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+        }
+        return -1;
+    }
+
+    /**
+     * Check class bits for possible HSP or HFP support.
+     * This is a simple heuristic that tries to guess if a device with the
+     * given class bits might support HSP or HFP. It is not accurate for all
+     * devices. It tries to err on the side of false positives.
+     * @return True if this device might support HSP or HFP.
+     */
+    public static boolean doesClassMatch(int btClass) {
+        switch (BluetoothClass.Device.getDevice(btClass)) {
+        case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
+        case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
+        case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+            return true;
+        default:
+            return false;
+        }
+    }
+
     private ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
@@ -289,12 +344,4 @@ public class BluetoothHeadset {
             }
         }
     };
-
-    private IBluetoothHeadsetCallback mHeadsetCallback = new IBluetoothHeadsetCallback.Stub() {
-        public void onConnectHeadsetResult(String address, int resultCode) {
-            if (mConnectHeadsetCallback != null) {
-                mConnectHeadsetCallback.onConnectHeadsetResult(address, resultCode);
-            }
-        }
-    };
 }
index 7e0226d..55ff27f 100644 (file)
@@ -26,4 +26,6 @@ interface IBluetoothA2dp {
     int disconnectSink(in String address);
     List<String> listConnectedSinks();
     int getSinkState(in String address);
+    int setSinkPriority(in String address, int priority);
+    int getSinkPriority(in String address);
 }
index 564861f..582d4e3 100644 (file)
@@ -16,8 +16,6 @@
 
 package android.bluetooth;
 
-import android.bluetooth.IBluetoothHeadsetCallback;
-
 /**
  * System private API for Bluetooth Headset service
  *
@@ -25,22 +23,12 @@ import android.bluetooth.IBluetoothHeadsetCallback;
  */
 interface IBluetoothHeadset {
     int getState();
-
     String getHeadsetAddress();
-
-    // Request that the given headset be connected
-    // Assumes the given headset is already bonded
-    // Will disconnect any currently connected headset
-    // returns false if cannot start a connection (for example, there is
-    // already a pending connect). callback will always be called iff this
-    // returns true
-    boolean connectHeadset(in String address, in IBluetoothHeadsetCallback callback);
-
+    boolean connectHeadset(in String address);
     void disconnectHeadset();
-
     boolean isConnected(in String address);
-
     boolean startVoiceRecognition();
-
     boolean stopVoiceRecognition();
+    boolean setPriority(in String address, int priority);
+    int getPriority(in String address);
 }
index 6da00df..3908aa1 100644 (file)
@@ -1249,6 +1249,15 @@ public abstract class Context {
     public static final String INPUT_METHOD_SERVICE = "input_method";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@blink android.gadget.GadgetManager} for accessing wallpapers.
+     *
+     * @hide
+     * @see #getSystemService
+     */
+    public static final String GADGET_SERVICE = "gadget";
+    
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/gadget/GadgetHost.java b/core/java/android/gadget/GadgetHost.java
new file mode 100644 (file)
index 0000000..418f2aa
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.gadget;
+
+import android.content.Context;
+import android.widget.RemoteViews;
+
+/**
+ * GadgetHost provides the interaction with the Gadget Service for apps,
+ * like the home screen, that want to embed gadgets in their UI.
+ */
+public class GadgetHost {
+    public GadgetHost(Context context, int hostId) {
+    }
+
+    /**
+     * Start receiving onGadgetChanged calls for your gadgets.  Call this when your activity
+     * becomes visible, i.e. from onStart() in your Activity.
+     */
+    public void startListening() {
+    }
+
+    /**
+     * Stop receiving onGadgetChanged calls for your gadgets.  Call this when your activity is
+     * no longer visible, i.e. from onStop() in your Activity.
+     */
+    public void stopListening() {
+    }
+
+    /**
+     * Stop listening to changes for this gadget.
+     */
+    public void gadgetRemoved(int gadgetId) {
+    }
+
+    /**
+     * Remove all records about gadget instances from the gadget manager.  Call this when
+     * initializing your database, as it might be because of a data wipe.
+     */
+    public void clearGadgets() {
+    }
+
+    public final GadgetHostView createView(Context context, int gadgetId, GadgetInfo gadget) {
+        GadgetHostView view = onCreateView(context, gadgetId, gadget);
+        view.setGadget(gadgetId, gadget);
+        view.updateGadget(null);
+        return view;
+    }
+
+    /**
+     * Called to create the GadgetHostView.  Override to return a custom subclass if you
+     * need it.  {@more}
+     */
+    protected GadgetHostView onCreateView(Context context, int gadgetId, GadgetInfo gadget) {
+        return new GadgetHostView(context);
+    }
+}
+
diff --git a/core/java/android/gadget/GadgetHostView.java b/core/java/android/gadget/GadgetHostView.java
new file mode 100644 (file)
index 0000000..e2bef8c
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gadget;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.gadget.GadgetInfo;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+public class GadgetHostView extends FrameLayout {
+    static final String TAG = "GadgetHostView";
+
+    // When we're inflating the initialLayout for a gadget, we only allow
+    // views that are allowed in RemoteViews.
+    static final LayoutInflater.Filter sInflaterFilter = new LayoutInflater.Filter() {
+        public boolean onLoadClass(Class clazz) {
+            return clazz.isAnnotationPresent(RemoteViews.RemoteView.class);
+        }
+    };
+
+    int mGadgetId;
+    GadgetInfo mInfo;
+    View mContentView;
+
+    public GadgetHostView(Context context) {
+        super(context);
+    }
+
+    public void setGadget(int gadgetId, GadgetInfo info) {
+        if (mInfo != null) {
+            // TODO: remove the old view, or whatever
+        }
+        mGadgetId = gadgetId;
+        mInfo = info;
+    }
+
+    public void updateGadget(RemoteViews remoteViews) {
+        Context context = getContext();
+
+        View contentView = null;
+        Exception exception = null;
+        try {
+            if (remoteViews == null) {
+                // there is no remoteViews (yet), so use the initial layout
+                Context theirContext = context.createPackageContext(mInfo.provider.getPackageName(),
+                        0);
+                LayoutInflater inflater = (LayoutInflater)theirContext.getSystemService(
+                        Context.LAYOUT_INFLATER_SERVICE);
+                inflater = inflater.cloneInContext(theirContext);
+                inflater.setFilter(sInflaterFilter);
+                contentView = inflater.inflate(mInfo.initialLayout, this, false);
+            } else {
+                // use the RemoteViews
+                contentView = remoteViews.apply(mContext, this);
+            }
+        }
+        catch (PackageManager.NameNotFoundException e) {
+            exception = e;
+        }
+        catch (RuntimeException e) {
+            exception = e;
+        }
+        if (contentView == null) {
+            Log.w(TAG, "Error inflating gadget " + mInfo, exception);
+            // TODO: Should we throw an exception here for the host activity to catch?
+            // Maybe we should show a generic error widget.
+            TextView tv = new TextView(context);
+            tv.setText("Error inflating gadget");
+            contentView = tv;
+        }
+
+        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
+                FrameLayout.LayoutParams.WRAP_CONTENT,
+                FrameLayout.LayoutParams.WRAP_CONTENT);
+
+        mContentView = contentView;
+        this.addView(contentView, lp);
+
+        // TODO: do an animation (maybe even one provided by the gadget).
+    }
+}
+
@@ -1,25 +1,19 @@
 /*
- * Copyright (C) 2008, The Android Open Source Project
+ * Copyright (c) 2007, 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
+ * 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
+ *     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
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
  * limitations under the License.
  */
 
-package android.bluetooth;
+package android.gadget;
 
-/**
- * {@hide}
- */
-oneway interface IBluetoothHeadsetCallback
-{
-    void onConnectHeadsetResult(in String address, int resultCode);
-}
+parcelable GadgetInfo;
diff --git a/core/java/android/gadget/GadgetInfo.java b/core/java/android/gadget/GadgetInfo.java
new file mode 100644 (file)
index 0000000..1a7a9a0
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.gadget;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.content.ComponentName;
+
+/**
+ * Describes the meta data for an installed gadget.
+ */
+public class GadgetInfo implements Parcelable {
+    /**
+     * Identity of this gadget component.  This component should be a {@link
+     * android.content.BroadcastReceiver}, and it will be sent the Gadget intents
+     * {@link android.gadget as described in the gadget package documentation}.
+     */
+    public ComponentName provider;
+
+    /**
+     * Minimum width of the gadget, in dp.
+     */
+    public int minWidth;
+
+    /**
+     * Minimum height of the gadget, in dp.
+     */
+    public int minHeight;
+
+    /**
+     * How often, in milliseconds, that this gadget wants to be updated.
+     * The gadget manager may place a limit on how often a gadget is updated.
+     */
+    public int updatePeriodMillis;
+
+    /**
+     * The resource id of the initial layout for this gadget.  This should be
+     * displayed until the RemoteViews for the gadget is available.
+     */
+    public int initialLayout;
+
+    /**
+     * The activity to launch that will configure the gadget.
+     */
+    public ComponentName configure;
+
+    public GadgetInfo() {
+    }
+
+    /**
+     * Unflatten the GadgetInfo from a parcel.
+     */
+    public GadgetInfo(Parcel in) {
+        if (0 != in.readInt()) {
+            this.provider = new ComponentName(in);
+        }
+        this.minWidth = in.readInt();
+        this.minHeight = in.readInt();
+        this.updatePeriodMillis = in.readInt();
+        this.initialLayout = in.readInt();
+        if (0 != in.readInt()) {
+            this.configure = new ComponentName(in);
+        }
+    }
+
+
+    public void writeToParcel(android.os.Parcel out, int flags) {
+        if (this.provider != null) {
+            out.writeInt(1);
+            this.provider.writeToParcel(out, flags);
+        } else {
+            out.writeInt(0);
+        }
+        out.writeInt(this.minWidth);
+        out.writeInt(this.minHeight);
+        out.writeInt(this.updatePeriodMillis);
+        out.writeInt(this.initialLayout);
+        if (this.configure != null) {
+            out.writeInt(1);
+            this.configure.writeToParcel(out, flags);
+        } else {
+            out.writeInt(0);
+        }
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Parcelable.Creator that instantiates GadgetInfo objects
+     */
+    public static final Parcelable.Creator<GadgetInfo> CREATOR
+            = new Parcelable.Creator<GadgetInfo>()
+    {
+        public GadgetInfo createFromParcel(Parcel parcel)
+        {
+            return new GadgetInfo(parcel);
+        }
+
+        public GadgetInfo[] newArray(int size)
+        {
+            return new GadgetInfo[size];
+        }
+    };
+
+    public String toString() {
+        return "GadgetInfo(provider=" + this.provider + ")";
+    }
+}
+
+
diff --git a/core/java/android/gadget/GadgetManager.java b/core/java/android/gadget/GadgetManager.java
new file mode 100644 (file)
index 0000000..49c706e
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.gadget;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+import com.android.internal.gadget.IGadgetService;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.WeakHashMap;
+
+public class GadgetManager {
+    static final String TAG = "GadgetManager";
+
+    /**
+     * Send this when you want to pick a gadget to display.
+     *
+     * <p>
+     * The system will respond with an onActivityResult call with the following extras in
+     * the intent:
+     * <ul>
+     *   <li><b>gadgetId</b></li>
+     *   <li><b>gadgetId</b></li>
+     *   <li><b>gadgetId</b></li>
+     * </ul>
+     * TODO: Add constants for these.
+     * TODO: Where does this go?
+     */
+    public static final String GADGET_PICK_ACTION = "android.gadget.action.PICK_GADGET";
+
+    public static final String EXTRA_GADGET_ID = "gadgetId";
+
+    /**
+     * Sent when it is time to update your gadget.
+     */
+    public static final String GADGET_UPDATE_ACTION = "android.gadget.GADGET_UPDATE";
+
+    /**
+     * Sent when the gadget is added to a host for the first time. TODO: Maybe we don't want this.
+     */
+    public static final String GADGET_ENABLE_ACTION = "android.gadget.GADGET_ENABLE";
+
+    /**
+     * Sent when the gadget is removed from the last host. TODO: Maybe we don't want this.
+     */
+    public static final String GADGET_DISABLE_ACTION = "android.gadget.GADGET_DISABLE";
+
+    static WeakHashMap<Context, WeakReference<GadgetManager>> sManagerCache = new WeakHashMap();
+    static IGadgetService sService;
+    
+    Context mContext;
+
+    public static GadgetManager getInstance(Context context) {
+        synchronized (sManagerCache) {
+            if (sService == null) {
+                IBinder b = ServiceManager.getService(Context.GADGET_SERVICE);
+                sService = IGadgetService.Stub.asInterface(b);
+            }
+
+            WeakReference<GadgetManager> ref = sManagerCache.get(context);
+            GadgetManager result = null;
+            if (ref != null) {
+                result = ref.get();
+            }
+            if (result == null) {
+                result = new GadgetManager(context);
+                sManagerCache.put(context, new WeakReference(result));
+            }
+            return result;
+        }
+    }
+
+    private GadgetManager(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Call this with the new RemoteViews for your gadget whenever you need to.
+     *
+     * <p>
+     * This method will only work when called from the uid that owns the gadget provider.
+     *
+     * @param gadgetId      The gadget instance for which to set the RemoteViews.
+     * @param views         The RemoteViews object to show.
+     */
+    public void updateGadget(int gadgetId, RemoteViews views) {
+    }
+
+    /**
+     * Return a list of the gadgets that are currently installed.
+     */
+    public List<GadgetInfo> getAvailableGadgets() {
+        return null;
+    }
+
+    /**
+     * Get the available info about the gadget.  If the gadgetId has not been bound yet,
+     * this method will return null.
+     *
+     * TODO: throws GadgetNotFoundException ??? if not valid
+     */
+    public GadgetInfo getGadgetInfo(int gadgetId) {
+        try {
+            return sService.getGadgetInfo(gadgetId);
+        }
+        catch (RemoteException e) {
+            throw new RuntimeException("system server dead?", e);
+        }
+    }
+
+    /**
+     * Get a gadgetId for a host in the calling process.
+     *
+     * @return a gadgetId
+     */
+    public int allocateGadgetId(String hostPackage) {
+        try {
+            return sService.allocateGadgetId(hostPackage);
+        }
+        catch (RemoteException e) {
+            throw new RuntimeException("system server dead?", e);
+        }
+    }
+
+    /**
+     * Delete the gadgetId.  Same as removeGadget on GadgetHost.
+     */
+    public void deleteGadgetId(int gadgetId) {
+        try {
+            sService.deleteGadgetId(gadgetId);
+        }
+        catch (RemoteException e) {
+            throw new RuntimeException("system server dead?", e);
+        }
+    }
+
+    /**
+     * Set the component for a given gadgetId.  You need the GADGET_LIST permission.
+     */
+    public void bindGadgetId(int gadgetId, ComponentName provider) {
+        try {
+            sService.bindGadgetId(gadgetId, provider);
+        }
+        catch (RemoteException e) {
+            throw new RuntimeException("system server dead?", e);
+        }
+    }
+}
+
diff --git a/core/java/android/gadget/package.html b/core/java/android/gadget/package.html
new file mode 100644 (file)
index 0000000..280ccfb
--- /dev/null
@@ -0,0 +1,4 @@
+<body>
+@hide
+</body>
+
index e2d7097..c09567c 100644 (file)
@@ -55,6 +55,7 @@ public class Camera {
     private PreviewCallback mPreviewCallback;
     private AutoFocusCallback mAutoFocusCallback;
     private ErrorCallback mErrorCallback;
+    private boolean mOneShot;
     
     /**
      * Returns a new Camera object.
@@ -198,9 +199,25 @@ public class Camera {
      */
     public final void setPreviewCallback(PreviewCallback cb) {
         mPreviewCallback = cb;
-        setHasPreviewCallback(cb != null);
+        mOneShot = false;
+        setHasPreviewCallback(cb != null, false);
     }
-    private native final void setHasPreviewCallback(boolean installed);
+
+    /**
+     * Installs a callback to retrieve a single preview frame, after which the
+     * callback is cleared.
+     *
+     * @param cb A callback object that receives a copy of the preview frame.
+     */
+    public final void setOneShotPreviewCallback(PreviewCallback cb) {
+        if (cb != null) {
+            mPreviewCallback = cb;
+            mOneShot = true;
+            setHasPreviewCallback(true, true);
+        }
+    }
+
+    private native final void setHasPreviewCallback(boolean installed, boolean oneshot);
 
     private class EventHandler extends Handler
     {
@@ -230,8 +247,12 @@ public class Camera {
                 return;
             
             case PREVIEW_CALLBACK:
-                if (mPreviewCallback != null)
+                if (mPreviewCallback != null) {
                     mPreviewCallback.onPreviewFrame((byte[])msg.obj, mCamera);
+                    if (mOneShot) {
+                        mPreviewCallback = null;
+                    }
+                }
                 return;
 
             case AUTOFOCUS_CALLBACK:
index 21bb38e..1a7547d 100644 (file)
@@ -33,6 +33,8 @@ import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
+import android.view.Window;
+import android.view.WindowManager;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
@@ -197,6 +199,7 @@ public class InputMethodService extends AbstractInputMethodService {
     EditorInfo mInputEditorInfo;
     
     boolean mShowInputRequested;
+    boolean mLastShowInputRequested;
     boolean mShowCandidatesRequested;
     
     boolean mFullscreenApplied;
@@ -257,6 +260,8 @@ public class InputMethodService extends AbstractInputMethodService {
         public void bindInput(InputBinding binding) {
             mInputBinding = binding;
             mInputConnection = binding.getConnection();
+            if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
+                    + " ic=" + mInputConnection);
             onBindInput();
         }
 
@@ -264,17 +269,22 @@ public class InputMethodService extends AbstractInputMethodService {
          * Clear the current input binding.
          */
         public void unbindInput() {
+            if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
+                    + " ic=" + mInputConnection);
+            onUnbindInput();
             mInputStarted = false;
             mInputBinding = null;
             mInputConnection = null;
         }
 
         public void startInput(EditorInfo attribute) {
+            if (DEBUG) Log.v(TAG, "startInput(): editor=" + attribute);
             doStartInput(attribute, false);
         }
 
         public void restartInput(EditorInfo attribute) {
-            doStartInput(attribute, false);
+            if (DEBUG) Log.v(TAG, "restartInput(): editor=" + attribute);
+            doStartInput(attribute, true);
         }
 
         /**
@@ -305,6 +315,7 @@ public class InputMethodService extends AbstractInputMethodService {
             if (!isEnabled()) {
                 return;
             }
+            if (DEBUG) Log.v(TAG, "finishInput() in " + this);
             onFinishInput();
             mInputStarted = false;
         }
@@ -455,7 +466,7 @@ public class InputMethodService extends AbstractInputMethodService {
         mIsInputViewShown = false;
         
         mExtractFrame.setVisibility(View.GONE);
-        mCandidatesFrame.setVisibility(View.GONE);
+        mCandidatesFrame.setVisibility(View.INVISIBLE);
         mInputFrame.setVisibility(View.GONE);
     }
     
@@ -469,6 +480,29 @@ public class InputMethodService extends AbstractInputMethodService {
     }
     
     /**
+     * Take care of handling configuration changes.  Subclasses of
+     * InputMethodService generally don't need to deal directly with
+     * this on their own; the standard implementation here takes care of
+     * regenerating the input method UI as a result of the configuration
+     * change, so you can rely on your {@link #onCreateInputView} and
+     * other methods being called as appropriate due to a configuration change.
+     */
+    @Override public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        
+        boolean visible = mWindowVisible;
+        boolean showingInput = mShowInputRequested;
+        boolean showingCandidates = mShowCandidatesRequested;
+        initViews();
+        if (visible) {
+            if (showingCandidates) {
+                setCandidatesViewShown(true);
+            }
+            showWindow(showingInput);
+        }
+    }
+
+    /**
      * Implement to return our standard {@link InputMethodImpl}.  Subclasses
      * can override to provide their own customized version.
      */
@@ -493,6 +527,27 @@ public class InputMethodService extends AbstractInputMethodService {
     }
     
     /**
+     * Return the maximum width, in pixels, available the input method.
+     * Input methods are positioned at the bottom of the screen and, unless
+     * running in fullscreen, will generally want to be as short as possible
+     * so should compute their height based on their contents.  However, they
+     * can stretch as much as needed horizontally.  The function returns to
+     * you the maximum amount of space available horizontally, which you can
+     * use if needed for UI placement.
+     * 
+     * <p>In many cases this is not needed, you can just rely on the normal
+     * view layout mechanisms to position your views within the full horizontal
+     * space given to the input method.
+     * 
+     * <p>Note that this value can change dynamically, in particular when the
+     * screen orientation changes.
+     */
+    public int getMaxWidth() {
+        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
+        return wm.getDefaultDisplay().getWidth();
+    }
+    
+    /**
      * Return the currently active InputBinding for the input method, or
      * null if there is none.
      */
@@ -525,12 +580,19 @@ public class InputMethodService extends AbstractInputMethodService {
      * is currently running in fullscreen mode.
      */
     public void updateFullscreenMode() {
-        boolean isFullscreen = onEvaluateFullscreenMode();
+        boolean isFullscreen = mShowInputRequested && onEvaluateFullscreenMode();
+        boolean changed = mLastShowInputRequested != mShowInputRequested;
         if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
+            changed = true;
             mIsFullscreen = isFullscreen;
             mFullscreenApplied = true;
-            mWindow.getWindow().setBackgroundDrawable(
-                    onCreateBackgroundDrawable());
+            Drawable bg = onCreateBackgroundDrawable();
+            if (bg == null) {
+                // We need to give the window a real drawable, so that it
+                // correctly sets its mode.
+                bg = getResources().getDrawable(android.R.color.transparent);
+            }
+            mWindow.getWindow().setBackgroundDrawable(bg);
             mExtractFrame.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
             if (isFullscreen) {
                 if (mExtractView == null) {
@@ -540,11 +602,39 @@ public class InputMethodService extends AbstractInputMethodService {
                     }
                 }
                 startExtractingText();
-                mWindow.getWindow().setLayout(FILL_PARENT, FILL_PARENT);
-            } else {
-                mWindow.getWindow().setLayout(WRAP_CONTENT, WRAP_CONTENT);
             }
         }
+        
+        if (changed) {
+            onConfigureWindow(mWindow.getWindow(), isFullscreen,
+                    !mShowInputRequested);
+            mLastShowInputRequested = mShowInputRequested;
+        }
+    }
+    
+    /**
+     * Update the given window's parameters for the given mode.  This is called
+     * when the window is first displayed and each time the fullscreen or
+     * candidates only mode changes.
+     * 
+     * <p>The default implementation makes the layout for the window
+     * FILL_PARENT x FILL_PARENT when in fullscreen mode, and
+     * FILL_PARENT x WRAP_CONTENT when in non-fullscreen mode.
+     * 
+     * @param win The input method's window.
+     * @param isFullscreen If true, the window is running in fullscreen mode
+     * and intended to cover the entire application display.
+     * @param isCandidatesOnly If true, the window is only showing the
+     * candidates view and none of the rest of its UI.  This is mutually
+     * exclusive with fullscreen mode.
+     */
+    public void onConfigureWindow(Window win, boolean isFullscreen,
+            boolean isCandidatesOnly) {
+        if (isFullscreen) {
+            mWindow.getWindow().setLayout(FILL_PARENT, FILL_PARENT);
+        } else {
+            mWindow.getWindow().setLayout(FILL_PARENT, WRAP_CONTENT);
+        }
     }
     
     /**
@@ -607,7 +697,7 @@ public class InputMethodService extends AbstractInputMethodService {
      * is currently shown.
      */
     public void updateInputViewShown() {
-        boolean isShown = onEvaluateInputViewShown();
+        boolean isShown = mShowInputRequested && onEvaluateInputViewShown();
         if (mIsInputViewShown != isShown && mWindowVisible) {
             mIsInputViewShown = isShown;
             mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
@@ -650,18 +740,18 @@ public class InputMethodService extends AbstractInputMethodService {
     public void setCandidatesViewShown(boolean shown) {
         if (mShowCandidatesRequested != shown) {
             mCandidatesFrame.setVisibility(shown ? View.VISIBLE : View.INVISIBLE);
-            if (!mShowInputRequested) {
-                // If we are being asked to show the candidates view while the app
-                // has not asked for the input view to be shown, then we need
-                // to update whether the window is shown.
-                if (shown) {
-                    showWindow(false);
-                } else {
-                    hideWindow();
-                }
-            }
             mShowCandidatesRequested = shown;
         }
+        if (!mShowInputRequested && mWindowVisible != shown) {
+            // If we are being asked to show the candidates view while the app
+            // has not asked for the input view to be shown, then we need
+            // to update whether the window is shown.
+            if (shown) {
+                showWindow(false);
+            } else {
+                hideWindow();
+            }
+        }
     }
     
     public void setStatusIcon(int iconResId) {
@@ -729,7 +819,7 @@ public class InputMethodService extends AbstractInputMethodService {
      * Called by the framework to create a Drawable for the background of
      * the input method window.  May return null for no background.  The default
      * implementation returns a non-null standard background only when in
-     * fullscreen mode.
+     * fullscreen mode.  This is called each time the fullscreen mode changes.
      */
     public Drawable onCreateBackgroundDrawable() {
         if (isFullscreenMode()) {
@@ -789,22 +879,6 @@ public class InputMethodService extends AbstractInputMethodService {
     public void onStartInputView(EditorInfo info, boolean restarting) {
     }
     
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        
-        boolean visible = mWindowVisible;
-        boolean showingInput = mShowInputRequested;
-        boolean showingCandidates = mShowCandidatesRequested;
-        initViews();
-        if (visible) {
-            if (showingCandidates) {
-                setCandidatesViewShown(true);
-            }
-            showWindow(showingInput);
-        }
-    }
-
     /**
      * The system has decided that it may be time to show your input method.
      * This is called due to a corresponding call to your
@@ -837,17 +911,17 @@ public class InputMethodService extends AbstractInputMethodService {
         boolean wasVisible = mWindowVisible;
         mWindowVisible = true;
         if (!mShowInputRequested) {
-            doShowInput = true;
-            mShowInputRequested = true;
+            if (showInput) {
+                doShowInput = true;
+                mShowInputRequested = true;
+            }
         } else {
             showInput = true;
         }
         
-        if (doShowInput) {
-            if (DEBUG) Log.v(TAG, "showWindow: updating UI");
-            updateFullscreenMode();
-            updateInputViewShown();
-        }
+        if (DEBUG) Log.v(TAG, "showWindow: updating UI");
+        updateFullscreenMode();
+        updateInputViewShown();
         
         if (!mWindowAdded || !mWindowCreated) {
             mWindowAdded = true;
@@ -885,13 +959,44 @@ public class InputMethodService extends AbstractInputMethodService {
         }
     }
     
+    /**
+     * Called when a new client has bound to the input method.  This
+     * may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
+     * and {@link #onFinishInput()} calls as the user navigates through its
+     * UI.  Upon this call you know that {@link #getCurrentInputBinding}
+     * and {@link #getCurrentInputConnection} return valid objects.
+     */
     public void onBindInput() {
     }
     
+    /**
+     * Called when the previous bound client is no longer associated
+     * with the input method.  After returning {@link #getCurrentInputBinding}
+     * and {@link #getCurrentInputConnection} will no longer return
+     * valid objects.
+     */
+    public void onUnbindInput() {
+    }
+    
+    /**
+     * Called to inform the input method that text input has started in an
+     * editor.  You should use this callback to initialize the state of your
+     * input to match the state of the editor given to it.
+     * 
+     * @param attribute The attributes of the editor that input is starting
+     * in.
+     * @param restarting Set to true if input is restarting in the same
+     * editor such as because the application has changed the text in
+     * the editor.  Otherwise will be false, indicating this is a new
+     * session with the editor.
+     */
     public void onStartInput(EditorInfo attribute, boolean restarting) {
     }
     
     void doStartInput(EditorInfo attribute, boolean restarting) {
+        if (mInputStarted && !restarting) {
+            onFinishInput();
+        }
         mInputStarted = true;
         mInputEditorInfo = attribute;
         onStartInput(attribute, restarting);
@@ -903,6 +1008,13 @@ public class InputMethodService extends AbstractInputMethodService {
         }
     }
     
+    /**
+     * Called to inform the input method that text input has finished in
+     * the last editor.  At this point there may be a call to
+     * {@link #onStartInput(EditorInfo, boolean)} to perform input in a
+     * new editor, or the input method may be left idle.  This method is
+     * <em>not</em> called when input restarts in the same editor.
+     */
     public void onFinishInput() {
     }
     
index 7b64405..a18f37c 100644 (file)
@@ -1740,12 +1740,12 @@ public final class Settings {
          */
         public static final Uri CONTENT_URI =
             Uri.parse("content://" + AUTHORITY + "/secure");
-        
+
         /**
          * Whether ADB is enabled.
          */
         public static final String ADB_ENABLED = "adb_enabled";
-    
+
         /**
          * Setting to allow mock locations and location provider status to be injected into the
          * LocationManager service for testing purposes during application development.  These
@@ -1753,7 +1753,7 @@ public final class Settings {
          * by network, gps, or other location providers.
          */
         public static final String ALLOW_MOCK_LOCATION = "mock_location";
-    
+
         /**
          * The Android ID (a unique 64-bit value) as a hex string.
          * Identical to that obtained by calling
@@ -1761,24 +1761,40 @@ public final class Settings {
          * so you can get it without binding to a service.
          */
         public static final String ANDROID_ID = "android_id";
-    
+
         /**
          * Whether bluetooth is enabled/disabled
          * 0=disabled. 1=enabled.
          */
         public static final String BLUETOOTH_ON = "bluetooth_on";
-    
+
+        /**
+         * Get the key that retrieves a bluetooth headset's priority.
+         * @hide
+         */
+        public static final String getBluetoothHeadsetPriorityKey(String address) {
+            return ("bluetooth_headset_priority_" + address.toUpperCase());
+        }
+
+        /**
+         * Get the key that retrieves a bluetooth a2dp sink's priority.
+         * @hide
+         */
+        public static final String getBluetoothA2dpSinkPriorityKey(String address) {
+            return ("bluetooth_a2dp_sink_priority_" + address.toUpperCase());
+        }
+
         /**
          * Whether or not data roaming is enabled. (0 = false, 1 = true)
          */
         public static final String DATA_ROAMING = "data_roaming";
-    
+
         /**
          * Setting to record the input method used by default, holding the ID
          * of the desired method.
          */
         public static final String DEFAULT_INPUT_METHOD = "default_input_method";
-    
+
         /**
          * Whether the device has been provisioned (0 = false, 1 = true)
          */
@@ -1953,7 +1969,13 @@ public final class Settings {
          * Whether the Wi-Fi watchdog is enabled.
          */
         public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
-    
+
+        /**
+         * A comma-separated list of SSIDs for which the Wi-Fi watchdog should be enabled.
+         * @hide pending API council
+         */
+        public static final String WIFI_WATCHDOG_WATCH_LIST = "wifi_watchdog_watch_list";
+
         /**
          * The number of pings to test if an access point is a good connection.
          */
diff --git a/core/java/android/provider/UserDictionary.java b/core/java/android/provider/UserDictionary.java
new file mode 100644 (file)
index 0000000..58e5731
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import java.util.Locale;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.text.TextUtils;
+
+/**
+ * 
+ * @hide Pending API council approval
+ */
+public class UserDictionary {
+    public static final String AUTHORITY = "user_dictionary";
+
+    /**
+     * The content:// style URL for this provider
+     */
+    public static final Uri CONTENT_URI =
+        Uri.parse("content://" + AUTHORITY);
+
+    /**
+     * Contains the user defined words.
+     * @hide Pending API council approval
+     */
+    public static class Words implements BaseColumns {
+        /**
+         * The content:// style URL for this table
+         */
+        public static final Uri CONTENT_URI =
+                Uri.parse("content://" + AUTHORITY + "/words");
+
+        /**
+         * The MIME type of {@link #CONTENT_URI} providing a directory of words.
+         */
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.userword";
+
+        /**
+         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single word.
+         */
+        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.userword";
+
+        public static final String _ID = BaseColumns._ID;
+
+        /**
+         * The word column.
+         * <p>TYPE: TEXT</p>
+         */
+        public static final String WORD = "word";
+
+        /**
+         * The frequency column. A value between 1 and 255.
+         * <p>TYPE: INTEGER</p>
+         */
+        public static final String FREQUENCY = "frequency";
+
+        /**
+         * The locale that this word belongs to. Null if it pertains to all
+         * locales. Locale is a 5 letter string such as <pre>en_US</pre>.
+         * <p>TYPE: TEXT</p>
+         */
+        public static final String LOCALE = "locale";
+
+        /**
+         * The uid of the application that inserted the word.
+         * <p>TYPE: INTEGER</p>
+         */
+        public static final String APP_ID = "appid";
+
+        public static final int LOCALE_TYPE_ALL = 0;
+        
+        public static final int LOCALE_TYPE_CURRENT = 1;
+        
+        /**
+         * Sort by descending order of frequency.
+         */
+        public static final String DEFAULT_SORT_ORDER = FREQUENCY + " DESC";
+
+
+        public static void addWord(Context context, String word, 
+                int frequency, int localeType) {
+            final ContentResolver resolver = context.getContentResolver();
+
+            if (TextUtils.isEmpty(word) || localeType < 0 || localeType > 1) {
+                return;
+            }
+            
+            if (frequency < 0) frequency = 0;
+            if (frequency > 255) frequency = 255;
+
+            String locale = null;
+
+            // TODO: Verify if this is the best way to get the current locale
+            if (localeType == LOCALE_TYPE_CURRENT) {
+                locale = Locale.getDefault().toString();
+            }
+            ContentValues values = new ContentValues(4);
+
+            values.put(WORD, word);
+            values.put(FREQUENCY, frequency);
+            values.put(LOCALE, locale);
+            values.put(APP_ID, 0); // TODO: Get App UID
+
+            Uri result = resolver.insert(CONTENT_URI, values);
+            // It's ok if the insert doesn't succeed because the word
+            // already exists.
+        }
+    }
+}
index 90ef8f6..be784ff 100644 (file)
@@ -35,6 +35,7 @@ import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.media.AudioManager;
 import android.os.Binder;
+import android.provider.Settings;
 import android.util.Log;
 
 import java.io.FileDescriptor;
@@ -83,6 +84,8 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
 
         mIntentFilter = new IntentFilter(BluetoothIntent.ENABLED_ACTION);
         mIntentFilter.addAction(BluetoothIntent.DISABLED_ACTION);
+        mIntentFilter.addAction(BluetoothIntent.BONDING_CREATED_ACTION);
+        mIntentFilter.addAction(BluetoothIntent.BONDING_REMOVED_ACTION);
         mContext.registerReceiver(mReceiver, mIntentFilter);
 
         if (device.isEnabled()) {
@@ -103,10 +106,15 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
+            String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
             if (action.equals(BluetoothIntent.ENABLED_ACTION)) {
                 onBluetoothEnable();
             } else if (action.equals(BluetoothIntent.DISABLED_ACTION)) {
                 onBluetoothDisable();
+            } else if (action.equals(BluetoothIntent.BONDING_CREATED_ACTION)) {
+                setSinkPriority(address, BluetoothA2dp.PRIORITY_AUTO);
+            } else if (action.equals(BluetoothIntent.BONDING_REMOVED_ACTION)) {
+                setSinkPriority(address, BluetoothA2dp.PRIORITY_OFF);
             }
         }
     };
@@ -145,7 +153,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
         if (path == null) {
             return BluetoothError.ERROR;
         }
-        
+
         SinkState sink = mAudioDevices.get(path);
         int state = BluetoothA2dp.STATE_DISCONNECTED;
         if (sink != null) {
@@ -159,8 +167,8 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
         case BluetoothA2dp.STATE_CONNECTING:
             return BluetoothError.SUCCESS;
         }
-        
-        // State is DISCONNECTED    
+
+        // State is DISCONNECTED
         if (!connectSinkNative(path)) {
             return BluetoothError.ERROR;
         }
@@ -189,7 +197,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
             return BluetoothError.SUCCESS;
         }
 
-        // State is CONNECTING or CONNECTED or PLAYING 
+        // State is CONNECTING or CONNECTED or PLAYING
         if (!disconnectSinkNative(path)) {
             return BluetoothError.ERROR;
         } else {
@@ -229,16 +237,37 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
         return BluetoothA2dp.STATE_DISCONNECTED;
     }
 
-    public synchronized void onHeadsetCreated(String path) {
+    public synchronized int getSinkPriority(String address) {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+            return BluetoothError.ERROR;
+        }
+        return Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.getBluetoothA2dpSinkPriorityKey(address),
+                BluetoothA2dp.PRIORITY_OFF);
+    }
+
+    public synchronized int setSinkPriority(String address, int priority) {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
+        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+            return BluetoothError.ERROR;
+        }
+        return Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.getBluetoothA2dpSinkPriorityKey(address), priority) ?
+                BluetoothError.SUCCESS : BluetoothError.ERROR;
+    }
+
+    private synchronized void onHeadsetCreated(String path) {
         updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
     }
 
-    public synchronized void onHeadsetRemoved(String path) {
+    private synchronized void onHeadsetRemoved(String path) {
         if (mAudioDevices == null) return;
         mAudioDevices.remove(path);
     }
 
-    public synchronized void onSinkConnected(String path) {
+    private synchronized void onSinkConnected(String path) {
         if (mAudioDevices == null) return;
         // bluez 3.36 quietly disconnects the previous sink when a new sink
         // is connected, so we need to mark all previously connected sinks as
@@ -258,16 +287,16 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
         updateState(path, BluetoothA2dp.STATE_CONNECTED);
     }
 
-    public synchronized void onSinkDisconnected(String path) {
+    private synchronized void onSinkDisconnected(String path) {
         mAudioManager.setBluetoothA2dpOn(false);
         updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
     }
 
-    public synchronized void onSinkPlaying(String path) {
+    private synchronized void onSinkPlaying(String path) {
         updateState(path, BluetoothA2dp.STATE_PLAYING);
     }
 
-    public synchronized void onSinkStopped(String path) {
+    private synchronized void onSinkStopped(String path) {
         updateState(path, BluetoothA2dp.STATE_CONNECTED);
     }
 
@@ -307,7 +336,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
 
         if (state != prevState) {
             if (DBG) log("state " + address + " (" + path + ") " + prevState + "->" + state);
-    
+
             Intent intent = new Intent(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
             intent.putExtra(BluetoothIntent.ADDRESS, address);
             intent.putExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, prevState);
@@ -339,5 +368,4 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
     private synchronized native boolean connectSinkNative(String path);
     private synchronized native boolean disconnectSinkNative(String path);
     private synchronized native boolean isSinkConnectedNative(String path);
-
 }
index 749c923..a03a36a 100644 (file)
@@ -367,6 +367,35 @@ public final class Recognizer {
         SR_RecognizerStop(mRecognizer);
         SR_RecognizerDeactivateRule(mRecognizer, mActiveGrammar.mGrammar, "trash");
     }
+    
+    /**
+     * Reset the acoustic state vectorto it's default value.
+     * 
+     * @hide
+     */
+    public void resetAcousticState() {
+        SR_AcousticStateReset(mRecognizer);
+    }
+    
+    /**
+     * Set the acoustic state vector.
+     * @param state String containing the acoustic state vector.
+     * 
+     * @hide
+     */
+    public void setAcousticState(String state) {
+        SR_AcousticStateSet(mRecognizer, state);
+    }
+    
+    /**
+     * Get the acoustic state vector.
+     * @return String containing the acoustic state vector.
+     * 
+     * @hide
+     */
+    public String getAcousticState() {
+        return SR_AcousticStateGet(mRecognizer);
+    }
 
     /**
      * Clean up resources.
@@ -572,6 +601,9 @@ public final class Recognizer {
         return "EVENT_" + event;
     }
 
+    //
+    // SR_Recognizer methods
+    //
     private static native void SR_RecognizerStart(int recognizer);
     private static native void SR_RecognizerStop(int recognizer);
     private static native int SR_RecognizerCreate();
@@ -615,6 +647,14 @@ public final class Recognizer {
     private static native boolean SR_RecognizerIsSignalTooFewSamples(int recognizer);
     private static native boolean SR_RecognizerIsSignalTooManySamples(int recognizer);
     // private static native void SR_Recognizer_Change_Sample_Rate (size_t new_sample_rate);
+    
+    
+    //
+    // SR_AcousticState native methods
+    //
+    private static native void SR_AcousticStateReset(int recognizer);
+    private static native void SR_AcousticStateSet(int recognizer, String state);
+    private static native String SR_AcousticStateGet(int recognizer);
 
 
     //
index 0aa3cc2..a99496d 100644 (file)
@@ -263,5 +263,12 @@ public class WaveHeader {
         out.write(val >> 0);
         out.write(val >> 8);
     }
+    
+    @Override
+    public String toString() {
+        return String.format(
+                "WaveHeader format=%d numChannels=%d sampleRate=%d bitsPerSample=%d numBytes=%d",
+                mFormat, mNumChannels, mSampleRate, mBitsPerSample, mNumBytes);
+    }
 
 }
index 9d7a124..9e0289a 100644 (file)
@@ -117,6 +117,7 @@ public final class ViewRoot extends Handler implements ViewParent,
 
     View mView;
     View mFocusedView;
+    View mRealFocusedView;  // this is not set to null in touch mode
     int mViewVisibility;
     boolean mAppVisible = true;
 
@@ -971,9 +972,19 @@ public final class ViewRoot extends Handler implements ViewParent,
             
         if (mFirst) {
             // handle first focus request
-            if (mView != null && !mView.hasFocus()) {
-                mView.requestFocus(View.FOCUS_FORWARD);
-                mFocusedView = mView.findFocus();
+            if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
+                    + mView.hasFocus());
+            if (mView != null) {
+                if (!mView.hasFocus()) {
+                    mView.requestFocus(View.FOCUS_FORWARD);
+                    mFocusedView = mRealFocusedView = mView.findFocus();
+                    if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
+                            + mFocusedView);
+                } else {
+                    mRealFocusedView = mView.findFocus();
+                    if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
+                            + mRealFocusedView);
+                }
             }
         }
 
@@ -1214,13 +1225,16 @@ public final class ViewRoot extends Handler implements ViewParent,
             // requestChildRectangleOnScreen() call (in which case 'rectangle'
             // is non-null and we just want to scroll to whatever that
             // rectangle is).
-            View focus = mFocusedView;
+            View focus = mRealFocusedView;
             if (focus != mLastScrolledFocus) {
                 // If the focus has changed, then ignore any requests to scroll
                 // to a rectangle; first we want to make sure the entire focus
                 // view is visible.
                 rectangle = null;
             }
+            if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
+                    + " rectangle=" + rectangle + " ci=" + ci
+                    + " vi=" + vi);
             if (focus == mLastScrolledFocus && !mScrollMayChange
                     && rectangle == null) {
                 // Optimization: if the focus hasn't changed since last
@@ -1234,6 +1248,7 @@ public final class ViewRoot extends Handler implements ViewParent,
                 // a pan so it can be seen.
                 mLastScrolledFocus = focus;
                 mScrollMayChange = false;
+                if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
                 // Try to find the rectangle from the focus view.
                 if (focus.getGlobalVisibleRect(mVisRect, null)) {
                     if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
@@ -1307,7 +1322,9 @@ public final class ViewRoot extends Handler implements ViewParent,
             mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused);
             scheduleTraversals();
         }
-        mFocusedView = focused;
+        mFocusedView = mRealFocusedView = focused;
+        if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Request child focus: focus now "
+                + mFocusedView);
     }
 
     public void clearChildFocus(View child) {
@@ -1315,7 +1332,8 @@ public final class ViewRoot extends Handler implements ViewParent,
 
         View oldFocus = mFocusedView;
 
-        mFocusedView = null;
+        if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Clearing child focus");
+        mFocusedView = mRealFocusedView = null;
         if (mView != null && !mView.hasFocus()) {
             // If a view gets the focus, the listener will be invoked from requestChildFocus()
             if (!mView.requestFocus(View.FOCUS_FORWARD)) {
index a676234..ba40782 100644 (file)
@@ -800,7 +800,7 @@ public final class InputMethodManager {
             
             try {
                 if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
-                        + ic + " tba=" + tba);
+                        + ic + " tba=" + tba + " initial=" + initial);
                 InputBindResult res = mService.startInput(mClient, tba, initial,
                         mCurMethod == null);
                 if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
@@ -848,6 +848,9 @@ public final class InputMethodManager {
         synchronized (mH) {
             if (DEBUG) Log.v(TAG, "focusIn: " + view);
             // Okay we have a new view that is being served.
+            if (mServedView != view) {
+                mCurrentTextBoxAttribute = null;
+            }
             mServedView = view;
             mCompletions = null;
             mServedConnecting = true;
index cae94c9..4f8e5e4 100644 (file)
 
 package android.webkit;
 
+import android.app.AlertDialog;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -30,7 +32,14 @@ import android.os.SystemClock;
 import android.util.Config;
 import android.util.Log;
 import android.view.KeyEvent;
-
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.TextView;
+import com.android.internal.R;
+
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.HashMap;
 
 /**
@@ -376,12 +385,24 @@ class CallbackProxy extends Handler {
 
             case JS_ALERT:
                 if (mWebChromeClient != null) {
-                    JsResult res = (JsResult) msg.obj;
+                    final JsResult res = (JsResult) msg.obj;
                     String message = msg.getData().getString("message");
                     String url = msg.getData().getString("url");
                     if (!mWebChromeClient.onJsAlert(mWebView, url, message,
-                                res)) {
-                        res.handleDefault();
+                            res)) {
+                        new AlertDialog.Builder(mContext)
+                                .setTitle(getJsDialogTitle(url))
+                                .setMessage(message)
+                                .setPositiveButton(R.string.ok,
+                                        new AlertDialog.OnClickListener() {
+                                            public void onClick(
+                                                    DialogInterface dialog,
+                                                    int which) {
+                                                res.confirm();
+                                            }
+                                        })
+                                .setCancelable(false)
+                                .show();
                     }
                     res.setReady();
                 }
@@ -389,12 +410,29 @@ class CallbackProxy extends Handler {
 
             case JS_CONFIRM:
                 if (mWebChromeClient != null) {
-                    JsResult res = (JsResult) msg.obj;
+                    final JsResult res = (JsResult) msg.obj;
                     String message = msg.getData().getString("message");
                     String url = msg.getData().getString("url");
                     if (!mWebChromeClient.onJsConfirm(mWebView, url, message,
-                                res)) {
-                        res.handleDefault();
+                            res)) {
+                        new AlertDialog.Builder(mContext)
+                                .setTitle(getJsDialogTitle(url))
+                                .setMessage(message)
+                                .setPositiveButton(R.string.ok, 
+                                        new DialogInterface.OnClickListener() {
+                                            public void onClick(
+                                                    DialogInterface dialog,
+                                                    int which) {
+                                                res.confirm();
+                                            }})
+                                .setNegativeButton(R.string.cancel, 
+                                        new DialogInterface.OnClickListener() {
+                                            public void onClick(
+                                                    DialogInterface dialog,
+                                                    int which) {
+                                                res.cancel();
+                                            }})
+                                .show();
                     }
                     // Tell the JsResult that it is ready for client
                     // interaction.
@@ -404,13 +442,49 @@ class CallbackProxy extends Handler {
 
             case JS_PROMPT:
                 if (mWebChromeClient != null) {
-                    JsPromptResult res = (JsPromptResult) msg.obj;
+                    final JsPromptResult res = (JsPromptResult) msg.obj;
                     String message = msg.getData().getString("message");
                     String defaultVal = msg.getData().getString("default");
                     String url = msg.getData().getString("url");
                     if (!mWebChromeClient.onJsPrompt(mWebView, url, message,
                                 defaultVal, res)) {
-                        res.handleDefault();
+                        final LayoutInflater factory = LayoutInflater
+                                .from(mContext);
+                        final View view = factory.inflate(R.layout.js_prompt,
+                                null);
+                        final EditText v = (EditText) view
+                                .findViewById(R.id.value);
+                        v.setText(defaultVal);
+                        ((TextView) view.findViewById(R.id.message))
+                                .setText(message);
+                        new AlertDialog.Builder(mContext)
+                                .setTitle(getJsDialogTitle(url))
+                                .setView(view)
+                                .setPositiveButton(R.string.ok,
+                                        new DialogInterface.OnClickListener() {
+                                            public void onClick(
+                                                    DialogInterface dialog,
+                                                    int whichButton) {
+                                                res.confirm(v.getText()
+                                                        .toString());
+                                            }
+                                        })
+                                .setNegativeButton(R.string.cancel,
+                                        new DialogInterface.OnClickListener() {
+                                            public void onClick(
+                                                    DialogInterface dialog,
+                                                    int whichButton) {
+                                                res.cancel();
+                                            }
+                                        })
+                                .setOnCancelListener(
+                                        new DialogInterface.OnCancelListener() {
+                                            public void onCancel(
+                                                    DialogInterface dialog) {
+                                                res.cancel();
+                                            }
+                                        })
+                                .show();
                     }
                     // Tell the JsResult that it is ready for client
                     // interaction.
@@ -420,12 +494,32 @@ class CallbackProxy extends Handler {
 
             case JS_UNLOAD:
                 if (mWebChromeClient != null) {
-                    JsResult res = (JsResult) msg.obj;
+                    final JsResult res = (JsResult) msg.obj;
                     String message = msg.getData().getString("message");
                     String url = msg.getData().getString("url");
                     if (!mWebChromeClient.onJsBeforeUnload(mWebView, url,
-                                message, res)) {
-                        res.handleDefault();
+                            message, res)) {
+                        final String m = mContext.getString(
+                                R.string.js_dialog_before_unload, message);
+                        new AlertDialog.Builder(mContext)
+                                .setMessage(m)
+                                .setPositiveButton(R.string.ok,
+                                        new DialogInterface.OnClickListener() {
+                                            public void onClick(
+                                                    DialogInterface dialog,
+                                                    int which) {
+                                                res.confirm();
+                                            }
+                                        })
+                                .setNegativeButton(R.string.cancel,
+                                        new DialogInterface.OnClickListener() {
+                                            public void onClick(
+                                                    DialogInterface dialog,
+                                                    int which) {
+                                                res.cancel();
+                                            }
+                                        })
+                                .show();
                     }
                     res.setReady();
                 }
@@ -468,6 +562,24 @@ class CallbackProxy extends Handler {
         sendMessage(obtainMessage(SWITCH_OUT_HISTORY));
     }
 
+    private String getJsDialogTitle(String url) {
+        String title = url;
+        if (URLUtil.isDataUrl(url)) {
+            // For data: urls, we just display 'JavaScript' similar to Safari.
+            title = mContext.getString(R.string.js_dialog_title_default);
+        } else {
+            try {
+                URL aUrl = new URL(url);
+                // For example: "The page at 'http://www.mit.edu' says:"
+                title = mContext.getString(R.string.js_dialog_title,
+                        aUrl.getProtocol() + "://" + aUrl.getHost());
+            } catch (MalformedURLException ex) {
+                // do nothing. just use the url as the title
+            }
+        }
+        return title;
+    }
+
     //--------------------------------------------------------------------------
     // WebViewClient functions.
     // NOTE: shouldOverrideKeyEvent is never called from the WebCore thread so
index 30b519a..b7b40b1 100644 (file)
@@ -38,13 +38,20 @@ import android.text.method.MovementMethod;
 import android.text.method.PasswordTransformationMethod;
 import android.text.method.TextKeyListener;
 import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
 import android.view.View.MeasureSpec;
 import android.view.ViewConfiguration;
 import android.widget.AbsoluteLayout.LayoutParams;
+import android.widget.ArrayAdapter;
 import android.widget.AutoCompleteTextView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
 
 /**
  * TextDialog is a specialized version of EditText used by WebView
@@ -281,7 +288,7 @@ import android.widget.AutoCompleteTextView;
         }
         return false;
     }
-    
+
     /**
      *  Determine whether this TextDialog currently represents the node
      *  represented by ptr.
@@ -406,6 +413,9 @@ import android.widget.AutoCompleteTextView;
      * focus to the host.
      */
     /* package */ void remove() {
+        // hide the soft keyboard when the edit text is out of focus
+        InputMethodManager.getInstance(mContext).hideSoftInputFromWindow(
+                getWindowToken(), 0);
         mHandler.removeMessages(LONGPRESS);
         mWebView.removeView(this);
         mWebView.requestFocus();
@@ -427,6 +437,43 @@ import android.widget.AutoCompleteTextView;
         mWebView.passToJavaScript(getText().toString(), event);
     }
 
+    public void setAdapterCustom(AutoCompleteAdapter adapter) {
+        adapter.setTextView(this);
+        super.setAdapter(adapter);
+    }
+
+    /**
+     *  This is a special version of ArrayAdapter which changes its text size
+     *  to match the text size of its host TextView.
+     */
+    public static class AutoCompleteAdapter extends ArrayAdapter<String> {
+        private TextView mTextView;
+
+        public AutoCompleteAdapter(Context context, ArrayList<String> entries) {
+            super(context, com.android.internal.R.layout
+                    .search_dropdown_item_1line, entries);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public View getView(int position, View convertView, ViewGroup parent) {
+            TextView tv =
+                    (TextView) super.getView(position, convertView, parent);
+            if (tv != null && mTextView != null) {
+                tv.setTextSize(mTextView.getTextSize());
+            }
+            return tv;
+        }
+
+        /**
+         * Set the TextView so we can match its text size.
+         */
+        private void setTextView(TextView tv) {
+            mTextView = tv;
+        }
+    }
+
     /**
      * Determine whether to use the system-wide password disguising method,
      * or to use none.
index f00238d..9cfc622 100644 (file)
@@ -57,6 +57,7 @@ import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.ViewTreeObserver;
 import android.view.inputmethod.InputMethodManager;
+import android.webkit.TextDialog.AutoCompleteAdapter;
 import android.webkit.WebViewCore.EventHub;
 import android.widget.AbsoluteLayout;
 import android.widget.AdapterView;
@@ -2819,10 +2820,8 @@ public class WebView extends AbsoluteLayout
         public void run() {
             ArrayList<String> pastEntries = mDatabase.getFormData(mUrl, mName);
             if (pastEntries.size() > 0) {
-                ArrayAdapter<String> adapter = new ArrayAdapter<String>(
-                        mContext, com.android.internal.R.layout
-                        .search_dropdown_item_1line,
-                        pastEntries);
+                AutoCompleteAdapter adapter = new
+                        AutoCompleteAdapter(mContext, pastEntries);
                 ((HashMap) mUpdateMessage.obj).put("adapter", adapter);
                 mUpdateMessage.sendToTarget();
             }
@@ -4458,9 +4457,9 @@ public class WebView extends AbsoluteLayout
                 case UPDATE_TEXT_ENTRY_ADAPTER:
                     HashMap data = (HashMap) msg.obj;
                     if (mTextEntry.isSameTextField(msg.arg1)) {
-                        ArrayAdapter<String> adapter =
-                                (ArrayAdapter<String>) data.get("adapter");
-                        mTextEntry.setAdapter(adapter);
+                        AutoCompleteAdapter adapter =
+                                (AutoCompleteAdapter) data.get("adapter");
+                        mTextEntry.setAdapterCustom(adapter);
                     }
                     break;
                 case UPDATE_CLIPBOARD:
index 024b663..7d52901 100644 (file)
@@ -413,7 +413,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
                         // when the selection is at the bottom, we block the
                         // event to avoid going to the next focusable widget
                         Adapter adapter = mDropDownList.getAdapter();
-                        if (curIndex == adapter.getCount() - 1) {
+                        if (adapter != null && curIndex == adapter.getCount() - 1) {
                             return true;
                         }
                     }
index 6c0c164..f2cec92 100644 (file)
@@ -393,6 +393,12 @@ public class MediaController extends FrameLayout {
             doPauseResume();
             show(sDefaultTimeout);
             return true;
+        } else if (keyCode ==  KeyEvent.KEYCODE_STOP) {
+            if (mPlayer.isPlaying()) {
+                mPlayer.pause();
+                updatePausePlay();
+            }
+            return true;
         } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
                 keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
             // don't show the controls for volume adjustment
index df40156..1227afd 100644 (file)
@@ -447,7 +447,8 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
                 keyCode != KeyEvent.KEYCODE_ENDCALL &&
                 mMediaPlayer != null &&
                 mMediaController != null) {
-            if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
+            if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
+                    keyCode == KeyEvent.KEYCODE_PLAYPAUSE) {
                 if (mMediaPlayer.isPlaying()) {
                     pause();
                     mMediaController.show();
@@ -456,6 +457,10 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
                     mMediaController.hide();
                 }
                 return true;
+            } else if (keyCode == KeyEvent.KEYCODE_STOP 
+                    && mMediaPlayer.isPlaying()) {
+                pause();
+                mMediaController.show();
             } else {
                 toggleMediaControlsVisiblity();
             }
diff --git a/core/java/com/android/internal/gadget/IGadgetService.aidl b/core/java/com/android/internal/gadget/IGadgetService.aidl
new file mode 100644 (file)
index 0000000..0117d1d
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008 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.internal.gadget;
+
+import android.content.ComponentName;
+import android.gadget.GadgetInfo;
+
+/** {@hide} */
+interface IGadgetService {
+    int allocateGadgetId(String hostPackage);
+    void deleteGadgetId(int gadgetId);
+    void bindGadgetId(int gadgetId, in ComponentName provider);
+    GadgetInfo getGadgetInfo(int gadgetId);
+}
diff --git a/core/java/com/android/internal/gadget/package.html b/core/java/com/android/internal/gadget/package.html
new file mode 100644 (file)
index 0000000..db6f78b
--- /dev/null
@@ -0,0 +1,3 @@
+<body>
+{@hide}
+</body>
\ No newline at end of file
index a7081e3..1ec74a1 100644 (file)
@@ -116,7 +116,7 @@ public class HandlerCaller {
     }
     
     public Message obtainMessageI(int what, int arg1) {
-        return mH.obtainMessage(what, arg1);
+        return mH.obtainMessage(what, arg1, 0);
     }
     
     public Message obtainMessageIO(int what, int arg1, Object arg2) {
index 3b11a64..558a4c3 100644 (file)
@@ -143,7 +143,7 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie
     
     void setCaptionMode(boolean shortcut) {
 
-        mShortcutCaptionMode = shortcut;
+        mShortcutCaptionMode = shortcut && (mItemData.shouldShowShortcut());
         
         /*
          * If there is no item model, don't do any of the below (for example,
@@ -155,7 +155,7 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie
         
         CharSequence text = mItemData.getTitleForItemView(this);
         
-        if (shortcut) {
+        if (mShortcutCaptionMode) {
             
             if (mShortcutCaption == null) {
                 mShortcutCaption = mItemData.getShortcutLabel();
index e5d57ad..32513cd 100644 (file)
@@ -171,9 +171,13 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
     }
 
     public void setShortcut(boolean showShortcut, char shortcutKey) {
-        mShortcutView.setText(mItemData.getShortcutLabel());
+        final int newVisibility = (showShortcut && mItemData.shouldShowShortcut())
+                ? VISIBLE : GONE;
+
+        if (newVisibility == VISIBLE) {
+            mShortcutView.setText(mItemData.getShortcutLabel());
+        }
 
-        final int newVisibility = showShortcut ? VISIBLE : GONE;
         if (mShortcutView.getVisibility() != newVisibility) {
             mShortcutView.setVisibility(newVisibility);
         }
index 2987602..cbc4e9f 100644 (file)
@@ -22,6 +22,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -279,7 +280,8 @@ public class MenuBuilder implements Menu {
         mVisibleItems = new ArrayList<MenuItemImpl>();
         mIsVisibleItemsStale = true;
         
-        mShortcutsVisible = true;
+        mShortcutsVisible =
+                (mResources.getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS);
     }
     
     public void setCallback(Callback callback) {
@@ -687,7 +689,8 @@ public class MenuBuilder implements Menu {
     }
 
     /**
-     * Sets whether the shortcuts should be visible on menus.
+     * Sets whether the shortcuts should be visible on menus.  Devices without hardware
+     * key input will never make shortcuts visible even if this method is passed 'true'.
      * 
      * @param shortcutsVisible Whether shortcuts should be visible (if true and a
      *            menu item does not have a shortcut defined, that item will
@@ -696,9 +699,11 @@ public class MenuBuilder implements Menu {
     public void setShortcutsVisible(boolean shortcutsVisible) {
         if (mShortcutsVisible == shortcutsVisible) return;
         
-        mShortcutsVisible = shortcutsVisible;
+        mShortcutsVisible =
+            (mResources.getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS)
+            && shortcutsVisible;
         
-        refreshShortcuts(shortcutsVisible, isQwertyMode());
+        refreshShortcuts(mShortcutsVisible, isQwertyMode());
     }
 
     /**
index 5590f1a..20ea6a6 100644 (file)
@@ -131,6 +131,7 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
         mText = (TextView) findViewById(R.id.timepicker_input);
         mText.setOnFocusChangeListener(this);
         mText.setFilters(new InputFilter[] { mInputFilter });
+        mText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
         
         mSlideUpOutAnimation = new TranslateAnimation(
                 Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,
index e1ef459..a81f252 100644 (file)
@@ -70,6 +70,10 @@ sp<Camera> get_native_camera(JNIEnv *env, jobject thiz)
 static void err_callback(status_t err, void *cookie)
 {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
+    if (env == NULL) {
+        LOGE("err_callback on dead VM");
+        return;
+    }
     callback_cookie *c = (callback_cookie *)cookie;
     int error;
 
@@ -176,6 +180,10 @@ static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz,
 static void preview_callback(const sp<IMemory>& mem, void *cookie)
 {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
+    if (env == NULL) {
+        LOGE("preview_callback on dead VM");
+        return;
+    }
     callback_cookie *c = (callback_cookie *)cookie;
     int arg1 = 0, arg2 = 0;
     jobject obj = NULL;
@@ -234,7 +242,7 @@ static bool android_hardware_Camera_previewEnabled(JNIEnv *env, jobject thiz)
     return c->previewEnabled();
 }
 
-static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed)
+static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean oneshot)
 {
     sp<Camera> c = get_native_camera(env, thiz);
     if (c == 0)
@@ -245,14 +253,22 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t
     // each preview frame for nothing.
     callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context);
 
-    c->setFrameCallback(installed ? preview_callback : NULL,
-            cookie,
-            installed ? FRAME_CALLBACK_FLAG_CAMERA: FRAME_CALLBACK_FLAG_NOOP);
+    int callback_flag;
+    if (installed) {
+        callback_flag = oneshot ? FRAME_CALLBACK_FLAG_BARCODE_SCANNER : FRAME_CALLBACK_FLAG_CAMERA;
+    } else {
+        callback_flag = FRAME_CALLBACK_FLAG_NOOP;
+    }
+    c->setFrameCallback(installed ? preview_callback : NULL, cookie, callback_flag);
 }
 
 static void autofocus_callback_impl(bool success, void *cookie)
 {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
+    if (env == NULL) {
+        LOGE("autofocus_callback on dead VM");
+        return;
+    }
     callback_cookie *c = (callback_cookie *)cookie;
     env->CallStaticVoidMethod(c->camera_class, fields.post_event,
                               c->camera_ref, kAutoFocusCallback,
@@ -276,6 +292,10 @@ static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
 static void jpeg_callback(const sp<IMemory>& mem, void *cookie)
 {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
+    if (env == NULL) {
+        LOGE("jpeg`_callback on dead VM");
+        return;
+    }
     callback_cookie *c = (callback_cookie *)cookie;
     int arg1 = 0, arg2 = 0;
     jobject obj = NULL;
@@ -319,6 +339,10 @@ static void jpeg_callback(const sp<IMemory>& mem, void *cookie)
 static void shutter_callback_impl(void *cookie)
 {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
+    if (env == NULL) {
+        LOGE("shutter_callback on dead VM");
+        return;
+    }
     callback_cookie *c = (callback_cookie *)cookie;
     env->CallStaticVoidMethod(c->camera_class, fields.post_event,
                               c->camera_ref, kShutterCallback, 0, 0, NULL);
@@ -328,6 +352,10 @@ static void raw_callback(const sp<IMemory>& mem __attribute__((unused)),
                          void *cookie)
 {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
+    if (env == NULL) {
+        LOGE("raw_callback on dead VM");
+        return;
+    }
     callback_cookie *c = (callback_cookie *)cookie;
     env->CallStaticVoidMethod(c->camera_class, fields.post_event,
                               c->camera_ref, kRawCallback, 0, 0, NULL);
@@ -404,7 +432,7 @@ static jint android_hardware_Camera_unlock(JNIEnv *env, jobject thiz)
     sp<Camera> c = get_native_camera(env, thiz);
     if (c == 0)
         return INVALID_OPERATION;
-    return (jint) c->lock();
+    return (jint) c->unlock();
 }
 
 //-------------------------------------------------
@@ -429,7 +457,7 @@ static JNINativeMethod camMethods[] = {
     "()Z",
     (void *)android_hardware_Camera_previewEnabled },
   { "setHasPreviewCallback",
-    "(Z)V",
+    "(ZZ)V",
     (void *)android_hardware_Camera_setHasPreviewCallback },
   { "native_autoFocus",
     "()V",
index 29c1f52..ded909f 100644 (file)
         android:label="@string/permlab_writeCalendar"
         android:description="@string/permdesc_writeCalendar" />
 
+    <!-- Allows an application to read the user dictionary. This should
+         really only be required by an IME, or a dictionary editor like 
+         the Settings app. 
+         @hide Pending API council approval -->
+    <permission android:name="android.permission.READ_USER_DICTIONARY"
+        android:permissionGroup="android.permission-group.PERSONAL_INFO"
+        android:protectionLevel="dangerous"
+        android:label="@string/permlab_readDictionary"
+        android:description="@string/permdesc_readDictionary" />
+
+    <!-- Allows an application to write to the user dictionary.
+         @hide Pending API council approval -->
+    <permission android:name="android.permission.WRITE_USER_DICTIONARY"
+        android:permissionGroup="android.permission-group.PERSONAL_INFO"
+        android:protectionLevel="normal"
+        android:label="@string/permlab_writeDictionary"
+        android:description="@string/permdesc_writeDictionary" />
+
     <!-- ======================================= -->
     <!-- Permissions for accessing location info -->
     <!-- ======================================= -->
diff --git a/core/res/res/drawable/btn_check_off_longpress.png b/core/res/res/drawable/btn_check_off_longpress.png
deleted file mode 100644 (file)
index c81e119..0000000
Binary files a/core/res/res/drawable/btn_check_off_longpress.png and /dev/null differ
diff --git a/core/res/res/drawable/btn_check_on_longpress.png b/core/res/res/drawable/btn_check_on_longpress.png
deleted file mode 100644 (file)
index 367760b..0000000
Binary files a/core/res/res/drawable/btn_check_on_longpress.png and /dev/null differ
diff --git a/core/res/res/drawable/emo_im_angel.png b/core/res/res/drawable/emo_im_angel.png
new file mode 100644 (file)
index 0000000..c34dfa6
Binary files /dev/null and b/core/res/res/drawable/emo_im_angel.png differ
diff --git a/core/res/res/drawable/emo_im_cool.png b/core/res/res/drawable/emo_im_cool.png
new file mode 100644 (file)
index 0000000..d8eeb34
Binary files /dev/null and b/core/res/res/drawable/emo_im_cool.png differ
diff --git a/core/res/res/drawable/emo_im_crying.png b/core/res/res/drawable/emo_im_crying.png
new file mode 100644 (file)
index 0000000..1cafdb3
Binary files /dev/null and b/core/res/res/drawable/emo_im_crying.png differ
diff --git a/core/res/res/drawable/emo_im_embarrassed.png b/core/res/res/drawable/emo_im_embarrassed.png
new file mode 100644 (file)
index 0000000..e4db963
Binary files /dev/null and b/core/res/res/drawable/emo_im_embarrassed.png differ
diff --git a/core/res/res/drawable/emo_im_foot_in_mouth.png b/core/res/res/drawable/emo_im_foot_in_mouth.png
new file mode 100644 (file)
index 0000000..09d1fba
Binary files /dev/null and b/core/res/res/drawable/emo_im_foot_in_mouth.png differ
diff --git a/core/res/res/drawable/emo_im_happy.png b/core/res/res/drawable/emo_im_happy.png
new file mode 100644 (file)
index 0000000..b86602a
Binary files /dev/null and b/core/res/res/drawable/emo_im_happy.png differ
diff --git a/core/res/res/drawable/emo_im_kissing.png b/core/res/res/drawable/emo_im_kissing.png
new file mode 100644 (file)
index 0000000..56378f6
Binary files /dev/null and b/core/res/res/drawable/emo_im_kissing.png differ
diff --git a/core/res/res/drawable/emo_im_laughing.png b/core/res/res/drawable/emo_im_laughing.png
new file mode 100644 (file)
index 0000000..980bf28
Binary files /dev/null and b/core/res/res/drawable/emo_im_laughing.png differ
diff --git a/core/res/res/drawable/emo_im_lips_are_sealed.png b/core/res/res/drawable/emo_im_lips_are_sealed.png
new file mode 100644 (file)
index 0000000..f2de993
Binary files /dev/null and b/core/res/res/drawable/emo_im_lips_are_sealed.png differ
diff --git a/core/res/res/drawable/emo_im_money_mouth.png b/core/res/res/drawable/emo_im_money_mouth.png
new file mode 100644 (file)
index 0000000..08c53fd
Binary files /dev/null and b/core/res/res/drawable/emo_im_money_mouth.png differ
diff --git a/core/res/res/drawable/emo_im_sad.png b/core/res/res/drawable/emo_im_sad.png
new file mode 100644 (file)
index 0000000..31c08d0
Binary files /dev/null and b/core/res/res/drawable/emo_im_sad.png differ
diff --git a/core/res/res/drawable/emo_im_surprised.png b/core/res/res/drawable/emo_im_surprised.png
new file mode 100644 (file)
index 0000000..abe8c7a
Binary files /dev/null and b/core/res/res/drawable/emo_im_surprised.png differ
diff --git a/core/res/res/drawable/emo_im_tongue_sticking_out.png b/core/res/res/drawable/emo_im_tongue_sticking_out.png
new file mode 100644 (file)
index 0000000..6f0f47b
Binary files /dev/null and b/core/res/res/drawable/emo_im_tongue_sticking_out.png differ
diff --git a/core/res/res/drawable/emo_im_undecided.png b/core/res/res/drawable/emo_im_undecided.png
new file mode 100644 (file)
index 0000000..eb4f8c5
Binary files /dev/null and b/core/res/res/drawable/emo_im_undecided.png differ
diff --git a/core/res/res/drawable/emo_im_winking.png b/core/res/res/drawable/emo_im_winking.png
new file mode 100644 (file)
index 0000000..568562a
Binary files /dev/null and b/core/res/res/drawable/emo_im_winking.png differ
diff --git a/core/res/res/drawable/emo_im_wtf.png b/core/res/res/drawable/emo_im_wtf.png
new file mode 100644 (file)
index 0000000..41dd47f
Binary files /dev/null and b/core/res/res/drawable/emo_im_wtf.png differ
diff --git a/core/res/res/drawable/emo_im_yelling.png b/core/res/res/drawable/emo_im_yelling.png
new file mode 100644 (file)
index 0000000..c3c8612
Binary files /dev/null and b/core/res/res/drawable/emo_im_yelling.png differ
diff --git a/core/res/res/drawable/ic_menu_account_list.png b/core/res/res/drawable/ic_menu_account_list.png
new file mode 100644 (file)
index 0000000..f0945b2
Binary files /dev/null and b/core/res/res/drawable/ic_menu_account_list.png differ
diff --git a/core/res/res/drawable/ic_menu_allfriends.png b/core/res/res/drawable/ic_menu_allfriends.png
new file mode 100755 (executable)
index 0000000..a5bd331
Binary files /dev/null and b/core/res/res/drawable/ic_menu_allfriends.png differ
diff --git a/core/res/res/drawable/ic_menu_archive.png b/core/res/res/drawable/ic_menu_archive.png
new file mode 100644 (file)
index 0000000..a4599e3
Binary files /dev/null and b/core/res/res/drawable/ic_menu_archive.png differ
diff --git a/core/res/res/drawable/ic_menu_attachment.png b/core/res/res/drawable/ic_menu_attachment.png
new file mode 100644 (file)
index 0000000..89d626f
Binary files /dev/null and b/core/res/res/drawable/ic_menu_attachment.png differ
diff --git a/core/res/res/drawable/ic_menu_back.png b/core/res/res/drawable/ic_menu_back.png
new file mode 100644 (file)
index 0000000..5ce50eb
Binary files /dev/null and b/core/res/res/drawable/ic_menu_back.png differ
diff --git a/core/res/res/drawable/ic_menu_block.png b/core/res/res/drawable/ic_menu_block.png
new file mode 100644 (file)
index 0000000..422eeb1
Binary files /dev/null and b/core/res/res/drawable/ic_menu_block.png differ
diff --git a/core/res/res/drawable/ic_menu_blocked_user.png b/core/res/res/drawable/ic_menu_blocked_user.png
new file mode 100644 (file)
index 0000000..5a5619b
Binary files /dev/null and b/core/res/res/drawable/ic_menu_blocked_user.png differ
diff --git a/core/res/res/drawable/ic_menu_cc.png b/core/res/res/drawable/ic_menu_cc.png
new file mode 100644 (file)
index 0000000..4876021
Binary files /dev/null and b/core/res/res/drawable/ic_menu_cc.png differ
diff --git a/core/res/res/drawable/ic_menu_chat_dashboard.png b/core/res/res/drawable/ic_menu_chat_dashboard.png
new file mode 100644 (file)
index 0000000..37fd3cb
Binary files /dev/null and b/core/res/res/drawable/ic_menu_chat_dashboard.png differ
diff --git a/core/res/res/drawable/ic_menu_clear_playlist.png b/core/res/res/drawable/ic_menu_clear_playlist.png
new file mode 100644 (file)
index 0000000..750db62
Binary files /dev/null and b/core/res/res/drawable/ic_menu_clear_playlist.png differ
diff --git a/core/res/res/drawable/ic_menu_compose.png b/core/res/res/drawable/ic_menu_compose.png
new file mode 100644 (file)
index 0000000..1b4733e
Binary files /dev/null and b/core/res/res/drawable/ic_menu_compose.png differ
diff --git a/core/res/res/drawable/ic_menu_emoticons.png b/core/res/res/drawable/ic_menu_emoticons.png
new file mode 100644 (file)
index 0000000..e8c4e47
Binary files /dev/null and b/core/res/res/drawable/ic_menu_emoticons.png differ
diff --git a/core/res/res/drawable/ic_menu_end_conversation.png b/core/res/res/drawable/ic_menu_end_conversation.png
new file mode 100644 (file)
index 0000000..0ea0fcb
Binary files /dev/null and b/core/res/res/drawable/ic_menu_end_conversation.png differ
diff --git a/core/res/res/drawable/ic_menu_forward.png b/core/res/res/drawable/ic_menu_forward.png
new file mode 100644 (file)
index 0000000..0936fac
Binary files /dev/null and b/core/res/res/drawable/ic_menu_forward.png differ
diff --git a/core/res/res/drawable/ic_menu_friendslist.png b/core/res/res/drawable/ic_menu_friendslist.png
new file mode 100644 (file)
index 0000000..8ec6b1a
Binary files /dev/null and b/core/res/res/drawable/ic_menu_friendslist.png differ
diff --git a/core/res/res/drawable/ic_menu_goto.png b/core/res/res/drawable/ic_menu_goto.png
new file mode 100644 (file)
index 0000000..40183eb
Binary files /dev/null and b/core/res/res/drawable/ic_menu_goto.png differ
diff --git a/core/res/res/drawable/ic_menu_home.png b/core/res/res/drawable/ic_menu_home.png
new file mode 100644 (file)
index 0000000..34943f6
Binary files /dev/null and b/core/res/res/drawable/ic_menu_home.png differ
diff --git a/core/res/res/drawable/ic_menu_invite.png b/core/res/res/drawable/ic_menu_invite.png
new file mode 100644 (file)
index 0000000..7577e6d
Binary files /dev/null and b/core/res/res/drawable/ic_menu_invite.png differ
diff --git a/core/res/res/drawable/ic_menu_mark.png b/core/res/res/drawable/ic_menu_mark.png
new file mode 100644 (file)
index 0000000..5e95da7
Binary files /dev/null and b/core/res/res/drawable/ic_menu_mark.png differ
diff --git a/core/res/res/drawable/ic_menu_play_clip.png b/core/res/res/drawable/ic_menu_play_clip.png
new file mode 100644 (file)
index 0000000..4669947
Binary files /dev/null and b/core/res/res/drawable/ic_menu_play_clip.png differ
diff --git a/core/res/res/drawable/ic_menu_star.png b/core/res/res/drawable/ic_menu_star.png
new file mode 100755 (executable)
index 0000000..527d74a
Binary files /dev/null and b/core/res/res/drawable/ic_menu_star.png differ
diff --git a/core/res/res/drawable/ic_menu_start_conversation.png b/core/res/res/drawable/ic_menu_start_conversation.png
new file mode 100644 (file)
index 0000000..aadcc2f
Binary files /dev/null and b/core/res/res/drawable/ic_menu_start_conversation.png differ
diff --git a/core/res/res/drawable/ic_menu_stop.png b/core/res/res/drawable/ic_menu_stop.png
new file mode 100644 (file)
index 0000000..4fc825c
Binary files /dev/null and b/core/res/res/drawable/ic_menu_stop.png differ
diff --git a/core/res/res/drawable/ic_power.png b/core/res/res/drawable/ic_power.png
deleted file mode 100755 (executable)
index cfdf422..0000000
Binary files a/core/res/res/drawable/ic_power.png and /dev/null differ
diff --git a/core/res/res/layout/js_prompt.xml b/core/res/res/layout/js_prompt.xml
new file mode 100644 (file)
index 0000000..9ab9d09
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="fill_parent" 
+        android:layout_height="wrap_content"
+        android:gravity="center_horizontal"
+        >
+    
+    <TextView android:id="@+id/message"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            />
+            
+       <EditText android:id="@+id/value"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:textStyle="bold"
+            android:selectAllOnFocus="true"
+            android:scrollHorizontally="true"
+            android:layout_marginTop="6dip"
+            />
+                
+</LinearLayout>
index ec37417..729af1b 100644 (file)
 ** limitations under the License.
 */
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:background="@android:drawable/zoom_plate"
-    android:gravity="bottom"
-    android:paddingLeft="15dip"
-    android:paddingRight="15dip">
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
     <ZoomButton android:id="@+id/zoomIn" 
         android:background="@android:drawable/btn_plus"
         android:layout_width="wrap_content"
@@ -34,4 +28,4 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         />
-  </LinearLayout>
+</merge>
index b424837..08a5f7b 100644 (file)
 ** limitations under the License.
 */
 -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="wrap_content">
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
     <ZoomControls android:id="@+id/zoomControls"
         android:layout_alignParentBottom="true"
         android:layout_centerHorizontal="true"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        style="@style/ZoomControls"
         />
     <ImageView android:id="@+id/zoomMagnify"
         android:focusable="true"
@@ -35,4 +34,4 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         />
-   </RelativeLayout>
+</merge>
index 5859b9b..61a2c29 100644 (file)
     <string name="permdesc_subscribedFeedsRead">"Umožňuje aplikaci získat podrobnosti o aktuálně synchronizovaných zdrojích."</string>
     <string name="permlab_subscribedFeedsWrite">"zápis odebíraných zdrojů"</string>
     <string name="permdesc_subscribedFeedsWrite">"Umožňuje aplikaci upravit vaše aktuálně synchronizované zdroje. To může škodlivým aplikacím umožnit změnu vašich synchronizovaných zdrojů."</string>
+    <!-- no translation found for permlab_readDictionary (432535716804748781) -->
+    <skip />
+    <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
+    <skip />
+    <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
+    <skip />
+    <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
+    <skip />
   <string-array name="phoneTypes">
     <item>"Domů"</item>
     <item>"Mobil"</item>
     <string name="factorytest_not_system">"Test FACTORY_TEST lze provést pouze u balíčků nainstalovaných ve složce /system/app."</string>
     <string name="factorytest_no_action">"Nebyl nalezen žádný balíček umožňující test FACTORY_TEST."</string>
     <string name="factorytest_reboot">"Restartovat"</string>
+    <!-- no translation found for js_dialog_title (8143918455087008109) -->
+    <skip />
+    <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
+    <skip />
     <string name="save_password_label">"Potvrdit"</string>
     <string name="save_password_message">"Chcete, aby si prohlížeč zapamatoval toto heslo?"</string>
     <string name="save_password_notnow">"Nyní ne"</string>
index 0b2c7a7..44671e6 100644 (file)
     <string name="permdesc_subscribedFeedsRead">"Ermöglicht einer Anwendung, Details zu den zurzeit synchronisierten Feeds abzurufen."</string>
     <string name="permlab_subscribedFeedsWrite">"Abonnierte Feeds schreiben"</string>
     <string name="permdesc_subscribedFeedsWrite">"Ermöglicht einer Anwendung, Änderungen an den kürzlich synchronisierten Feeds vorzunehmen. Schädliche Anwendungen könnten so Ihre synchronisierten Feeds ändern."</string>
+    <!-- no translation found for permlab_readDictionary (432535716804748781) -->
+    <skip />
+    <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
+    <skip />
+    <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
+    <skip />
+    <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
+    <skip />
   <string-array name="phoneTypes">
     <item>"Privat"</item>
     <item>"Mobil"</item>
-    <item>"Beruflich"</item>
-    <item>"Beruflich (Fax)"</item>
-    <item>"Faxnummer (privat)"</item>
+    <item>"Arbeit"</item>
+    <item>"Fax (Arbeit)"</item>
+    <item>"Fax (privat)"</item>
     <item>"Pager"</item>
     <item>"Andere"</item>
     <item>"Benutzerdefiniert"</item>
   </string-array>
   <string-array name="emailAddressTypes">
     <item>"Privat"</item>
-    <item>"Beruflich"</item>
+    <item>"Arbeit"</item>
     <item>"Andere"</item>
     <item>"Benutzerdefiniert"</item>
   </string-array>
   <string-array name="postalAddressTypes">
     <item>"Privat"</item>
-    <item>"Beruflich"</item>
+    <item>"Arbeit"</item>
     <item>"Andere"</item>
     <item>"Benutzerdefiniert"</item>
   </string-array>
   <string-array name="imAddressTypes">
     <item>"Privat"</item>
-    <item>"Beruflich"</item>
+    <item>"Arbeit"</item>
     <item>"Andere"</item>
     <item>"Benutzerdefiniert"</item>
   </string-array>
   <string-array name="organizationTypes">
-    <item>"Beruflich"</item>
+    <item>"Arbeit"</item>
     <item>"Andere"</item>
     <item>"Benutzerdefiniert"</item>
   </string-array>
     <string name="lockscreen_pattern_correct">"Korrekt!"</string>
     <string name="lockscreen_pattern_wrong">"Tut uns leid. Versuchen Sie es noch einmal."</string>
     <string name="lockscreen_plugged_in">"Wird aufgeladen (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
-    <string name="lockscreen_low_battery">"Stecken Sie Ihr Ladegerät ein."</string>
+    <string name="lockscreen_low_battery">"Bitte Ladegerät anschließen"</string>
     <string name="lockscreen_missing_sim_message_short">"Keine SIM-Karte."</string>
     <string name="lockscreen_missing_sim_message">"Keine SIM-Karte im Telefon."</string>
     <string name="lockscreen_missing_sim_instructions">"Bitte legen Sie eine SIM-Karte ein."</string>
     <string name="factorytest_not_system">"Die Aktion FACTORY_TEST wird nur für unter \"/system/app\" gespeicherte Pakete unterstützt."</string>
     <string name="factorytest_no_action">"Es wurden kein Paket mit der Aktion FACTORY_TEST gefunden."</string>
     <string name="factorytest_reboot">"Neu booten"</string>
+    <!-- no translation found for js_dialog_title (8143918455087008109) -->
+    <skip />
+    <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
+    <skip />
     <string name="save_password_label">"Bestätigen"</string>
     <string name="save_password_message">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
     <string name="save_password_notnow">"Nicht jetzt"</string>
     <!-- no translation found for am (4885350190794996052) -->
     <skip />
     <string name="pm">".."</string>
-    <string name="numeric_date">"<xliff:g id="MONTH">%m</xliff:g>/<xliff:g id="DAY">%d</xliff:g>/<xliff:g id="YEAR">%Y</xliff:g>"</string>
+    <string name="numeric_date">"<xliff:g id="DAY">%d</xliff:g>/<xliff:g id="MONTH">%m</xliff:g>/<xliff:g id="YEAR">%Y</xliff:g>"</string>
     <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
     <string name="wday1_date1_wday2_date2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DATE1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="DATE2">%5$s</xliff:g>"</string>
     <string name="date1_time1_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
     <skip />
     <!-- no translation found for month (7026169712234774086) -->
     <skip />
-    <string name="month_day_year">"<xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
+    <string name="month_day_year">"<xliff:g id="DAY">%-d</xliff:g>. <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
     <!-- no translation found for month_year (9219019380312413367) -->
     <skip />
     <string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
-    <string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
-    <string name="same_year_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>"</string>
-    <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>"</string>
-    <string name="same_year_mdy1_mdy2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR">%9$s</xliff:g>"</string>
-    <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR">%9$s</xliff:g>"</string>
-    <string name="same_year_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
-    <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
-    <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
-    <string name="numeric_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>"</string>
-    <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>"</string>
-    <string name="numeric_mdy1_mdy2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
-    <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
-    <string name="numeric_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
-    <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
-    <string name="same_month_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>"</string>
-    <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>"</string>
-    <string name="same_month_mdy1_mdy2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
-    <string name="same_month_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
-    <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
-    <string name="abbrev_month_day_year">"<xliff:g id="MONTH">%b</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
+    <string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="DAY">%-d</xliff:g>. <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
+    <string name="same_year_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> –  <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
+    <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>,  <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
+    <string name="same_year_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR">%9$s</xliff:g>"</string>
+    <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR">%9$s</xliff:g>"</string>
+    <string name="same_year_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="numeric_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>"</string>
+    <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>"</string>
+    <string name="numeric_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+    <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+    <string name="numeric_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_month_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g>. – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g>"</string>
+    <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
+    <string name="same_month_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g>. – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+    <string name="same_month_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="abbrev_month_day_year">"<xliff:g id="DAY">%-d</xliff:g>. <xliff:g id="MONTH">%b</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
     <!-- no translation found for abbrev_month_year (3856424847226891943) -->
     <skip />
     <!-- no translation found for abbrev_month_day (5028815883653985933) -->
index 6727d5e..07a92fa 100644 (file)
     <string name="permdesc_subscribedFeedsRead">"Permite que una aplicación obtenga detalles sobre los feeds sincronizados en este momento."</string>
     <string name="permlab_subscribedFeedsWrite">"escribir feeds a los que está suscrito el usuario"</string>
     <string name="permdesc_subscribedFeedsWrite">"Permite que una aplicación modifique los feeds sincronizados actualmente. Este permiso podría provocar que una aplicación malintencionada cambie los feeds sincronizados."</string>
+    <!-- no translation found for permlab_readDictionary (432535716804748781) -->
+    <skip />
+    <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
+    <skip />
+    <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
+    <skip />
+    <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
+    <skip />
   <string-array name="phoneTypes">
     <item>"Casa"</item>
     <item>"Móvil"</item>
     <string name="factorytest_not_system">"La acción FACTORY_TEST sólo es compatible con los paquetes instalados en /system/app."</string>
     <string name="factorytest_no_action">"No se ha encontrado ningún paquete que proporcione la acción FACTORY_TEST."</string>
     <string name="factorytest_reboot">"Reiniciar"</string>
+    <!-- no translation found for js_dialog_title (8143918455087008109) -->
+    <skip />
+    <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
+    <skip />
     <string name="save_password_label">"Confirmar"</string>
     <string name="save_password_message">"¿Deseas que el navegador recuerde esta contraseña?"</string>
     <string name="save_password_notnow">"Ahora no"</string>
index 600bc2c..0f58ba1 100644 (file)
     <string name="permdesc_subscribedFeedsRead">"Permet à une application d\'obtenir des informations sur les flux récemment synchronisés."</string>
     <string name="permlab_subscribedFeedsWrite">"Écrire les flux auxquels vous êtes abonné"</string>
     <string name="permdesc_subscribedFeedsWrite">"Permet à une application de modifier vos flux synchronisés actuels. Cette fonctionnalité peut permettre à des applications malveillantes de modifier vos flux synchronisés."</string>
+    <!-- no translation found for permlab_readDictionary (432535716804748781) -->
+    <skip />
+    <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
+    <skip />
+    <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
+    <skip />
+    <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
+    <skip />
   <string-array name="phoneTypes">
     <item>"Accueil"</item>
     <item>"Mobile"</item>
     <string name="factorytest_not_system">"L\'action FACTORY_TEST est uniquement prise en charge pour les paquets de données installés dans in/system/app."</string>
     <string name="factorytest_no_action">"Impossible de trouver un paquet proposant l\'action FACTORY_TEST."</string>
     <string name="factorytest_reboot">"Redémarrer"</string>
+    <!-- no translation found for js_dialog_title (8143918455087008109) -->
+    <skip />
+    <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
+    <skip />
     <string name="save_password_label">"Confirmer"</string>
     <string name="save_password_message">"Voulez-vous que le navigateur se souvienne de ce mot de passe ?"</string>
     <string name="save_password_notnow">"Pas maintenant"</string>
index b41d449..8b96f89 100644 (file)
     <string name="permdesc_subscribedFeedsRead">"Consente a un\'applicazione di ottenere dettagli sui feed attualmente sincronizzati."</string>
     <string name="permlab_subscribedFeedsWrite">"scrivere feed sottoscritti"</string>
     <string name="permdesc_subscribedFeedsWrite">"Consente la modifica da parte di un\'applicazione dei feed attualmente sincronizzati. Le applicazioni dannose potrebbero essere in grado di modificare i feed sincronizzati."</string>
+    <!-- no translation found for permlab_readDictionary (432535716804748781) -->
+    <skip />
+    <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
+    <skip />
+    <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
+    <skip />
+    <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
+    <skip />
   <string-array name="phoneTypes">
     <item>"Casa"</item>
     <item>"Cellulare"</item>
     <string name="factorytest_not_system">"L\'azione FACTORY_TEST è supportata soltanto per i pacchetti installati in /system/app."</string>
     <string name="factorytest_no_action">"Nessun pacchetto trovato che fornisca l\'azione FACTORY_TEST."</string>
     <string name="factorytest_reboot">"Riavvia"</string>
+    <!-- no translation found for js_dialog_title (8143918455087008109) -->
+    <skip />
+    <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
+    <skip />
     <string name="save_password_label">"Conferma"</string>
     <string name="save_password_message">"Memorizzare la password nel browser?"</string>
     <string name="save_password_notnow">"Non ora"</string>
index 93b66f3..0735837 100644 (file)
     <string name="permdesc_subscribedFeedsRead">"現在同期しているフィードの詳細の取得をアプリケーションに許可します。"</string>
     <string name="permlab_subscribedFeedsWrite">"登録したフィードの書き込み"</string>
     <string name="permdesc_subscribedFeedsWrite">"現在同期しているフィードの変更をアプリケーションに許可します。悪意のあるアプリケーションが同期フィードを変更する恐れがあります。"</string>
+    <!-- no translation found for permlab_readDictionary (432535716804748781) -->
+    <skip />
+    <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
+    <skip />
+    <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
+    <skip />
+    <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
+    <skip />
   <string-array name="phoneTypes">
     <item>"自宅"</item>
     <item>"携帯"</item>
     <string name="factorytest_not_system">"FACTORY_TEST操作は、/system/appにインストールされたパッケージのみが対象です。"</string>
     <string name="factorytest_no_action">"FACTORY_TEST操作を行うパッケージは見つかりませんでした。"</string>
     <string name="factorytest_reboot">"再起動"</string>
+    <!-- no translation found for js_dialog_title (8143918455087008109) -->
+    <skip />
+    <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
+    <skip />
     <string name="save_password_label">"確認"</string>
     <string name="save_password_message">"このパスワードをブラウザで保存しますか?"</string>
     <string name="save_password_notnow">"今は保存しない"</string>
index 54a7321..9426f35 100644 (file)
     <string name="permdesc_subscribedFeedsRead">"Hiermee kan een toepassing details over de huidige gesynchroniseerde feeds achterhalen."</string>
     <string name="permlab_subscribedFeedsWrite">"geabonneerde feeds schrijven"</string>
     <string name="permdesc_subscribedFeedsWrite">"Hiermee kan een toepassing uw huidige gesynchroniseerde feeds wijzigen. Een schadelijke toepassing kan op deze manier uw gesynchroniseerde feeds wijzigen."</string>
+    <!-- no translation found for permlab_readDictionary (432535716804748781) -->
+    <skip />
+    <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
+    <skip />
+    <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
+    <skip />
+    <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
+    <skip />
   <string-array name="phoneTypes">
     <item>"Thuis"</item>
     <item>"Mobiel"</item>
     <string name="factorytest_not_system">"De actie FACTORY_TEST wordt alleen ondersteund voor pakketten die zijn geïnstalleerd in /system/app."</string>
     <string name="factorytest_no_action">"Er is geen pakket gevonden dat de actie FACTORY_TEST levert."</string>
     <string name="factorytest_reboot">"Opnieuw opstarten"</string>
+    <!-- no translation found for js_dialog_title (8143918455087008109) -->
+    <skip />
+    <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
+    <skip />
     <string name="save_password_label">"Bevestigen"</string>
     <string name="save_password_message">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
     <string name="save_password_notnow">"Niet nu"</string>
index c3cf8a1..d76922f 100644 (file)
     <string name="permdesc_subscribedFeedsRead">"Pozwala aplikacjom na pobieranie informacji szczegółowych na temat obecnie zsynchronizowanych źródeł."</string>
     <string name="permlab_subscribedFeedsWrite">"zapisywanie subskrybowanych źródeł"</string>
     <string name="permdesc_subscribedFeedsWrite">"Umożliwia aplikacji zmianę obecnie zsynchronizowanych źródeł. Może to pozwolić szkodliwej aplikacji na zmianę zsynchronizowanych źródeł."</string>
+    <!-- no translation found for permlab_readDictionary (432535716804748781) -->
+    <skip />
+    <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
+    <skip />
+    <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
+    <skip />
+    <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
+    <skip />
   <string-array name="phoneTypes">
     <item>"Strona główna"</item>
     <item>"Komórka"</item>
     <string name="factorytest_not_system">"Czynność FACTORY_TEST jest obsługiwana tylko dla pakietów zainstalowanych w katalogu /system/app."</string>
     <string name="factorytest_no_action">"Nie znaleziono żadnego pakietu, który zapewnia działanie FACTORY_TEST."</string>
     <string name="factorytest_reboot">"Uruchom ponownie"</string>
+    <!-- no translation found for js_dialog_title (8143918455087008109) -->
+    <skip />
+    <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
+    <skip />
     <string name="save_password_label">"Potwierdź"</string>
     <string name="save_password_message">"Czy chcesz, aby zapamiętać to hasło w przeglądarce?"</string>
     <string name="save_password_notnow">"Nie teraz"</string>
index 8d362bd..a00973f 100644 (file)
     <string name="permdesc_subscribedFeedsRead">"Позволяет приложению получать сведения о синхронизированных фидах."</string>
     <string name="permlab_subscribedFeedsWrite">"записывать фиды с подпиской"</string>
     <string name="permdesc_subscribedFeedsWrite">"Разрешает приложению изменять ваши синхронизированные фиды. Это может позволить вредоносному ПО изменять ваши синхронизированные фиды."</string>
+    <!-- no translation found for permlab_readDictionary (432535716804748781) -->
+    <skip />
+    <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
+    <skip />
+    <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
+    <skip />
+    <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
+    <skip />
   <string-array name="phoneTypes">
     <item>"Домашний"</item>
     <item>"Мобильный"</item>
     <string name="factorytest_not_system">"Действие FACTORY_TEST поддерживается только для пакетов, установленных в папке /system/app."</string>
     <string name="factorytest_no_action">"Пакет, предоставляющий действие FACTORY_TEST, не найден."</string>
     <string name="factorytest_reboot">"Перезагрузить"</string>
+    <!-- no translation found for js_dialog_title (8143918455087008109) -->
+    <skip />
+    <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
+    <skip />
     <string name="save_password_label">"Подтверждение"</string>
     <string name="save_password_message">"Сохранить этот пароль в браузере?"</string>
     <string name="save_password_notnow">"Не сейчас"</string>
index 27b8fea..87bd4e4 100644 (file)
     <string name="permdesc_subscribedFeedsRead">"允许应用程序获取有关当前同步的供稿的详情。"</string>
     <string name="permlab_subscribedFeedsWrite">"写入订阅的供稿"</string>
     <string name="permdesc_subscribedFeedsWrite">"允许应用程序修改您当前同步的供稿。这样恶意程序可以更改您同步的供稿。"</string>
+    <!-- no translation found for permlab_readDictionary (432535716804748781) -->
+    <skip />
+    <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
+    <skip />
+    <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
+    <skip />
+    <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
+    <skip />
   <string-array name="phoneTypes">
     <item>"家庭"</item>
     <item>"手机"</item>
     <string name="factorytest_not_system">"只有在 /system/app 中安装的包支持 FACTORY_TEST 操作。"</string>
     <string name="factorytest_no_action">"未发现支持 FACTORY_TEST 操作的包。"</string>
     <string name="factorytest_reboot">"重新引导"</string>
+    <!-- no translation found for js_dialog_title (8143918455087008109) -->
+    <skip />
+    <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
+    <skip />
     <string name="save_password_label">"确认"</string>
     <string name="save_password_message">"是否希望浏览器记住此密码?"</string>
     <string name="save_password_notnow">"暂不保存"</string>
index b95ca98..fbe8c55 100644 (file)
     <string name="permdesc_subscribedFeedsRead">"允許應用程式取得目前已同步處理的資訊提供。"</string>
     <string name="permlab_subscribedFeedsWrite">"寫入訂閱資訊提供"</string>
     <string name="permdesc_subscribedFeedsWrite">"允許應用程式修改已同步處理的資訊提供。惡意程式可使用此功能變更已同步處理的資訊提供。"</string>
+    <!-- no translation found for permlab_readDictionary (432535716804748781) -->
+    <skip />
+    <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
+    <skip />
+    <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
+    <skip />
+    <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
+    <skip />
   <string-array name="phoneTypes">
     <item>"首頁"</item>
     <item>"行動"</item>
     <string name="factorytest_not_system">"FACTORY_TEST 動作只支援安裝在 /system/app 裡的程式。"</string>
     <string name="factorytest_no_action">"找不到提供 FACTORY_TEST 的程式。"</string>
     <string name="factorytest_reboot">"重新開機"</string>
+    <!-- no translation found for js_dialog_title (8143918455087008109) -->
+    <skip />
+    <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
+    <skip />
     <string name="save_password_label">"確認"</string>
     <string name="save_password_message">"是否記憶此密碼?"</string>
     <string name="save_password_notnow">"現在不要"</string>
index 1704179..2562a8a 100644 (file)
     <!-- ***************************************************************** -->
     <eat-comment />
 
-    <!-- Searchable activities &amp; applications must provide search configuration information
+    <!-- Searchable activities and applications must provide search configuration information
         in an XML file, typically called searchable.xml.  This file is referenced in your manifest. 
         For a more in-depth discussion of search configuration, please refer to
         {@link android.app.SearchManager}. -->
     
     <!-- The set of attributes for a MapView. -->
     <declare-styleable name="MapView">
-        <!-- An API Key required to use MapView. Currently, this can be an arbitrary string. 
-             In order to run on actual devices, though, your app will need an authentic key, but
-             the process for issuing keys is not ready at this time. -->
+        <!-- Value is a string that specifies the Maps API Key to use. -->
         <attr name="apiKey" format="string" />
     </declare-styleable>
     
index cb364e6..f25d829 100644 (file)
   <public type="drawable" name="btn_plus" id="0x01080008" />
   <public type="drawable" name="btn_radio" id="0x01080009" />
   <public type="drawable" name="btn_star" id="0x0108000a" />
-  <public type="drawable" name="btn_star_big_off" id="0x0108000b" />
+  <public type="drawable" name="btn_star_big_off" id="0x0108000b" /> 
   <public type="drawable" name="btn_star_big_on" id="0x0108000c" />
   <public type="drawable" name="button_onoff_indicator_on" id="0x0108000d" />
   <public type="drawable" name="button_onoff_indicator_off" id="0x0108000e" />
   <public type="style" name="Theme.NoDisplay" id="0x01030055" />
   <public type="style" name="Animation.InputMethod" id="0x01030056" />
   <public type="style" name="Widget.KeyboardView" id="0x01030057" />
-  
-  <public type="drawable" name="ic_btn_search" id="0x0108009e" />
-  <public type="drawable" name="ic_dialog_menu_generic" id="0x010800a0" />
-  <public type="drawable" name="ic_menu_login" id="0x010800a1" />
-  <public type="drawable" name="ic_menu_refresh" id="0x010800a2" />
-  <public type="drawable" name="ic_menu_notifications" id="0x010800a3" />
+
+  <public type="drawable" name="emo_im_angel"               id="0x010800a4" />
+  <public type="drawable" name="emo_im_cool"                id="0x010800a5" />
+  <public type="drawable" name="emo_im_crying"              id="0x010800a6" />
+  <public type="drawable" name="emo_im_embarrassed"         id="0x010800a7" />
+  <public type="drawable" name="emo_im_foot_in_mouth"       id="0x010800a8" />
+  <public type="drawable" name="emo_im_happy"               id="0x010800a9" />
+  <public type="drawable" name="emo_im_kissing"             id="0x010800aa" />
+  <public type="drawable" name="emo_im_laughing"            id="0x010800ab" />
+  <public type="drawable" name="emo_im_lips_are_sealed"     id="0x010800ac" />
+  <public type="drawable" name="emo_im_money_mouth"         id="0x010800ad" />
+  <public type="drawable" name="emo_im_sad"                 id="0x010800ae" />
+  <public type="drawable" name="emo_im_surprised"           id="0x010800af" />
+  <public type="drawable" name="emo_im_tongue_sticking_out" id="0x010800b0" />
+  <public type="drawable" name="emo_im_undecided"           id="0x010800b1" />
+  <public type="drawable" name="emo_im_winking"             id="0x010800b2" />
+  <public type="drawable" name="emo_im_wtf"                 id="0x010800b3" />
+  <public type="drawable" name="emo_im_yelling"             id="0x010800b4" />
 </resources>
index f9e2e0f..978a024 100644 (file)
       your currently synced feeds. This could allow a malicious application to
       change your synced feeds.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_readDictionary">read user defined dictionary</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_readDictionary">Allows an application to read any private
+      words, names and phrases that the user may have stored in the user dictionary.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_writeDictionary">write to user defined dictionary</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_writeDictionary">Allows an application to write new words into the
+      user dictionary.</string>
+
     <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
     <!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
     <string-array name="phoneTypes">
     <string name="web_user_agent"><xliff:g id="x">Mozilla/5.0 (Linux; U; Android %s)
         AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1</xliff:g></string>
 
+    <!-- Title for a JavaScript dialog. "The page at <url of current page> says:" -->
+    <string name="js_dialog_title">The page at \'<xliff:g id="title">%s</xliff:g>\' says:</string>
+    <!-- Default title for a javascript dialog -->
+    <string name="js_dialog_title_default">JavaScript</string>
+    <!-- Message in a javascript dialog asking if the user wishes to leave the
+             current page -->
+    <string name="js_dialog_before_unload">Navigate away from this page?\n\n<xliff:g id="message">%s</xliff:g>\n\nSelect OK to continue, or Cancel to stay on the current page.</string>
+
     <!-- Title of the WebView save password dialog.  If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. -->
     <string name="save_password_label">Confirm</string>
     
index bc300c3..73e7dd0 100644 (file)
         <item name="android:shadowColor">#BB000000</item>
         <item name="android:shadowRadius">2.75</item>
     </style>
+
+    <style name="ZoomControls">
+        <item name="android:background">@android:drawable/zoom_plate</item>
+        <item name="android:gravity">bottom</item>
+        <item name="android:paddingLeft">15dip</item>
+        <item name="android:paddingRight">15dip</item>
+    </style>
 </resources>
diff --git a/core/res/waitingroom/screen_background_blue-land.png b/core/res/waitingroom/screen_background_blue-land.png
deleted file mode 100644 (file)
index 50e46b1..0000000
Binary files a/core/res/waitingroom/screen_background_blue-land.png and /dev/null differ
diff --git a/core/res/waitingroom/screen_background_green-land.png b/core/res/waitingroom/screen_background_green-land.png
deleted file mode 100644 (file)
index f46afa1..0000000
Binary files a/core/res/waitingroom/screen_background_green-land.png and /dev/null differ
diff --git a/core/res/waitingroom/screen_background_white-land.png b/core/res/waitingroom/screen_background_white-land.png
deleted file mode 100644 (file)
index a179c38..0000000
Binary files a/core/res/waitingroom/screen_background_white-land.png and /dev/null differ
index 71744be..dd585c9 100644 (file)
@@ -275,7 +275,7 @@ public:
             STOPPED = 1
         };
 
-            status_t    obtainBuffer(Buffer* audioBuffer, bool blocking);
+            status_t    obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
             void        releaseBuffer(Buffer* audioBuffer);
 
 
index f382451..fd62daa 100644 (file)
@@ -358,7 +358,7 @@ public:
             STOPPED = 1
         };
 
-            status_t    obtainBuffer(Buffer* audioBuffer, bool blocking);
+            status_t    obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
             void        releaseBuffer(Buffer* audioBuffer);
 
 
index 0ddfb8e..0cfdeec 100644 (file)
@@ -134,7 +134,7 @@ private:
     Condition mWaitCbkCond; // condition enabling interface to wait for audio callback completion after a change is requested
     float mVolume;  // Volume applied to audio track
     int mStreamType; // Audio stream used for output
-    int mProcessSize;  // Size of audio blocks generated at a time by audioCallback() (in PCM frames).
+    unsigned int mProcessSize;  // Size of audio blocks generated at a time by audioCallback() (in PCM frames).
 
     bool initAudioTrack();
     static void audioCallback(int event, void* user, void *info);
index 72ed281..1991aa7 100644 (file)
@@ -28,6 +28,11 @@ namespace android {
 
 #define MAX_SAMPLE_RATE     65535
 #define THREAD_PRIORITY_AUDIO_CLIENT (ANDROID_PRIORITY_AUDIO)
+// Maximum cumulated timeout milliseconds before restarting audioflinger thread
+#define MAX_STARTUP_TIMEOUT_MS  3000    // Longer timeout period at startup to cope with A2DP init time
+#define MAX_RUN_TIMEOUT_MS      1000
+#define WAIT_PERIOD_MS          10
+
 
 struct audio_track_cblk_t
 {
@@ -55,9 +60,11 @@ struct audio_track_cblk_t
                 int16_t     flowControlFlag; // underrun (out) or overrrun (in) indication
                 uint8_t     out;        // out equals 1 for AudioTrack and 0 for AudioRecord
                 uint8_t     forceReady; 
+                uint16_t    bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
+                uint16_t    waitTimeMs;      // Cumulated wait time
                 // Padding ensuring that data buffer starts on a cache line boundary (32 bytes). 
                 // See AudioFlinger::TrackBase constructor
-                int32_t     Padding[4];
+                int32_t     Padding[3];
                 
                             audio_track_cblk_t();
                 uint32_t    stepUser(uint32_t frameCount);
index 9c7bc47..f8454fd 100644 (file)
@@ -40,7 +40,7 @@ class IMemoryHeap;
 class OverlayRef : public LightRefBase<OverlayRef>
 {
 public:
-    OverlayRef(overlay_handle_t const*, const sp<IOverlay>&,
+    OverlayRef(overlay_handle_t, const sp<IOverlay>&,
             uint32_t w, uint32_t h, int32_t f, uint32_t ws, uint32_t hs);
 
     static sp<OverlayRef> readFromParcel(const Parcel& data);
@@ -53,7 +53,7 @@ private:
     OverlayRef();
     virtual ~OverlayRef();
 
-    overlay_handle_t const *mOverlayHandle;
+    overlay_handle_t mOverlayHandle;
     sp<IOverlay> mOverlayChannel;
     uint32_t mWidth;
     uint32_t mHeight;
@@ -74,7 +74,7 @@ public:
     void destroy();
     
     /* get the HAL handle for this overlay */
-    overlay_handle_t const* getHandleRef() const;
+    overlay_handle_t getHandleRef() const;
 
     /* blocks until an overlay buffer is available and return that buffer. */
     status_t dequeueBuffer(overlay_buffer_t* buffer);
index 7c451ab..9087c44 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef ANDROID_PARCEL_H
 #define ANDROID_PARCEL_H
 
+#include <cutils/native_handle.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <utils/String16.h>
@@ -78,6 +79,9 @@ public:
     status_t            writeString16(const char16_t* str, size_t len);
     status_t            writeStrongBinder(const sp<IBinder>& val);
     status_t            writeWeakBinder(const wp<IBinder>& val);
+
+    // doesn't take ownership of the native_handle
+    status_t            writeNativeHandle(const native_handle& handle);
     
     // Place a file descriptor into the parcel.  The given fd must remain
     // valid for the lifetime of the parcel.
@@ -108,6 +112,15 @@ public:
     const char16_t*     readString16Inplace(size_t* outLen) const;
     sp<IBinder>         readStrongBinder() const;
     wp<IBinder>         readWeakBinder() const;
+
+    
+    // if alloc is NULL, native_handle is allocated with malloc(), otherwise
+    // alloc is used. If the function fails, the effects of alloc() must be
+    // reverted by the caller.
+    native_handle*     readNativeHandle(
+            native_handle* (*alloc)(void* cookie, int numFds, int ints),
+            void* cookie) const;
+
     
     // Retrieve a file descriptor from the parcel.  This returns the raw fd
     // in the parcel, which you do not own -- use dup() to get your own copy.
index 7242575..c8c8431 100644 (file)
@@ -126,7 +126,7 @@ status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
 // ----------------------------------------------------------------------------
 
 A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
-    mFd(-1), mStandby(false), mStartCount(0), mRetryCount(0), mData(NULL),
+    mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
     mInitialized(false)
 {
     // use any address by default
index 3286535..6e3d49f 100644 (file)
@@ -170,7 +170,7 @@ private:
         bool mVisibilityChanged;
 
         overlay_t* mOverlay;        
-        overlay_handle_t const *mOverlayHandle;
+        overlay_handle_t mOverlayHandle;
         overlay_control_device_t* mOverlayDevice;
         uint32_t mWidth;
         uint32_t mHeight;
index 4a325ac..50c6008 100644 (file)
@@ -125,10 +125,9 @@ void Camera::disconnect()
 status_t Camera::reconnect()
 {
     LOGV("reconnect");
-    if (mCamera != 0) {
-        return mCamera->connect(this);
-    }
-    return NO_INIT;
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->connect(this);
 }
 
 sp<ICamera> Camera::remote()
@@ -138,14 +137,16 @@ sp<ICamera> Camera::remote()
 
 status_t Camera::lock()
 {
-    if (mCamera != 0) return mCamera->lock();
-    return NO_INIT;
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->lock();
 }
 
 status_t Camera::unlock()
 {
-    if (mCamera != 0) return mCamera->unlock();
-    return NO_INIT;
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->unlock();
 }
 
 // pass the buffered ISurface to the camera service
@@ -156,7 +157,9 @@ status_t Camera::setPreviewDisplay(const sp<Surface>& surface)
         LOGE("app passed NULL surface");
         return NO_INIT;
     }
-    return mCamera->setPreviewDisplay(surface->getISurface());
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->setPreviewDisplay(surface->getISurface());
 }
 
 status_t Camera::setPreviewDisplay(const sp<ISurface>& surface)
@@ -166,7 +169,9 @@ status_t Camera::setPreviewDisplay(const sp<ISurface>& surface)
         LOGE("app passed NULL surface");
         return NO_INIT;
     }
-    return mCamera->setPreviewDisplay(surface);
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->setPreviewDisplay(surface);
 }
 
 
@@ -174,48 +179,62 @@ status_t Camera::setPreviewDisplay(const sp<ISurface>& surface)
 status_t Camera::startPreview()
 {
     LOGV("startPreview");
-    return mCamera->startPreview();
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->startPreview();
 }
 
 // stop preview mode
 void Camera::stopPreview()
 {
     LOGV("stopPreview");
-    mCamera->stopPreview();
+    sp <ICamera> c = mCamera;
+    if (c == 0) return;
+    c->stopPreview();
 }
 
 // get preview state
 bool Camera::previewEnabled()
 {
     LOGV("previewEnabled");
-    return mCamera->previewEnabled();
+    sp <ICamera> c = mCamera;
+    if (c == 0) return false;
+    return c->previewEnabled();
 }
 
 status_t Camera::autoFocus()
 {
     LOGV("autoFocus");
-    return mCamera->autoFocus();
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->autoFocus();
 }
 
 // take a picture
 status_t Camera::takePicture()
 {
     LOGV("takePicture");
-    return mCamera->takePicture();
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->takePicture();
 }
 
 // set preview/capture parameters - key/value pairs
 status_t Camera::setParameters(const String8& params)
 {
     LOGV("setParameters");
-    return mCamera->setParameters(params);
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->setParameters(params);
 }
 
 // get preview/capture parameters - key/value pairs
 String8 Camera::getParameters() const
 {
     LOGV("getParameters");
-    String8 params = mCamera->getParameters();
+    String8 params;
+    sp <ICamera> c = mCamera;
+    if (c != 0) params = mCamera->getParameters();
     return params;
 }
 
@@ -252,6 +271,8 @@ void Camera::setFrameCallback(frame_callback cb, void *cookie, int frame_callbac
     LOGV("setFrameCallback");
     mFrameCallback = cb;
     mFrameCallbackCookie = cookie;
+    sp <ICamera> c = mCamera;
+    if (c == 0) return;
     mCamera->setFrameCallbackFlag(frame_callback_flag);
 }
 
index 2745f52..c8e6168 100644 (file)
@@ -74,7 +74,7 @@ status_t Overlay::getStatus() const {
     return mStatus;
 }
 
-overlay_handle_t const* Overlay::getHandleRef() const {
+overlay_handle_t Overlay::getHandleRef() const {
     if (mStatus != NO_ERROR) return NULL;
     return mOverlayRef->mOverlayHandle;
 }
@@ -112,7 +112,7 @@ OverlayRef::OverlayRef()
 {    
 }
 
-OverlayRef::OverlayRef(overlay_handle_t const* handle, const sp<IOverlay>& channel,
+OverlayRef::OverlayRef(overlay_handle_t handle, const sp<IOverlay>& channel,
          uint32_t w, uint32_t h, int32_t f, uint32_t ws, uint32_t hs)
     : mOverlayHandle(handle), mOverlayChannel(channel),
     mWidth(w), mHeight(h), mFormat(f), mWidthStride(ws), mHeightStride(hs),
@@ -126,7 +126,7 @@ OverlayRef::~OverlayRef()
         /* FIXME: handles should be promoted to "real" API and be handled by 
          * the framework */
         for (int i=0 ; i<mOverlayHandle->numFds ; i++) {
-            close(mOverlayHandle->fds[i]);
+            close(mOverlayHandle->data[i]);
         }
         free((void*)mOverlayHandle);
     }
@@ -141,16 +141,8 @@ sp<OverlayRef> OverlayRef::readFromParcel(const Parcel& data) {
         uint32_t f = data.readInt32();
         uint32_t ws = data.readInt32();
         uint32_t hs = data.readInt32();
-        /* FIXME: handles should be promoted to "real" API and be handled by 
-         * the framework */
-        int numfd = data.readInt32();
-        int numint = data.readInt32();
-        overlay_handle_t* handle = (overlay_handle_t*)malloc(
-                sizeof(overlay_handle_t) + numint*sizeof(int));
-        for (int i=0 ; i<numfd ; i++)
-            handle->fds[i] = data.readFileDescriptor();
-        for (int i=0 ; i<numint ; i++)
-            handle->data[i] = data.readInt32();
+        native_handle* handle = data.readNativeHandle(NULL, NULL);
+
         result = new OverlayRef();
         result->mOverlayHandle = handle;
         result->mOverlayChannel = overlay;
@@ -171,14 +163,7 @@ status_t OverlayRef::writeToParcel(Parcel* reply, const sp<OverlayRef>& o) {
         reply->writeInt32(o->mFormat);
         reply->writeInt32(o->mWidthStride);
         reply->writeInt32(o->mHeightStride);
-        /* FIXME: handles should be promoted to "real" API and be handled by 
-         * the framework */
-        reply->writeInt32(o->mOverlayHandle->numFds);
-        reply->writeInt32(o->mOverlayHandle->numInts);
-        for (int i=0 ; i<o->mOverlayHandle->numFds ; i++)
-            reply->writeFileDescriptor(o->mOverlayHandle->fds[i]);
-        for (int i=0 ; i<o->mOverlayHandle->numInts ; i++)
-            reply->writeInt32(o->mOverlayHandle->data[i]);
+        reply->writeNativeHandle(*(o->mOverlayHandle));
     } else {
         reply->writeStrongBinder(NULL);
     }
index 3eca4b0..0eba0b0 100644 (file)
@@ -650,6 +650,26 @@ status_t Parcel::writeWeakBinder(const wp<IBinder>& val)
     return flatten_binder(ProcessState::self(), val, this);
 }
 
+status_t Parcel::writeNativeHandle(const native_handle& handle)
+{
+    if (handle.version != sizeof(native_handle))
+        return BAD_TYPE;
+
+    status_t err;
+    err = writeInt32(handle.numFds);
+    if (err != NO_ERROR) return err;
+    
+    err = writeInt32(handle.numInts);
+    if (err != NO_ERROR) return err;
+    
+    for (int i=0 ; err==NO_ERROR && i<handle.numFds ; i++)
+        err = writeDupFileDescriptor(handle.data[i]);
+    
+    err = write(handle.data + handle.numFds, sizeof(int)*handle.numInts);
+    
+    return err;
+}
+
 status_t Parcel::writeFileDescriptor(int fd)
 {
     flat_binder_object obj;
@@ -902,6 +922,47 @@ wp<IBinder> Parcel::readWeakBinder() const
     return val;
 }
 
+
+native_handle* Parcel::readNativeHandle(native_handle* (*alloc)(void*, int, int), void* cookie) const
+{
+    int numFds, numInts;
+    status_t err;
+    err = readInt32(&numFds);
+    if (err != NO_ERROR) return 0;
+    err = readInt32(&numInts);
+    if (err != NO_ERROR) return 0;
+
+    native_handle* h;
+    if (alloc == 0) {
+        size_t size = sizeof(native_handle) + sizeof(int)*(numFds + numInts);
+        h = (native_handle*)malloc(size); 
+        h->version = sizeof(native_handle);
+        h->numFds = numFds;
+        h->numInts = numInts;
+    } else {
+        h = alloc(cookie, numFds, numInts);
+        if (h->version != sizeof(native_handle)) {
+            return 0;
+        }
+    }
+    
+    for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
+        h->data[i] = readFileDescriptor();
+        if (h->data[i] < 0) err = BAD_VALUE;
+    }
+    
+    err = read(h->data + numFds, sizeof(int)*numInts);
+    
+    if (err != NO_ERROR) {
+        if (alloc == 0) {
+            free(h);
+        }
+        h = 0;
+    }
+    return h;
+}
+
+
 int Parcel::readFileDescriptor() const
 {
     const flat_binder_object* flat = readObject(true);
@@ -923,7 +984,7 @@ const flat_binder_object* Parcel::readObject(bool nullMetaData) const
                 = reinterpret_cast<const flat_binder_object*>(mData+DPOS);
         mDataPos = DPOS + sizeof(flat_binder_object);
         if (!nullMetaData && (obj->cookie == NULL && obj->binder == NULL)) {
-            // When transfering a NULL object, we don't write it into
+            // When transferring a NULL object, we don't write it into
             // the object list, so we don't want to check for it when
             // reading.
             LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
index bbb9548..3d39181 100644 (file)
@@ -245,6 +245,8 @@ status_t AudioRecord::start()
 
     if (android_atomic_or(1, &mActive) == 0) {
         mNewPosition = mCblk->user + mUpdatePeriod;
+        mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+        mCblk->waitTimeMs = 0;
         if (t != 0) {
            t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
         } else {
@@ -342,7 +344,7 @@ status_t AudioRecord::getPosition(uint32_t *position)
 
 // -------------------------------------------------------------------------
 
-status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, bool blocking)
+status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
 {
     int active;
     int timeout = 0;
@@ -362,14 +364,21 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, bool blocking)
             active = mActive;
             if (UNLIKELY(!active))
                 return NO_MORE_BUFFERS;
-            if (UNLIKELY(!blocking))
+            if (UNLIKELY(!waitCount))
                 return WOULD_BLOCK;
             timeout = 0;
-            result = cblk->cv.waitRelative(cblk->lock, seconds(1));
+            result = cblk->cv.waitRelative(cblk->lock, milliseconds(WAIT_PERIOD_MS));
             if (__builtin_expect(result!=NO_ERROR, false)) {
-                LOGW(   "obtainBuffer timed out (is the CPU pegged?) "
-                        "user=%08x, server=%08x", cblk->user, cblk->server);
-                timeout = 1;
+                cblk->waitTimeMs += WAIT_PERIOD_MS;
+                if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
+                    LOGW(   "obtainBuffer timed out (is the CPU pegged?) "
+                            "user=%08x, server=%08x", cblk->user, cblk->server);
+                    timeout = 1;
+                    cblk->waitTimeMs = 0;
+                }
+                if (--waitCount == 0) {
+                    return TIMED_OUT;
+                }
             }
             // read the server count again
         start_loop_here:
@@ -382,6 +391,8 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, bool blocking)
         "but didn't need to be locked. We recovered, but "
         "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
 
+    cblk->waitTimeMs = 0;
+    
     if (framesReq > framesReady) {
         framesReq = framesReady;
     }
@@ -430,7 +441,9 @@ ssize_t AudioRecord::read(void* buffer, size_t userSize)
 
         audioBuffer.frameCount = userSize/mChannelCount/sizeof(int16_t);
 
-        status_t err = obtainBuffer(&audioBuffer, true);
+        // Calling obtainBuffer() with a negative wait count causes
+        // an (almost) infinite wait time.
+        status_t err = obtainBuffer(&audioBuffer, -1);
         if (err < 0) {
             // out of buffers, return #bytes written
             if (err == status_t(NO_MORE_BUFFERS))
@@ -457,7 +470,7 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
 {
     Buffer audioBuffer;
     uint32_t frames = mRemainingFrames;
-    size_t readSize = 0;
+    size_t readSize;
 
     // Manage marker callback
     if (mMarkerPosition > 0) {
@@ -477,17 +490,19 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
 
     do {
         audioBuffer.frameCount = frames;
-        status_t err = obtainBuffer(&audioBuffer, false);
+        // Calling obtainBuffer() with a wait count of 1 
+        // limits wait time to WAIT_PERIOD_MS. This prevents from being 
+        // stuck here not being able to handle timed events (position, markers).
+        status_t err = obtainBuffer(&audioBuffer, 1);
         if (err < NO_ERROR) {
-            if (err != WOULD_BLOCK) {
+            if (err != TIMED_OUT) {
                 LOGE("Error obtaining an audio buffer, giving up.");
                 return false;
             }
+            break;
         }
         if (err == status_t(STOPPED)) return false;
 
-        if (audioBuffer.size == 0) break;
-
         size_t reqSize = audioBuffer.size;
         mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
         readSize = audioBuffer.size;
@@ -514,13 +529,6 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
         }
     }
 
-    // If no data was read, it is likely that obtainBuffer() did
-    // not find available data in PCM buffer: we release the processor for
-    // a few millisecond before polling again for available data.
-    if (readSize == 0) {
-        usleep(5000);
-    } 
-
     if (frames == 0) {
         mRemainingFrames = mNotificationFrames;
     } else {
index ce65312..f9f8568 100644 (file)
@@ -330,6 +330,8 @@ void AudioTrack::start()
 
     if (android_atomic_or(1, &mActive) == 0) {
         mNewPosition = mCblk->server + mUpdatePeriod;
+        mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
+        mCblk->waitTimeMs = 0;
         if (t != 0) {
            t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
         } else {
@@ -572,7 +574,7 @@ status_t AudioTrack::reload()
 
 // -------------------------------------------------------------------------
 
-status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, bool blocking)
+status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
 {
     int active;
     int timeout = 0;
@@ -594,15 +596,23 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, bool blocking)
                 LOGV("Not active and NO_MORE_BUFFERS");
                 return NO_MORE_BUFFERS;
             }
-            if (UNLIKELY(!blocking))
+            if (UNLIKELY(!waitCount))
                 return WOULD_BLOCK;
             timeout = 0;
-            result = cblk->cv.waitRelative(cblk->lock, seconds(1));
-            if (__builtin_expect(result!=NO_ERROR, false)) {
-                LOGW(   "obtainBuffer timed out (is the CPU pegged?) "
-                        "user=%08x, server=%08x", cblk->user, cblk->server);
-                mAudioTrack->start(); // FIXME: Wake up audioflinger
-                timeout = 1;
+            result = cblk->cv.waitRelative(cblk->lock, milliseconds(WAIT_PERIOD_MS));
+            if (__builtin_expect(result!=NO_ERROR, false)) { 
+                cblk->waitTimeMs += WAIT_PERIOD_MS;
+                if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
+                    LOGW(   "obtainBuffer timed out (is the CPU pegged?) "
+                            "user=%08x, server=%08x", cblk->user, cblk->server);
+                    mAudioTrack->start(); // FIXME: Wake up audioflinger
+                    timeout = 1;
+                    cblk->waitTimeMs = 0;
+                }
+                ;
+                if (--waitCount == 0) {
+                    return TIMED_OUT;
+                }
             }
             // read the server count again
         start_loop_here:
@@ -610,6 +620,8 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, bool blocking)
         }
     }
 
+    cblk->waitTimeMs = 0;
+    
     if (framesReq > framesAvail) {
         framesReq = framesAvail;
     }
@@ -667,8 +679,9 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
         if (mFormat == AudioSystem::PCM_16_BIT) {
             audioBuffer.frameCount >>= 1;
         }
-
-        status_t err = obtainBuffer(&audioBuffer, true);
+        // Calling obtainBuffer() with a negative wait count causes
+        // an (almost) infinite wait time.
+        status_t err = obtainBuffer(&audioBuffer, -1);
         if (err < 0) {
             // out of buffers, return #bytes written
             if (err == status_t(NO_MORE_BUFFERS))
@@ -706,7 +719,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
 {
     Buffer audioBuffer;
     uint32_t frames;
-    size_t writtenSize = 0;
+    size_t writtenSize;
 
     // Manage underrun callback
     if (mActive && (mCblk->framesReady() == 0)) {
@@ -756,18 +769,20 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
     do {
 
         audioBuffer.frameCount = frames;
-
-        status_t err = obtainBuffer(&audioBuffer, false);
+        
+        // Calling obtainBuffer() with a wait count of 1 
+        // limits wait time to WAIT_PERIOD_MS. This prevents from being 
+        // stuck here not being able to handle timed events (position, markers, loops). 
+        status_t err = obtainBuffer(&audioBuffer, 1);
         if (err < NO_ERROR) {
-            if (err != WOULD_BLOCK) {
+            if (err != TIMED_OUT) {
                 LOGE("Error obtaining an audio buffer, giving up.");
                 return false;
             }
+            break;
         }
         if (err == status_t(STOPPED)) return false;
 
-        if (audioBuffer.size == 0) break;
-
         // Divide buffer size by 2 to take into account the expansion
         // due to 8 to 16 bit conversion: the callback must fill only half
         // of the destination buffer
@@ -802,13 +817,6 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
     }
     while (frames);
 
-    // If no data was written, it is likely that obtainBuffer() did
-    // not find room in PCM buffer: we release the processor for
-    // a few millisecond before polling again for available room.
-    if (writtenSize == 0) {
-        usleep(5000);
-    }
-
     if (frames == 0) {
         mRemainingFrames = mNotificationFrames;
     } else {
@@ -872,7 +880,12 @@ uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount)
 
     u += frameCount;
     // Ensure that user is never ahead of server for AudioRecord
-    if (!out && u > this->server) {
+    if (out) {
+        // If stepServer() has been called once, switch to normal obtainBuffer() timeout period
+        if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) {
+            bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+        }
+    } else if (u > this->server) {
         LOGW("stepServer occured after track reset");
         u = this->server;
     }
@@ -909,13 +922,20 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount)
     uint32_t s = this->server;
 
     s += frameCount;
-    // It is possible that we receive a flush()
-    // while the mixer is processing a block: in this case,
-    // stepServer() is called After the flush() has reset u & s and
-    // we have s > u
-    if (out && s > this->user) {
-        LOGW("stepServer occured after track reset");
-        s = this->user;
+    if (out) {
+        // Mark that we have read the first buffer so that next time stepUser() is called
+        // we switch to normal obtainBuffer() timeout period
+        if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) {
+            bufferTimeoutMs = MAX_RUN_TIMEOUT_MS - 1;
+        }        
+        // It is possible that we receive a flush()
+        // while the mixer is processing a block: in this case,
+        // stepServer() is called After the flush() has reset u & s and
+        // we have s > u
+        if (s > this->user) {
+            LOGW("stepServer occured after track reset");
+            s = this->user;
+        }
     }
 
     if (s >= loopEnd) {
diff --git a/services/java/com/android/server/GadgetService.java b/services/java/com/android/server/GadgetService.java
new file mode 100644 (file)
index 0000000..4e49253
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 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.server;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.gadget.GadgetManager;
+import android.gadget.GadgetInfo;
+
+import com.android.internal.gadget.IGadgetService;
+
+class GadgetService extends IGadgetService.Stub
+{
+    private static final String TAG = "GadgetService";
+
+    Context mContext;
+
+    GadgetService(Context context) {
+        mContext = context;
+    }
+
+    public int allocateGadgetId(String hostPackage) {
+        return 42;
+    }
+
+    public void deleteGadgetId(int gadgetId) {
+    }
+
+    public void bindGadgetId(int gadgetId, ComponentName provider) {
+        sendEnabled(provider);
+    }
+
+    void sendEnabled(ComponentName provider) {
+        Intent intent = new Intent(GadgetManager.GADGET_ENABLE_ACTION);
+        intent.setComponent(provider);
+        mContext.sendBroadcast(intent);
+    }
+
+    public GadgetInfo getGadgetInfo(int gadgetId) {
+        GadgetInfo info = new GadgetInfo();
+        info.provider = new ComponentName("com.android.gadgethost",
+                "com.android.gadgethost.TestGadgetProvider");
+        info.minWidth = 0;
+        info.minHeight = 0;
+        info.updatePeriodMillis = 60 * 1000; // 60s
+        return info;
+    }
+}
+
index baf57bc..7f7a52e 100644 (file)
@@ -290,7 +290,7 @@ class ServerThread extends Thread {
                 Log.i(TAG, "Starting Audio Service");
                 ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));
             } catch (Throwable e) {
-                Log.e(TAG, "Failure starting Volume Service", e);
+                Log.e(TAG, "Failure starting Audio Service", e);
             }
 
             try {
@@ -300,6 +300,13 @@ class ServerThread extends Thread {
             } catch (Throwable e) {
                 Log.e(TAG, "Failure starting HeadsetObserver", e);
             }
+
+            try {
+                Log.i(TAG, "Starting Gadget Service");
+                ServiceManager.addService(Context.GADGET_SERVICE, new GadgetService(context));
+            } catch (Throwable e) {
+                Log.e(TAG, "Failure starting Gadget Service", e);
+            }
         }
 
         // make sure the ADB_ENABLED setting value matches the secure property value
index 9578c2e..fe97b93 100644 (file)
@@ -23,6 +23,7 @@ import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.net.NetworkInfo;
+import android.net.DhcpInfo;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
@@ -30,7 +31,6 @@ import android.net.wifi.WifiStateTracker;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.SystemProperties;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Config;
@@ -241,6 +241,15 @@ public class WifiWatchdogService {
         return Settings.Secure.getInt(mContentResolver,
             Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS, 1000);
     }
+
+    /**
+     * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WATCH_LIST
+     * @return the comma-separated list of SSIDs
+     */
+    private String getWatchList() {
+        return Settings.Secure.getString(mContentResolver,
+                Settings.Secure.WIFI_WATCHDOG_WATCH_LIST);
+    }
     
     /**
      * Registers to receive the necessary Wi-Fi broadcasts.
@@ -304,8 +313,13 @@ public class WifiWatchdogService {
      * 
      * @return The DNS of the current AP.
      */
-    private static String getDns() {
-        return SystemProperties.get(SYSTEMPROPERTY_KEY_DNS);
+    private int getDns() {
+        DhcpInfo addressInfo = mWifiManager.getDhcpInfo();
+        if (addressInfo != null) {
+            return addressInfo.dns1;
+        } else {
+            return -1;
+        }
     }
     
     /**
@@ -315,18 +329,19 @@ public class WifiWatchdogService {
      * @return Whether the DNS is reachable
      */
     private boolean checkDnsConnectivity() {
-        String dns = getDns();
-        if (V) {
-            myLogV("checkDnsConnectivity: Checking " + dns + " for connectivity");
-        }
-        
-        if (TextUtils.isEmpty(dns)) {
+        int dns = getDns();
+        if (dns == -1) {
             if (V) {
                 myLogV("checkDnsConnectivity: Invalid DNS, returning false");
             }
             return false;
         }
         
+        if (V) {
+            myLogV("checkDnsConnectivity: Checking 0x" +
+                    Integer.toHexString(Integer.reverseBytes(dns)) + " for connectivity");
+        }
+
         int numInitialIgnoredPings = getInitialIgnoredPingCount();
         int numPings = getPingCount();
         int pingDelay = getPingDelayMs();
@@ -403,13 +418,13 @@ public class WifiWatchdogService {
     }
 
     private boolean backgroundCheckDnsConnectivity() {
-        String dns = getDns();
+        int dns = getDns();
         if (false && V) {
             myLogV("backgroundCheckDnsConnectivity: Background checking " + dns +
                     " for connectivity");
         }
         
-        if (TextUtils.isEmpty(dns)) {
+        if (dns == -1) {
             if (V) {
                 myLogV("backgroundCheckDnsConnectivity: DNS is empty, returning false");
             }
@@ -557,7 +572,14 @@ public class WifiWatchdogService {
                 return false;
             }
         }
-        
+
+        if (!isOnWatchList(ssid)) {
+            if (V) {
+                Log.v(TAG, "  SSID not on watch list, returning false");
+            }
+            return false;
+        }
+
         // The watchdog only monitors networks with multiple APs
         if (!hasRequiredNumberOfAps(ssid)) {
             return false;
@@ -565,6 +587,24 @@ public class WifiWatchdogService {
 
         return true;
     }
+
+    private boolean isOnWatchList(String ssid) {
+        String watchList;
+
+        if (ssid == null || (watchList = getWatchList()) == null) {
+            return false;
+        }
+
+        String[] list = watchList.split(" *, *");
+
+        for (String name : list) {
+            if (ssid.equals(name)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
     
     /**
      * Checks if the current scan results have multiple access points with an SSID.
@@ -1180,7 +1220,7 @@ public class WifiWatchdogService {
         /** Used to generate IDs */
         private static Random sRandom = new Random();
         
-        static boolean isDnsReachable(String dns, int timeout) {
+        static boolean isDnsReachable(int dns, int timeout) {
             try {
                 DatagramSocket socket = new DatagramSocket();
                 
@@ -1191,7 +1231,13 @@ public class WifiWatchdogService {
                 fillQuery(buf);
                 
                 // Send the DNS query
-                InetAddress dnsAddress = InetAddress.getByName(dns);
+                byte parts[] = new byte[4];
+                parts[0] = (byte)(dns & 0xff);
+                parts[1] = (byte)((dns >> 8) & 0xff);
+                parts[2] = (byte)((dns >> 16) & 0xff);
+                parts[3] = (byte)((dns >> 24) & 0xff);
+
+                InetAddress dnsAddress = InetAddress.getByAddress(parts);
                 DatagramPacket packet = new DatagramPacket(buf,
                         buf.length, dnsAddress, DNS_PORT);
                 socket.send(packet);
index 7a4c78f..663b7a4 100644 (file)
@@ -116,4 +116,35 @@ public class AutoCompleteTextViewPopup
                 ListView.INVALID_POSITION, textView.getListSelection());
     }
 
+    /** Make sure we handle an empty adapter properly */
+    @MediumTest
+    public void testPopupNavigateNoAdapter() throws Throwable {
+        AutoCompleteTextViewSimple theActivity = getActivity();
+        final AutoCompleteTextView textView = theActivity.getTextView();
+        final Instrumentation instrumentation = getInstrumentation();
+
+        // focus and type
+        textView.requestFocus();
+        instrumentation.waitForIdleSync();
+        sendKeys("A");
+
+        // No initial selection
+        assertEquals("getListSelection(-1)",
+                ListView.INVALID_POSITION, textView.getListSelection());
+
+        // check for selection position as expected
+        sendKeys("DPAD_DOWN");
+        assertEquals("getListSelection(0)", 0, textView.getListSelection());
+
+        // Now get rid of the adapter
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                textView.setAdapter((ArrayAdapter<?>) null);
+            }
+        });
+        instrumentation.waitForIdleSync();
+
+        // now try moving "down" - nothing should happen since there's no longer an adapter
+        sendKeys("DPAD_DOWN");
+    }
 }
diff --git a/tests/GadgetHost/Android.mk b/tests/GadgetHost/Android.mk
new file mode 100644 (file)
index 0000000..1d88db8
--- /dev/null
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := GadgetHost
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/GadgetHost/AndroidManifest.xml b/tests/GadgetHost/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..8da4485
--- /dev/null
@@ -0,0 +1,22 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.gadgethost">
+    <uses-permission android:name="android.permission.VIBRATE" />
+
+    <application>
+        <activity android:name="GadgetHostActivity" android:label="_GadgetHost">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name="GadgetPickActivity">
+            <intent-filter>
+                <action android:name="android.gadget.action.PICK_GADGET" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+        <receiver android:name="TestGadgetProvider">
+        </receiver>
+    </application>
+</manifest>
diff --git a/tests/GadgetHost/res/layout/gadget_host.xml b/tests/GadgetHost/res/layout/gadget_host.xml
new file mode 100644 (file)
index 0000000..824cc44
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/gadget_view_title"
+    />
+
+    <ScrollView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        >
+        
+        <com.android.gadgethost.GadgetContainerView
+            android:id="@+id/gadget_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+        />
+
+    </ScrollView>
+
+    <Button
+        android:id="@+id/add_gadget"
+        android:text="@string/add_gadget"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        />
+
+</LinearLayout>
+
diff --git a/tests/GadgetHost/res/layout/test_gadget.xml b/tests/GadgetHost/res/layout/test_gadget.xml
new file mode 100644 (file)
index 0000000..0fb7929
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:text="@string/oh_hai"
+/>
+
diff --git a/tests/GadgetHost/res/values/strings.xml b/tests/GadgetHost/res/values/strings.xml
new file mode 100644 (file)
index 0000000..d94cfbd
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<resources>
+    <string name="gadget_view_title">Gadget Test</string>
+    <string name="add_gadget">Add Gadget</string>
+    <string name="oh_hai">Oh hai.</string>
+</resources>
+
diff --git a/tests/GadgetHost/src/com/android/gadgethost/GadgetContainerView.java b/tests/GadgetHost/src/com/android/gadgethost/GadgetContainerView.java
new file mode 100644 (file)
index 0000000..159cbe4
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 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.gadgethost;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+public class GadgetContainerView extends LinearLayout
+{
+    public GadgetContainerView(Context context) {
+        super(context);
+    }
+
+    public GadgetContainerView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+}
diff --git a/tests/GadgetHost/src/com/android/gadgethost/GadgetHostActivity.java b/tests/GadgetHost/src/com/android/gadgethost/GadgetHostActivity.java
new file mode 100644 (file)
index 0000000..323141e
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2008 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.gadgethost;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.gadget.GadgetHost;
+import android.gadget.GadgetHostView;
+import android.gadget.GadgetInfo;
+import android.gadget.GadgetManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.View;
+import android.widget.LinearLayout;
+
+public class GadgetHostActivity extends Activity
+{
+    static final String TAG = "GadgetHostActivity";
+
+    static final int DISCOVER_GADGET_REQUEST = 1;
+
+    GadgetManager mGadgetManager;
+    GadgetContainerView mGadgetContainer;
+
+    public GadgetHostActivity() {
+        mGadgetManager = GadgetManager.getInstance(this);
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.gadget_host);
+
+        findViewById(R.id.add_gadget).setOnClickListener(mOnClickListener);
+        mGadgetContainer = (GadgetContainerView)findViewById(R.id.gadget_container);
+    }
+
+    View.OnClickListener mOnClickListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            discoverGadget(DISCOVER_GADGET_REQUEST);
+        }
+    };
+
+    void discoverGadget(int requestCode) {
+        Intent intent = new Intent(GadgetManager.GADGET_PICK_ACTION);
+        startActivityForResult(intent, requestCode);
+    }
+
+    void handleGadgetPickResult(int resultCode, Intent data) {
+        if (resultCode == RESULT_OK) {
+            Bundle extras = data.getExtras();
+            int gadgetId = extras.getInt(GadgetManager.EXTRA_GADGET_ID);
+            GadgetInfo gadget = mGadgetManager.getGadgetInfo(gadgetId);
+
+            if (gadget.configure != null) {
+                // configure the gadget if we should
+
+                // TODO: start the activity.  Watch for a cancel result.  If it returns
+                // RESULT_CANCELED, then remove the gadget.
+            } else {
+                // just add it as is
+                addGadgetView(gadgetId, gadget);
+            }
+        }
+    }
+
+    void addGadgetView(int gadgetId, GadgetInfo gadget) {
+        // TODO: Remove this hard-coded value when the GadgetInfo is real.
+        gadget.initialLayout = R.layout.test_gadget;
+
+        // Inflate the gadget's RemoteViews
+        GadgetHostView view = mHost.createView(this, gadgetId, gadget);
+
+        // Add it to the list
+        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+                65, // LinearLayout.LayoutParams.WRAP_CONTENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT);
+        mGadgetContainer.addView(view, layoutParams);
+    }
+
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        switch (requestCode) {
+        case DISCOVER_GADGET_REQUEST:
+            handleGadgetPickResult(resultCode, data);
+            break;
+        }
+    }
+
+    protected void onStart() {
+        super.onStart();
+        mHost.startListening();
+    }
+
+    protected void onStop() {
+        super.onStop();
+        mHost.stopListening();
+    }
+
+    class MyGadgetView extends GadgetHostView {
+        MyGadgetView() {
+            super(GadgetHostActivity.this);
+        }
+
+        public void createContextMenu(ContextMenu menu) {
+            menu.add("Delete");
+        }
+    }
+
+    GadgetHost mHost = new GadgetHost(this, 0) {
+        protected GadgetHostView onCreateView(Context context, int gadgetId, GadgetInfo gadget) {
+            return new MyGadgetView();
+        }
+    };
+
+}
+
+
diff --git a/tests/GadgetHost/src/com/android/gadgethost/GadgetPickActivity.java b/tests/GadgetHost/src/com/android/gadgethost/GadgetPickActivity.java
new file mode 100644 (file)
index 0000000..e8b3121
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2008 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.gadgethost;
+
+import android.app.ListActivity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.gadget.GadgetInfo;
+import android.gadget.GadgetManager;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.util.Log;
+
+public class GadgetPickActivity extends ListActivity
+{
+    private static final String TAG = "GadgetPickActivity";
+
+    GadgetManager mGadgetManager;
+    
+    public GadgetPickActivity() {
+        mGadgetManager = GadgetManager.getInstance(this);
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        Bundle extras = getIntent().getExtras();
+
+        String[] labels = new String[10];
+        for (int i=0; i<labels.length; i++) {
+            labels[i] = "Gadget " + (i+1);
+        }
+
+        setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, labels));
+    }
+
+    @Override
+    public void onListItemClick(ListView l, View v, int position, long id)
+    {
+        Log.d(TAG, "Clicked item " + position);
+
+        int gadgetId = mGadgetManager.allocateGadgetId(getCallingPackage());
+        mGadgetManager.bindGadgetId(gadgetId, new ComponentName(
+                    "com.android.gadgethost", "com.android.gadgethost.TestGadgetProvider"));
+
+        Intent result = new Intent();
+        result.putExtra(GadgetManager.EXTRA_GADGET_ID, gadgetId);
+
+        setResult(RESULT_OK, result);
+        finish();
+    }
+}
+
diff --git a/tests/GadgetHost/src/com/android/gadgethost/TestGadgetProvider.java b/tests/GadgetHost/src/com/android/gadgethost/TestGadgetProvider.java
new file mode 100644 (file)
index 0000000..8f9641b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 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.gadgethost;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class TestGadgetProvider extends BroadcastReceiver {
+
+    static final String TAG = "TestGadgetProvider";
+
+    public void onReceive(Context context, Intent intent) {
+        Log.d(TAG, "intent=" + intent);
+    }
+}
+
index 877763d..c438366 100644 (file)
@@ -2165,15 +2165,14 @@ ResourceTable::validateLocalizations(void)
                         // consider that string to have fulfilled the localization requirement.
                         String8 region(config.string(), 2);
                         if (configSet.find(region) == configSet.end()) {
-                            // TODO: force an error if there is no default to fall back to
                             if (configSet.count(defaultLocale) == 0) {
-                                fprintf(stdout, "aapt: warning: "
+                                fprintf(stdout, "aapt: error: "
                                         "*** string '%s' has no default or required localization "
                                         "for '%s' in %s\n",
                                         String8(nameIter->first).string(),
                                         config.string(),
                                         mBundle->getResourceSourceDirs()[0]);
-                                //err = UNKNOWN_ERROR;
+                                err = UNKNOWN_ERROR;
                             }
                         }
                     }