diff options
130 files changed, 2729 insertions, 411 deletions
@@ -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 diff --git a/api/current.xml b/api/current.xml index f6fa67d..e183217 100644 --- a/api/current.xml +++ b/api/current.xml @@ -8563,22 +8563,198 @@ 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" @@ -8651,17 +8827,6 @@ 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" @@ -9014,17 +9179,6 @@ 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" @@ -9102,17 +9256,6 @@ 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" @@ -9135,17 +9278,6 @@ 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" @@ -54475,6 +54607,19 @@ <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" @@ -56475,6 +56620,17 @@ 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" @@ -56558,6 +56714,23 @@ <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" @@ -56760,6 +56933,17 @@ <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" diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp index 33987c3..36c5ada 100644 --- a/camera/libcameraservice/CameraService.cpp +++ b/camera/libcameraservice/CameraService.cpp @@ -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 diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index 495156e..5af08f7 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -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". */ diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 022a87c..b0b0154 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -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 diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 905173e..c315271 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -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); - } - } - }; } diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl index 7e0226d..55ff27f 100644 --- a/core/java/android/bluetooth/IBluetoothA2dp.aidl +++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl @@ -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); } diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl index 564861f..582d4e3 100644 --- a/core/java/android/bluetooth/IBluetoothHeadset.aidl +++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl @@ -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); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 6da00df..3908aa1 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -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 index 0000000..418f2aa --- /dev/null +++ b/core/java/android/gadget/GadgetHost.java @@ -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 index 0000000..e2bef8c --- /dev/null +++ b/core/java/android/gadget/GadgetHostView.java @@ -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). + } +} + diff --git a/core/java/android/bluetooth/IBluetoothHeadsetCallback.aidl b/core/java/android/gadget/GadgetInfo.aidl index 03e884b..7231545 100644 --- a/core/java/android/bluetooth/IBluetoothHeadsetCallback.aidl +++ b/core/java/android/gadget/GadgetInfo.aidl @@ -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 index 0000000..1a7a9a0 --- /dev/null +++ b/core/java/android/gadget/GadgetInfo.java @@ -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 index 0000000..49c706e --- /dev/null +++ b/core/java/android/gadget/GadgetManager.java @@ -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 index 0000000..280ccfb --- /dev/null +++ b/core/java/android/gadget/package.html @@ -0,0 +1,4 @@ +<body> +@hide +</body> + diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index e2d7097..c09567c 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -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: diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 21bb38e..1a7547d 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -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() { } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 7b64405..a18f37c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -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 index 0000000..58e5731 --- /dev/null +++ b/core/java/android/provider/UserDictionary.java @@ -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. + } + } +} diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java index 90ef8f6..be784ff 100644 --- a/core/java/android/server/BluetoothA2dpService.java +++ b/core/java/android/server/BluetoothA2dpService.java @@ -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); - } diff --git a/core/java/android/speech/srec/Recognizer.java b/core/java/android/speech/srec/Recognizer.java index 749c923..a03a36a 100644 --- a/core/java/android/speech/srec/Recognizer.java +++ b/core/java/android/speech/srec/Recognizer.java @@ -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); // diff --git a/core/java/android/speech/srec/WaveHeader.java b/core/java/android/speech/srec/WaveHeader.java index 0aa3cc2..a99496d 100644 --- a/core/java/android/speech/srec/WaveHeader.java +++ b/core/java/android/speech/srec/WaveHeader.java @@ -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); + } } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 9d7a124..9e0289a 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -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)) { diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index a676234..ba40782 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -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; diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java index cae94c9..4f8e5e4 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -16,8 +16,10 @@ 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 diff --git a/core/java/android/webkit/TextDialog.java b/core/java/android/webkit/TextDialog.java index 30b519a..b7b40b1 100644 --- a/core/java/android/webkit/TextDialog.java +++ b/core/java/android/webkit/TextDialog.java @@ -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. diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index f00238d..9cfc622 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -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: diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index 024b663..7d52901 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -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; } } diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java index 6c0c164..f2cec92 100644 --- a/core/java/android/widget/MediaController.java +++ b/core/java/android/widget/MediaController.java @@ -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 diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java index df40156..1227afd 100644 --- a/core/java/android/widget/VideoView.java +++ b/core/java/android/widget/VideoView.java @@ -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 index 0000000..0117d1d --- /dev/null +++ b/core/java/com/android/internal/gadget/IGadgetService.aidl @@ -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 index 0000000..db6f78b --- /dev/null +++ b/core/java/com/android/internal/gadget/package.html @@ -0,0 +1,3 @@ +<body> +{@hide} +</body>
\ No newline at end of file diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java index a7081e3..1ec74a1 100644 --- a/core/java/com/android/internal/os/HandlerCaller.java +++ b/core/java/com/android/internal/os/HandlerCaller.java @@ -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) { diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java index 3b11a64..558a4c3 100644 --- a/core/java/com/android/internal/view/menu/IconMenuItemView.java +++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java @@ -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(); diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java index e5d57ad..32513cd 100644 --- a/core/java/com/android/internal/view/menu/ListMenuItemView.java +++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java @@ -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); } diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java index 2987602..cbc4e9f 100644 --- a/core/java/com/android/internal/view/menu/MenuBuilder.java +++ b/core/java/com/android/internal/view/menu/MenuBuilder.java @@ -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()); } /** diff --git a/core/java/com/android/internal/widget/NumberPicker.java b/core/java/com/android/internal/widget/NumberPicker.java index 5590f1a..20ea6a6 100644 --- a/core/java/com/android/internal/widget/NumberPicker.java +++ b/core/java/com/android/internal/widget/NumberPicker.java @@ -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, diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index e1ef459..a81f252 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -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", diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 29c1f52..ded909f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -156,6 +156,24 @@ 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 Binary files differdeleted file mode 100644 index c81e119..0000000 --- a/core/res/res/drawable/btn_check_off_longpress.png +++ /dev/null diff --git a/core/res/res/drawable/btn_check_on_longpress.png b/core/res/res/drawable/btn_check_on_longpress.png Binary files differdeleted file mode 100644 index 367760b..0000000 --- a/core/res/res/drawable/btn_check_on_longpress.png +++ /dev/null diff --git a/core/res/res/drawable/emo_im_angel.png b/core/res/res/drawable/emo_im_angel.png Binary files differnew file mode 100644 index 0000000..c34dfa6 --- /dev/null +++ b/core/res/res/drawable/emo_im_angel.png diff --git a/core/res/res/drawable/emo_im_cool.png b/core/res/res/drawable/emo_im_cool.png Binary files differnew file mode 100644 index 0000000..d8eeb34 --- /dev/null +++ b/core/res/res/drawable/emo_im_cool.png diff --git a/core/res/res/drawable/emo_im_crying.png b/core/res/res/drawable/emo_im_crying.png Binary files differnew file mode 100644 index 0000000..1cafdb3 --- /dev/null +++ b/core/res/res/drawable/emo_im_crying.png diff --git a/core/res/res/drawable/emo_im_embarrassed.png b/core/res/res/drawable/emo_im_embarrassed.png Binary files differnew file mode 100644 index 0000000..e4db963 --- /dev/null +++ b/core/res/res/drawable/emo_im_embarrassed.png diff --git a/core/res/res/drawable/emo_im_foot_in_mouth.png b/core/res/res/drawable/emo_im_foot_in_mouth.png Binary files differnew file mode 100644 index 0000000..09d1fba --- /dev/null +++ b/core/res/res/drawable/emo_im_foot_in_mouth.png diff --git a/core/res/res/drawable/emo_im_happy.png b/core/res/res/drawable/emo_im_happy.png Binary files differnew file mode 100644 index 0000000..b86602a --- /dev/null +++ b/core/res/res/drawable/emo_im_happy.png diff --git a/core/res/res/drawable/emo_im_kissing.png b/core/res/res/drawable/emo_im_kissing.png Binary files differnew file mode 100644 index 0000000..56378f6 --- /dev/null +++ b/core/res/res/drawable/emo_im_kissing.png diff --git a/core/res/res/drawable/emo_im_laughing.png b/core/res/res/drawable/emo_im_laughing.png Binary files differnew file mode 100644 index 0000000..980bf28 --- /dev/null +++ b/core/res/res/drawable/emo_im_laughing.png diff --git a/core/res/res/drawable/emo_im_lips_are_sealed.png b/core/res/res/drawable/emo_im_lips_are_sealed.png Binary files differnew file mode 100644 index 0000000..f2de993 --- /dev/null +++ b/core/res/res/drawable/emo_im_lips_are_sealed.png diff --git a/core/res/res/drawable/emo_im_money_mouth.png b/core/res/res/drawable/emo_im_money_mouth.png Binary files differnew file mode 100644 index 0000000..08c53fd --- /dev/null +++ b/core/res/res/drawable/emo_im_money_mouth.png diff --git a/core/res/res/drawable/emo_im_sad.png b/core/res/res/drawable/emo_im_sad.png Binary files differnew file mode 100644 index 0000000..31c08d0 --- /dev/null +++ b/core/res/res/drawable/emo_im_sad.png diff --git a/core/res/res/drawable/emo_im_surprised.png b/core/res/res/drawable/emo_im_surprised.png Binary files differnew file mode 100644 index 0000000..abe8c7a --- /dev/null +++ b/core/res/res/drawable/emo_im_surprised.png diff --git a/core/res/res/drawable/emo_im_tongue_sticking_out.png b/core/res/res/drawable/emo_im_tongue_sticking_out.png Binary files differnew file mode 100644 index 0000000..6f0f47b --- /dev/null +++ b/core/res/res/drawable/emo_im_tongue_sticking_out.png diff --git a/core/res/res/drawable/emo_im_undecided.png b/core/res/res/drawable/emo_im_undecided.png Binary files differnew file mode 100644 index 0000000..eb4f8c5 --- /dev/null +++ b/core/res/res/drawable/emo_im_undecided.png diff --git a/core/res/res/drawable/emo_im_winking.png b/core/res/res/drawable/emo_im_winking.png Binary files differnew file mode 100644 index 0000000..568562a --- /dev/null +++ b/core/res/res/drawable/emo_im_winking.png diff --git a/core/res/res/drawable/emo_im_wtf.png b/core/res/res/drawable/emo_im_wtf.png Binary files differnew file mode 100644 index 0000000..41dd47f --- /dev/null +++ b/core/res/res/drawable/emo_im_wtf.png diff --git a/core/res/res/drawable/emo_im_yelling.png b/core/res/res/drawable/emo_im_yelling.png Binary files differnew file mode 100644 index 0000000..c3c8612 --- /dev/null +++ b/core/res/res/drawable/emo_im_yelling.png diff --git a/core/res/res/drawable/ic_menu_account_list.png b/core/res/res/drawable/ic_menu_account_list.png Binary files differnew file mode 100644 index 0000000..f0945b2 --- /dev/null +++ b/core/res/res/drawable/ic_menu_account_list.png diff --git a/core/res/res/drawable/ic_menu_allfriends.png b/core/res/res/drawable/ic_menu_allfriends.png Binary files differnew file mode 100755 index 0000000..a5bd331 --- /dev/null +++ b/core/res/res/drawable/ic_menu_allfriends.png diff --git a/core/res/res/drawable/ic_menu_archive.png b/core/res/res/drawable/ic_menu_archive.png Binary files differnew file mode 100644 index 0000000..a4599e3 --- /dev/null +++ b/core/res/res/drawable/ic_menu_archive.png diff --git a/core/res/res/drawable/ic_menu_attachment.png b/core/res/res/drawable/ic_menu_attachment.png Binary files differnew file mode 100644 index 0000000..89d626f --- /dev/null +++ b/core/res/res/drawable/ic_menu_attachment.png diff --git a/core/res/res/drawable/ic_menu_back.png b/core/res/res/drawable/ic_menu_back.png Binary files differnew file mode 100644 index 0000000..5ce50eb --- /dev/null +++ b/core/res/res/drawable/ic_menu_back.png diff --git a/core/res/res/drawable/ic_menu_block.png b/core/res/res/drawable/ic_menu_block.png Binary files differnew file mode 100644 index 0000000..422eeb1 --- /dev/null +++ b/core/res/res/drawable/ic_menu_block.png diff --git a/core/res/res/drawable/ic_menu_blocked_user.png b/core/res/res/drawable/ic_menu_blocked_user.png Binary files differnew file mode 100644 index 0000000..5a5619b --- /dev/null +++ b/core/res/res/drawable/ic_menu_blocked_user.png diff --git a/core/res/res/drawable/ic_menu_cc.png b/core/res/res/drawable/ic_menu_cc.png Binary files differnew file mode 100644 index 0000000..4876021 --- /dev/null +++ b/core/res/res/drawable/ic_menu_cc.png diff --git a/core/res/res/drawable/ic_menu_chat_dashboard.png b/core/res/res/drawable/ic_menu_chat_dashboard.png Binary files differnew file mode 100644 index 0000000..37fd3cb --- /dev/null +++ b/core/res/res/drawable/ic_menu_chat_dashboard.png diff --git a/core/res/res/drawable/ic_menu_clear_playlist.png b/core/res/res/drawable/ic_menu_clear_playlist.png Binary files differnew file mode 100644 index 0000000..750db62 --- /dev/null +++ b/core/res/res/drawable/ic_menu_clear_playlist.png diff --git a/core/res/res/drawable/ic_menu_compose.png b/core/res/res/drawable/ic_menu_compose.png Binary files differnew file mode 100644 index 0000000..1b4733e --- /dev/null +++ b/core/res/res/drawable/ic_menu_compose.png diff --git a/core/res/res/drawable/ic_menu_emoticons.png b/core/res/res/drawable/ic_menu_emoticons.png Binary files differnew file mode 100644 index 0000000..e8c4e47 --- /dev/null +++ b/core/res/res/drawable/ic_menu_emoticons.png diff --git a/core/res/res/drawable/ic_menu_end_conversation.png b/core/res/res/drawable/ic_menu_end_conversation.png Binary files differnew file mode 100644 index 0000000..0ea0fcb --- /dev/null +++ b/core/res/res/drawable/ic_menu_end_conversation.png diff --git a/core/res/res/drawable/ic_menu_forward.png b/core/res/res/drawable/ic_menu_forward.png Binary files differnew file mode 100644 index 0000000..0936fac --- /dev/null +++ b/core/res/res/drawable/ic_menu_forward.png diff --git a/core/res/res/drawable/ic_menu_friendslist.png b/core/res/res/drawable/ic_menu_friendslist.png Binary files differnew file mode 100644 index 0000000..8ec6b1a --- /dev/null +++ b/core/res/res/drawable/ic_menu_friendslist.png diff --git a/core/res/res/drawable/ic_menu_goto.png b/core/res/res/drawable/ic_menu_goto.png Binary files differnew file mode 100644 index 0000000..40183eb --- /dev/null +++ b/core/res/res/drawable/ic_menu_goto.png diff --git a/core/res/res/drawable/ic_menu_home.png b/core/res/res/drawable/ic_menu_home.png Binary files differnew file mode 100644 index 0000000..34943f6 --- /dev/null +++ b/core/res/res/drawable/ic_menu_home.png diff --git a/core/res/res/drawable/ic_menu_invite.png b/core/res/res/drawable/ic_menu_invite.png Binary files differnew file mode 100644 index 0000000..7577e6d --- /dev/null +++ b/core/res/res/drawable/ic_menu_invite.png diff --git a/core/res/res/drawable/ic_menu_mark.png b/core/res/res/drawable/ic_menu_mark.png Binary files differnew file mode 100644 index 0000000..5e95da7 --- /dev/null +++ b/core/res/res/drawable/ic_menu_mark.png diff --git a/core/res/res/drawable/ic_menu_play_clip.png b/core/res/res/drawable/ic_menu_play_clip.png Binary files differnew file mode 100644 index 0000000..4669947 --- /dev/null +++ b/core/res/res/drawable/ic_menu_play_clip.png diff --git a/core/res/res/drawable/ic_menu_star.png b/core/res/res/drawable/ic_menu_star.png Binary files differnew file mode 100755 index 0000000..527d74a --- /dev/null +++ b/core/res/res/drawable/ic_menu_star.png diff --git a/core/res/res/drawable/ic_menu_start_conversation.png b/core/res/res/drawable/ic_menu_start_conversation.png Binary files differnew file mode 100644 index 0000000..aadcc2f --- /dev/null +++ b/core/res/res/drawable/ic_menu_start_conversation.png diff --git a/core/res/res/drawable/ic_menu_stop.png b/core/res/res/drawable/ic_menu_stop.png Binary files differnew file mode 100644 index 0000000..4fc825c --- /dev/null +++ b/core/res/res/drawable/ic_menu_stop.png diff --git a/core/res/res/drawable/ic_power.png b/core/res/res/drawable/ic_power.png Binary files differdeleted file mode 100755 index cfdf422..0000000 --- a/core/res/res/drawable/ic_power.png +++ /dev/null diff --git a/core/res/res/layout/js_prompt.xml b/core/res/res/layout/js_prompt.xml new file mode 100644 index 0000000..9ab9d09 --- /dev/null +++ b/core/res/res/layout/js_prompt.xml @@ -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> diff --git a/core/res/res/layout/zoom_controls.xml b/core/res/res/layout/zoom_controls.xml index ec37417..729af1b 100644 --- a/core/res/res/layout/zoom_controls.xml +++ b/core/res/res/layout/zoom_controls.xml @@ -17,13 +17,7 @@ ** 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> diff --git a/core/res/res/layout/zoom_magnify.xml b/core/res/res/layout/zoom_magnify.xml index b424837..08a5f7b 100644 --- a/core/res/res/layout/zoom_magnify.xml +++ b/core/res/res/layout/zoom_magnify.xml @@ -17,14 +17,13 @@ ** 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> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 5859b9b..61a2c29 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -310,6 +310,14 @@ <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> @@ -406,6 +414,12 @@ <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> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 0b2c7a7..44671e6 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -310,36 +310,44 @@ <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> @@ -366,7 +374,7 @@ <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> @@ -406,6 +414,12 @@ <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> @@ -505,7 +519,7 @@ <!-- 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> @@ -533,36 +547,36 @@ <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) --> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 6727d5e..07a92fa 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -310,6 +310,14 @@ <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> @@ -406,6 +414,12 @@ <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> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 600bc2c..0f58ba1 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -310,6 +310,14 @@ <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> @@ -406,6 +414,12 @@ <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> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index b41d449..8b96f89 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -310,6 +310,14 @@ <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> @@ -406,6 +414,12 @@ <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> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 93b66f3..0735837 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -310,6 +310,14 @@ <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> @@ -406,6 +414,12 @@ <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> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 54a7321..9426f35 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -310,6 +310,14 @@ <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> @@ -406,6 +414,12 @@ <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> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index c3cf8a1..d76922f 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -310,6 +310,14 @@ <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> @@ -406,6 +414,12 @@ <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> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 8d362bd..a00973f 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -310,6 +310,14 @@ <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> @@ -406,6 +414,12 @@ <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> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 27b8fea..87bd4e4 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -310,6 +310,14 @@ <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> @@ -406,6 +414,12 @@ <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> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index b95ca98..fbe8c55 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -310,6 +310,14 @@ <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> @@ -406,6 +414,12 @@ <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> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 1704179..2562a8a 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2468,7 +2468,7 @@ <!-- ***************************************************************** --> <eat-comment /> - <!-- Searchable activities & 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}. --> @@ -2601,9 +2601,7 @@ <!-- 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> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index cb364e6..f25d829 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -748,7 +748,7 @@ <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" /> @@ -1034,10 +1034,22 @@ <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> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index f9e2e0f..978a024 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -979,6 +979,18 @@ 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"> @@ -1216,6 +1228,14 @@ <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> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index bc300c3..73e7dd0 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -627,4 +627,11 @@ <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 Binary files differdeleted file mode 100644 index 50e46b1..0000000 --- a/core/res/waitingroom/screen_background_blue-land.png +++ /dev/null diff --git a/core/res/waitingroom/screen_background_green-land.png b/core/res/waitingroom/screen_background_green-land.png Binary files differdeleted file mode 100644 index f46afa1..0000000 --- a/core/res/waitingroom/screen_background_green-land.png +++ /dev/null diff --git a/core/res/waitingroom/screen_background_white-land.png b/core/res/waitingroom/screen_background_white-land.png Binary files differdeleted file mode 100644 index a179c38..0000000 --- a/core/res/waitingroom/screen_background_white-land.png +++ /dev/null diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h index 71744be..dd585c9 100644 --- a/include/media/AudioRecord.h +++ b/include/media/AudioRecord.h @@ -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); diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index f382451..fd62daa 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -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); diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h index 0ddfb8e..0cfdeec7 100644 --- a/include/media/ToneGenerator.h +++ b/include/media/ToneGenerator.h @@ -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); diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h index 72ed281..1991aa7 100644 --- a/include/private/media/AudioTrackShared.h +++ b/include/private/media/AudioTrackShared.h @@ -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); diff --git a/include/ui/Overlay.h b/include/ui/Overlay.h index 9c7bc47..f8454fd 100644 --- a/include/ui/Overlay.h +++ b/include/ui/Overlay.h @@ -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); diff --git a/include/utils/Parcel.h b/include/utils/Parcel.h index 7c451ab..9087c44 100644 --- a/include/utils/Parcel.h +++ b/include/utils/Parcel.h @@ -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. diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp index 7242575..c8c8431 100644 --- a/libs/audioflinger/A2dpAudioInterface.cpp +++ b/libs/audioflinger/A2dpAudioInterface.cpp @@ -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 diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h index 3286535..6e3d49f 100644 --- a/libs/surfaceflinger/LayerBuffer.h +++ b/libs/surfaceflinger/LayerBuffer.h @@ -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; diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp index 4a325ac..50c6008 100644 --- a/libs/ui/Camera.cpp +++ b/libs/ui/Camera.cpp @@ -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); } diff --git a/libs/ui/Overlay.cpp b/libs/ui/Overlay.cpp index 2745f52..c8e6168 100644 --- a/libs/ui/Overlay.cpp +++ b/libs/ui/Overlay.cpp @@ -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); } diff --git a/libs/utils/Parcel.cpp b/libs/utils/Parcel.cpp index 3eca4b0..0eba0b0 100644 --- a/libs/utils/Parcel.cpp +++ b/libs/utils/Parcel.cpp @@ -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); diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index bbb9548..3d39181 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -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 { diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index ce65312..f9f8568 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -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 index 0000000..4e49253 --- /dev/null +++ b/services/java/com/android/server/GadgetService.java @@ -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; + } +} + diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index baf57bc..7f7a52e 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -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 diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java index 9578c2e..fe97b93 100644 --- a/services/java/com/android/server/WifiWatchdogService.java +++ b/services/java/com/android/server/WifiWatchdogService.java @@ -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); diff --git a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java index 7a4c78f..663b7a4 100644 --- a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java +++ b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java @@ -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 index 0000000..1d88db8 --- /dev/null +++ b/tests/GadgetHost/Android.mk @@ -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 index 0000000..8da4485 --- /dev/null +++ b/tests/GadgetHost/AndroidManifest.xml @@ -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 index 0000000..824cc44 --- /dev/null +++ b/tests/GadgetHost/res/layout/gadget_host.xml @@ -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 index 0000000..0fb7929 --- /dev/null +++ b/tests/GadgetHost/res/layout/test_gadget.xml @@ -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 index 0000000..d94cfbd --- /dev/null +++ b/tests/GadgetHost/res/values/strings.xml @@ -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 index 0000000..159cbe4 --- /dev/null +++ b/tests/GadgetHost/src/com/android/gadgethost/GadgetContainerView.java @@ -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 index 0000000..323141e --- /dev/null +++ b/tests/GadgetHost/src/com/android/gadgethost/GadgetHostActivity.java @@ -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 index 0000000..e8b3121 --- /dev/null +++ b/tests/GadgetHost/src/com/android/gadgethost/GadgetPickActivity.java @@ -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 index 0000000..8f9641b --- /dev/null +++ b/tests/GadgetHost/src/com/android/gadgethost/TestGadgetProvider.java @@ -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); + } +} + diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 877763d..c438366 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -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; } } } |